pax_global_header00006660000000000000000000000064150037432560014517gustar00rootroot0000000000000052 comment=e8639238d3109b7edbe1b9a024df6432ddce27dd zwave-js-server-python-0.63.0/000077500000000000000000000000001500374325600161765ustar00rootroot00000000000000zwave-js-server-python-0.63.0/.coveragerc000066400000000000000000000002571500374325600203230ustar00rootroot00000000000000[report] omit = zwave_js_server/const/* exclude_lines = pragma: no cover def __repr__ raise AssertionError raise NotImplementedError if TYPE_CHECKING: zwave-js-server-python-0.63.0/.devcontainer/000077500000000000000000000000001500374325600207355ustar00rootroot00000000000000zwave-js-server-python-0.63.0/.devcontainer/devcontainer.json000066400000000000000000000006231500374325600243120ustar00rootroot00000000000000{ "name": "zwave-js-server-python Dev", "image": "mcr.microsoft.com/devcontainers/python:3.12", "postCreateCommand": "scripts/setup", "customizations": { "vscode": { "extensions": [ "ms-python.vscode-pylance", "visualstudioexptteam.vscodeintellicode", "GitHub.vscode-pull-request-github" ] } } }zwave-js-server-python-0.63.0/.github/000077500000000000000000000000001500374325600175365ustar00rootroot00000000000000zwave-js-server-python-0.63.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001500374325600217215ustar00rootroot00000000000000zwave-js-server-python-0.63.0/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000014431500374325600237130ustar00rootroot00000000000000blank_issues_enabled: true contact_links: - name: Report a bug with Z-Wave JS url: https://github.com/home-assistant/core/issues about: Please report issues with Z-Wave JS in the Home Assistant core repository unless a developer told you otherwise. - name: I have a question or need support url: https://www.home-assistant.io/help about: We use GitHub for tracking bugs, check the Home Assistant website for resources on getting help. - name: Feature Request url: https://community.home-assistant.io/c/feature-requests about: Please use the Home Assistant Community Forum for making feature requests. - name: I'm unsure where to go url: https://www.home-assistant.io/join-chat about: If you are unsure where to go, then joining our chat is recommended; Just ask! zwave-js-server-python-0.63.0/.github/dependabot.yml000066400000000000000000000011571500374325600223720ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: "pip" directory: "/" # Location of package manifests schedule: interval: "weekly" open-pull-requests-limit: 10 zwave-js-server-python-0.63.0/.github/release-drafter.yml000066400000000000000000000005531500374325600233310ustar00rootroot00000000000000change-template: "- #$NUMBER - $TITLE (@$AUTHOR)" categories: - title: "⚠ Breaking Changes" labels: - "breaking-change" - title: "🤖 Automated Updates" collapse-after: 1 labels: - "ci-generated" - title: "⬆️ Dependencies" collapse-after: 1 labels: - "dependencies" template: | ## What’s Changed $CHANGES zwave-js-server-python-0.63.0/.github/workflows/000077500000000000000000000000001500374325600215735ustar00rootroot00000000000000zwave-js-server-python-0.63.0/.github/workflows/check-generated-modules.yml000066400000000000000000000030151500374325600267740ustar00rootroot00000000000000name: Check Generated Modules on: schedule: - cron: '30 3 15 * *' jobs: check-generated-modules: runs-on: ubuntu-latest strategy: matrix: python-version: - "3.12" node-version: - "20" steps: - uses: actions/checkout@v4.2.2 with: fetch-depth: 2 - name: Set up Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Generate registry JSON files run: | npm install npm run generate - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5.6.0 with: python-version: ${{ matrix.python-version }} - name: Install Python scripts dependencies run: | python -m pip install --upgrade pip pip install -r requirements_scripts.txt - name: Run scripts run: | python ./scripts/generate_multilevel_sensor_constants.py python ./scripts/generate_notification_constants.py - name: Check for changes id: changes uses: UnicornGlobal/has-changes-action@v1.0.12 - name: Create Pull Request if: steps.changes.outputs.changed == 1 uses: peter-evans/create-pull-request@v7.0.8 with: commit-message: "Update auto-generated constants" delete-branch: true title: "Update auto-generated constants" labels: "ci-generated" zwave-js-server-python-0.63.0/.github/workflows/publish-to-pypi.yml000066400000000000000000000012651500374325600253670ustar00rootroot00000000000000name: Publish releases to PyPI on: release: types: [published, prereleased] jobs: build-and-publish: name: Builds and publishes releases to PyPI runs-on: ubuntu-latest steps: - uses: actions/checkout@v4.2.2 - name: Set up Python 3.12 uses: actions/setup-python@v5.6.0 with: python-version: "3.12" - name: Install wheel run: |- pip install wheel - name: Build run: |- pip install build python -m build - name: Publish release to PyPI uses: pypa/gh-action-pypi-publish@v1.12.4 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} zwave-js-server-python-0.63.0/.github/workflows/release-drafter.yml000066400000000000000000000005101500374325600253570ustar00rootroot00000000000000name: Release Drafter on: push: branches: - main jobs: update_release_draft: runs-on: ubuntu-latest steps: # Drafts your next Release notes as Pull Requests are merged into "main" - uses: release-drafter/release-drafter@v6.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} zwave-js-server-python-0.63.0/.github/workflows/test.yml000066400000000000000000000026371500374325600233050ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Test on: push: branches: [main] pull_request: branches: [main] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: - "3.12" - "3.13" steps: - uses: actions/checkout@v4.2.2 with: fetch-depth: 2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5.6.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install tox tox-gh-actions - name: Test with tox run: tox - name: Upload coverage data uses: actions/upload-artifact@v4.6.2 with: name: coverage-${{ matrix.python-version }} path: "coverage.xml" coverage: runs-on: ubuntu-latest needs: build steps: - name: Check out the repository uses: actions/checkout@v4.2.2 with: fetch-depth: 2 - name: Download all coverage data uses: actions/download-artifact@v4.3.0 - name: Upload coverage report uses: codecov/codecov-action@v5.4.2 with: token: ${{ secrets.CODECOV_TOKEN }} zwave-js-server-python-0.63.0/.gitignore000066400000000000000000000021161500374325600201660ustar00rootroot00000000000000node_modules *.lock package-lock.json notifications.json sensors.json # Hide sublime text stuff *.sublime-project *.sublime-workspace # Hide some OS X stuff .DS_Store .AppleDouble .LSOverride Icon # Thumbnails ._* # IntelliJ IDEA .idea *.iml # pytest .pytest_cache .cache # GITHUB Proposed Python stuff: *.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs .eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 pip-wheel-metadata # Logs *.log pip-log.txt # Unit test / coverage reports .coverage .tox coverage.xml nosetests.xml htmlcov/ test-reports/ test-results.xml test-output.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject .python-version # emacs auto backups *~ *# *.orig # venv stuff pyvenv.cfg pip-selfcheck.json venv .venv Pipfile* share/* # vimmy stuff *.swp *.swo tags ctags.tmp # vagrant stuff virtualization/vagrant/setup_done virtualization/vagrant/.vagrant virtualization/vagrant/config # Visual Studio Code .vscode/* !.vscode/cSpell.json !.vscode/extensions.json !.vscode/tasks.json # Typing .mypy_cache zwave-js-server-python-0.63.0/.pre-commit-config.yaml000066400000000000000000000021231500374325600224550ustar00rootroot00000000000000repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.3 hooks: - id: ruff files: ^(scripts|test|zwave_js_server)/.+\.py$ args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black-pre-commit-mirror rev: 24.1.1 hooks: - id: black args: - --quiet files: ^((zwave_js_server|scripts|test)/.+)?[^/]+\.py$ - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: no-commit-to-branch args: - --branch=main - repo: https://github.com/pycqa/pydocstyle rev: 6.3.0 hooks: - id: pydocstyle files: ^(zwave_js_server|test)/.+\.py$ - repo: local hooks: - id: mypy name: mypy entry: scripts/run-in-env.sh mypy language: script types: [python] require_serial: true files: ^(zwave_js_server)/.+\.py$ - id: pylint name: pylint entry: scripts/run-in-env.sh pylint -j 0 language: script types: [python] files: ^zwave_js_server/.+\.py$ zwave-js-server-python-0.63.0/LICENSE000066400000000000000000000261351500374325600172120ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. zwave-js-server-python-0.63.0/MANIFEST.in000066400000000000000000000000171500374325600177320ustar00rootroot00000000000000exclude test/* zwave-js-server-python-0.63.0/README.md000066400000000000000000000017751500374325600174670ustar00rootroot00000000000000# zwave-js-server-python Python library for communicating with [zwave-js-server](https://github.com/zwave-js/zwave-js-server/). Goal for this library is to replicate the structure and the events of Z-Wave JS 1:1. So it has a `Driver`, `Controller` and `Node` classes. ## Setup development environment To setup your development environment, run `scripts/setup`, which will install all requirements and set up pre-commit checks. ## Trying it out ```shell python3 -m zwave_js_server ws://localhost:3000 ``` Or get the version of the server ```shell python3 -m zwave_js_server ws://localhost:3000 --server-version ``` Or dump the state. Optionally add `--event-timeout 5` if you want to listen 5 seconds extra for events. ```shell python3 -m zwave_js_server ws://localhost:3000 --dump-state ``` ## Sending commands ```python try: result = await client.async_send_command({ "command": "start_listening" }) except zwave_js_server.client.FailedCommand as err: print("Command failed with", err.error_code) ``` zwave-js-server-python-0.63.0/codecov.yml000066400000000000000000000001501500374325600203370ustar00rootroot00000000000000comment: false coverage: status: project: default: target: 90 threshold: 9% zwave-js-server-python-0.63.0/package.json000066400000000000000000000004321500374325600204630ustar00rootroot00000000000000{ "scripts": { "generate": "node scripts/generate_zwave_js_registry_json.js" }, "type": "module", "devDependencies": { "@tsconfig/node20": "^20.1.4", "@types/node": "^22.7.4", "ts-node": "^10.9.2", "typescript": "^5.3.3", "zwave-js": "^13.4.0" } } zwave-js-server-python-0.63.0/pyproject.toml000066400000000000000000000066131500374325600211200ustar00rootroot00000000000000[build-system] requires = ["setuptools>=77.0"] build-backend = "setuptools.build_meta" [project] name = "zwave-js-server-python" authors = [{ name = "Home Assistant Team", email = "hello@home-assistant.io" }] description = "Python wrapper for zwave-js-server" readme = "README.md" requires-python = ">=3.12" license = "Apache-2.0" keywords = ["home", "automation", "zwave", "zwave-js"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Home Automation", ] dependencies = ["aiohttp>3", "pydantic>=1.10.0"] dynamic = ["version"] [project.urls] "Source Code" = "https://github.com/home-assistant-libs/zwave-js-server-python" "Bug Reports" = "https://github.com/home-assistant-libs/zwave-js-server-python/issues" [project.scripts] zwave-js-server-python = "zwave_js_server.__main__:main" [tool.setuptools.dynamic] version = { attr = "zwave_js_server.const.__version__" } [tool.setuptools.packages.find] exclude = ["test", "test.*", "scripts"] [tool.setuptools.package-data] zwave_js_server = ["py.typed"] [tool.mypy] plugins = ["pydantic.mypy"] follow_imports = "skip" ignore_missing_imports = true check_untyped_defs = true disallow_incomplete_defs = true disallow_untyped_calls = true disallow_untyped_defs = true warn_return_any = false warn_unreachable = true warn_unused_ignores = true warn_incomplete_stub = true warn_redundant_casts = true warn_unused_configs = true [[tool.mypy.overrides]] module = "mypy-test.*" ignore_errors = true [tool.pylint.MAIN] disable = [ "duplicate-code", "fixme", "locally-disabled", "too-few-public-methods", "too-many-public-methods", "too-many-lines", ] enable = ["useless-suppression", "use-symbolic-message-instead"] extension-pkg-allow-list = "pydantic" fail-on = ["I"] ignore = ["test"] jobs = 2 load-plugins = ["pylint_strict_informational"] persistent = "no" score = "no" [tool.pylint.BASIC] good-names = ["id", "i", "j", "k", "ex", "Run", "_", "fp"] [tool.pylint.DESIGN] max-args = 9 max-attributes = 15 [tool.pylint.FORMAT] expected-line-ending-format = "LF" [tool.pylint.MESSAGE_CONTROL] disable="too-many-positional-arguments" [tool.pytest.ini_options] asyncio_mode = "auto" [tool.ruff] exclude = [ ".venv", ".git", ".tox", "docs", "venv", "bin", "lib", "deps", "build", ] line-length = 88 [tool.ruff.lint] select = ["D", "E", "F", "G", "I", "PLC", "PLE", "PLR", "PLW", "UP", "W"] ignore = [ "D202", "D212", "D203", "D213", "E501", "PLR0911", # Too many return statements ({returns} > {max_returns}) "PLR0912", # Too many branches ({branches} > {max_branches}) "PLR0913", # Too many arguments to function call ({c_args} > {max_args}) "PLR0915", # Too many statements ({statements} > {max_statements}) "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target "UP006", # keep type annotation style as is "UP007", # keep type annotation style as is ] [tool.ruff.lint.isort] force-sort-within-sections = true known-first-party = ["zwave_js_server", "test"] combine-as-imports = true split-on-trailing-comma = false case-sensitive = true zwave-js-server-python-0.63.0/requirements.txt000066400000000000000000000000421500374325600214560ustar00rootroot00000000000000aiohttp==3.11.18 pydantic==2.11.3 zwave-js-server-python-0.63.0/requirements_dev.txt000066400000000000000000000001641500374325600223210ustar00rootroot00000000000000-r requirements.txt -r requirements_lint.txt -r requirements_scripts.txt -r requirements_test.txt tox==4.25.0 -e . zwave-js-server-python-0.63.0/requirements_lint.txt000066400000000000000000000001501500374325600225040ustar00rootroot00000000000000black==25.1.0 mypy==1.15.0 pylint==3.3.6 pylint-strict-informational==0.1 pre-commit==4.2.0 ruff==0.11.7zwave-js-server-python-0.63.0/requirements_scripts.txt000066400000000000000000000001701500374325600232270ustar00rootroot00000000000000colorlog==6.9.0 python-slugify==8.0.4 types-python-slugify==8.0.2.20240310 -r requirements.txt -r requirements_lint.txt zwave-js-server-python-0.63.0/requirements_test.txt000066400000000000000000000001141500374325600225150ustar00rootroot00000000000000pytest==8.3.5 pytest-aiohttp==1.1.0 pytest-cov==6.1.1 pytest-timeout==2.3.1 zwave-js-server-python-0.63.0/scripts/000077500000000000000000000000001500374325600176655ustar00rootroot00000000000000zwave-js-server-python-0.63.0/scripts/.gitignore000066400000000000000000000001121500374325600216470ustar00rootroot00000000000000node_modules *.lock package-lock.json *.json !package.json !tsconfig.json zwave-js-server-python-0.63.0/scripts/README.md000066400000000000000000000217561500374325600211570ustar00rootroot00000000000000# Scripts This directory contains scripts that are used to help maintain this library. ## Python scripts To run these scripts, you will need to install `zwave-js-server-python` library's [requirements_scripts.txt](../../requirements_scripts.txt) into your environment. These scripts have to be run manually, and any changes that result from running the scripts have to be submitted as a PR to be included in the project. ### `generate_multilevel_sensor_constants.py` This script is used to download the latest multilevel sensor types and scales registries from the [zwave-js](https://github.com/zwave-js/zwave-js-server) repository and generate constants for the multilevel sensor command class. The generated constants can be found [here](../../zwave_js_server/const/command_class/multilevel_sensor.py). ### `generate_notification_constants.py` This script is used to download the latest notification registry from the [zwave-js](https://github.com/zwave-js/zwave-js-server) repository and generate constants for the notification command class. The generated constants can be found [here](../../zwave_js_server/const/command_class/notification.py). ### `run_mock_server.py` This script allows you to run a mock Z-Wave JS Server instance using a network state dump from the `zwave-js-server-python` library. While the functionality is limited for now and is intended to be expanded in the future, the mock server also supports manipulating the state of the network by replaying events on it and emulating a responsive network by setting up mocked responses to commands. The main purpose of this mock server is to allow developers to test, build, and troubleshoot applications that use the `zwave-js-server-python` library to integrate with [zwave-js](https://github.com/zwave-js/node-zwave-js) (e.g. Home Assistant). #### Usage At a minimum, the mock server instance needs the file path to a network state dump (which can be retrieved from an existing network using the library's [dump](../../zwave_js_server/dump.py) module). All other inputs are optional. ``` usage: run_mock_server.py [-h] [--host HOST] [--port PORT] [--log-level {DEBUG,INFO,WARNING,ERROR}] [--events-to-replay-path EVENTS_TO_REPLAY_PATH] [--command-results-path COMMAND_RESULTS_PATH] [--combined-replay-dump-path COMBINED_REPLAY_DUMP_PATH] network_state_path Mock Z-Wave JS Server positional arguments: network_state_path File path to network state dump JSON. optional arguments: -h, --help show this help message and exit --host HOST Host to bind to --port PORT Port to run on (defaults to 3000) --log-level {DEBUG,INFO,WARNING,ERROR} Log level for the mock server instance --events-to-replay-path EVENTS_TO_REPLAY_PATH File path to events to replay JSON. Events provided by --combined-replay-dump-path option will be first, followed by events from this file. --command-results-path COMMAND_RESULTS_PATH File path to command result JSON. Command results provided by --combined-replay-dump-path option will be first, followed by results from this file. --combined-replay-dump-path COMBINED_REPLAY_DUMP_PATH File path to the combined event and command result dump JSON. Events and command results will be extracted in the order they were received. ``` #### Inputs/File Formats ##### Network State Dump (required) The network state dump tells the server what the initial state of the network should be for the driver, the controller, and all of the network's nodes. The output of the library's [dump](../../zwave_js_server/dump.py) module can be used directly as the input to the server. ###### File Format ```json [ { "type": "version", "driverVersion": "10.3.1", "serverVersion": "1.24.1", "homeId": "123456789", "minSchemaVersion": 0, "maxSchemaVersion": 24 }, { "type": "result", "success": true, "messageId": "initialize", "result": {} }, { "type": "result", "success": true, "messageId": "start-listening", "result": { "state": { "driver": { ... // driver state dictionary }, "controller": { ... // controller state dictinoary }, "nodes": [ ... // list of node state dictionaries ] } } } ] ``` ##### Events to Replay (optional) `zwave-js` events can be replayed on the server once a client has connected to the server instance and started listening to emulate things happening on the network. These events can be provided initially at runtime via a JSON file, but the server also has a [`/replay` endpoint](#replay-endpoint) that can be POSTed to in order to add events to the replay queue. Command results can be recorded from a live network using the library's Client class (see the [Recording section](#recording-events-and-commandscommand-responses) for more details) ###### Limitations - The queue currently only gets played immediately after a new client starts listening to the server - The events will fire sequentially without any delays between the events - There is currently no way to clear the queue - There is currently no way to fire an event on demand - There is currently no way to control the timing of the events - There is currently no way to reorder events in the queue ###### File Format ```json [ { "record_type": "event", "ts": "2017-02-15T20:26:08.937881", // unused, can be omitted "type": "", // unused, can be omitted "event_msg": { ... // event message as the server would send it to the client } } ] ``` ##### Command Results (optional) The server can respond to commands from a queue of command responses. After each command, the first response for that command is removed from the queue and sent back to the client. In this way, you can control the exact behavior of what the server would send the client, even if there are multiple calls for the same command. These command results can be provided initially at runtime via a JSON file, but the server also has a [`/replay` endpoint](#replay-endpoint) that can be POSTed to in order to add command results to the queue. Command results can be recorded from a live network using the library's Client class (see the [Recording section](#recording-events-and-commandscommand-responses) for more details) ###### Limitations - Unlike events, which remain in the queue forever, command results are only returned once. To add to the queue, use the `/replay` endpoint - There is currently no way to clear a queue for a particular command - There is currently no way to clear all command responses - There is currently no way to reorder command results in the queue ###### File Format ```json [ { "record_type": "command", "ts": "2017-02-15T20:26:08.937881", // unused, can be omitted "command": "", // unused, can be omitted "command_msg": { ... // command message as the library would send it to the server }, "result_ts": "2017-02-15T20:26:08.937881", // unused, can be omitted "result_msg": { ... // response message as the server would send it to the client } } ] ``` #### Recording events and commands/command responses The library's Client class can record event and command/command result messages that occur between a server instance and a client. This would allow you to e.g. troubleshoot a user's problem by having them record everything that happens, reproduce the issue, and then send you the result to feed directly into the mock server. ##### Begin recording There are two ways to enable recording of commands and messages: 1. When creating the Client class instance, pass `record_messages=True` into the Client constructor and the class instance will begin recording all events, commands, and results of commands after the client starts listening to updates from the server. 2. Call `Client.begin_recording_messages()` at any point to begin recording all events, commands, and results of commands. ##### End recording You can end recording by calling `Client.end_recording_messages()`. This call will return a list which can be directly passed into the `--combined-replay-dump-path` option once serialized to a JSON file. #### `/replay` endpoint The `replay` endpoint accepts an HTTP POST request with either a single event or command/command response or a list of them. They will be added to the end of their respective queue. ## Typescript scripts To run these scripts, go to the `scripts` folder and run `yarn install`. ### `serialize_zwave_js_registries.ts` This script imports helper functions from Z-Wave JS to retrieve the Z-Wave JS registries used in the Python scripts above. zwave-js-server-python-0.63.0/scripts/const.py000066400000000000000000000021441500374325600213660ustar00rootroot00000000000000"""Constants for scripts package.""" AUTO_GEN_POST = [ "", "# ----------------------------------------------------------------------------------- #", "# **END OF AUTOGENERATED CONTENT** (DO NOT EDIT/REMOVE THIS COMMENT BLOCK AND DO NOT #", "# EDIT ANYTHING ABOVE IT. IF A NEW IMPORT IS NEEDED, ADD IT TO THE IMPORTS IN THE #", "# CORRESPONDING GENERATION SCRIPT THEN RE-RUN THE SCRIPT. LINES WRITTEN BELOW THIS #", "# BLOCK WILL BE PRESERVED AS LONG AS THIS BLOCK REMAINS) #", "# ----------------------------------------------------------------------------------- #", "", ] AUTO_GEN_PRE = [ "", "# ----------------------------------------------------------------------------------- #", "# **BEGINNING OF AUTOGENERATED CONTENT** (TO ADD ADDITIONAL MANUAL CONTENT, LOOK FOR #", '# THE "END OF AUTOGENERATED CONTENT" COMMENT BLOCK AND ADD YOUR CODE BELOW IT) #', "# ----------------------------------------------------------------------------------- #", "", ] GITHUB_PROJECT = "zwave-js/node-zwave-js" BRANCH_NAME = "master" zwave-js-server-python-0.63.0/scripts/generate_multilevel_sensor_constants.py000077500000000000000000000124301500374325600277630ustar00rootroot00000000000000#!/usr/bin/env python3 """Script to generate Multilevel Sensor CC constants.""" from __future__ import annotations from collections import defaultdict from collections.abc import Callable, Mapping import pathlib from const import AUTO_GEN_POST, AUTO_GEN_PRE from helpers import ( enum_name_format, format_for_class_name, get_json, get_manually_written_code, get_registry_location, run_black, separate_camel_case, ) CONST_FILE_PATH = ( pathlib.Path(__file__).parent.parent / "zwave_js_server/const/command_class/multilevel_sensor.py" ) def normalize_scale_definition(scale_definitions: dict[str, dict]) -> dict[str, int]: """Convert a scales definition dictionary into a normalized dictionary.""" scale_def_ = {} for scale_id, scale_props in scale_definitions.items(): scale_name_ = enum_name_format(scale_props["label"], True) scale_def_[scale_name_] = scale_id return dict(sorted(scale_def_.items(), key=lambda kv: kv[0])) scales = {} sensors = {} for sensor_props in get_json("sensors.json"): sensor_id = sensor_props["key"] scale_def = sensor_props["scales"] remove_parenthesis_ = True if sensor_id in (87, 88): remove_parenthesis_ = False sensor_name = enum_name_format(sensor_props["label"], remove_parenthesis_) sensors[sensor_name] = {"id": sensor_id, "label": sensor_props["label"]} scale_name = separate_camel_case(sensor_props.get("scaleGroupName", "")) if not (scale_name := enum_name_format(scale_name, remove_parenthesis_)): scale_name = sensor_name scales.setdefault(scale_name, {}).update(normalize_scale_definition(scale_def)) sensors[sensor_name]["scale"] = scale_name scales = dict(sorted(scales.items(), key=lambda kv: kv[0])) sensors = dict(sorted(sensors.items(), key=lambda kv: kv[0])) def generate_int_enum_class_definition( class_name: str, enum_map: Mapping[str, int | str | dict], enum_ref_url: str | None = None, get_id_func: Callable | None = None, docstring_info: str = "", base_class: str = "IntEnum", ) -> list[str]: """Generate an IntEnum class definition as an array of lines of string.""" class_def: list[str] = [] class_def.append(f"class {class_name}({base_class}):") docstring = ( f'"""Enum for known {docstring_info} multilevel sensor types."""'.replace( " ", " " ) ) class_def.append(f" {docstring}") if enum_ref_url: class_def.append(f" # {enum_ref_url}") for enum_name, enum_id in enum_map.items(): if get_id_func: enum_id = get_id_func(enum_id) class_def.append(f" {enum_name} = {enum_id}") return class_def def generate_int_enum_base_class(class_name: str, docstring: str) -> list[str]: """Generate an IntEnum base class definition.""" class_def: list[str] = [] class_def.append(f"class {class_name}(IntEnum):") class_def.append(f"\t{docstring}") return class_def SENSOR_TYPE_URL = get_registry_location("SensorTypes.ts") lines = [ '"""Constants for the Multilevel Sensor CC."""', *AUTO_GEN_PRE, "from __future__ import annotations", "", "from enum import IntEnum", 'CC_SPECIFIC_SCALE = "scale"', 'CC_SPECIFIC_SENSOR_TYPE = "sensorType"', "", ] lines.extend( [f"{sensor}_PROPERTY = \"{data['label']}\"" for sensor, data in sensors.items()] ) lines.extend( generate_int_enum_class_definition( "MultilevelSensorType", sensors, SENSOR_TYPE_URL, get_id_func=lambda x: x["id"], ) ) lines.extend( generate_int_enum_base_class( "MultilevelSensorScaleType", docstring='"""Common base class for multilevel sensor scale enums."""', ) ) _unit_name_to_enum_map = defaultdict(list) for scale_name, scale_dict in scales.items(): lines.extend( generate_int_enum_class_definition( format_for_class_name(scale_name, "Scale"), scale_dict, SENSOR_TYPE_URL, docstring_info=f"scales for {scale_name}", base_class="MultilevelSensorScaleType", ) ) for unit_name in scale_dict.keys(): _unit_name_to_enum_map[unit_name].append( f"{format_for_class_name(scale_name, 'Scale')}.{unit_name}" ) unit_name_to_enum_map = dict( sorted(_unit_name_to_enum_map.items(), key=lambda kv: kv[0]) ) for unit_name, enum_list in unit_name_to_enum_map.items(): unit_name_to_enum_map[unit_name] = sorted(enum_list) multilevel_sensor_type_to_scale_map_line = ( "MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: dict[MultilevelSensorType, " "type[MultilevelSensorScaleType]] = {" ) for sensor_name, sensor_def in sensors.items(): multilevel_sensor_type_to_scale_map_line += ( f" MultilevelSensorType.{sensor_name}: " f"{format_for_class_name(sensor_def['scale'], 'Scale')}," ) multilevel_sensor_type_to_scale_map_line += "}" lines.append(multilevel_sensor_type_to_scale_map_line) lines.append("") for unit_name, unit_enums in unit_name_to_enum_map.items(): lines.append( f"UNIT_{unit_name}: list[MultilevelSensorScaleType] = [{','.join(sorted(unit_enums))}]" ) lines.extend(AUTO_GEN_POST) lines.extend(get_manually_written_code(CONST_FILE_PATH)) CONST_FILE_PATH.write_text("\n".join(lines), encoding="utf-8") run_black(CONST_FILE_PATH) zwave-js-server-python-0.63.0/scripts/generate_notification_constants.py000077500000000000000000000170001500374325600266740ustar00rootroot00000000000000#!/usr/bin/env python3 """Script to generate Notification CC constants.""" from __future__ import annotations from collections.abc import Callable, Mapping import pathlib from const import AUTO_GEN_POST, AUTO_GEN_PRE from helpers import ( enum_name_format, format_for_class_name, get_json, get_manually_written_code, get_registry_location, run_black, ) CONST_FILE_PATH = ( pathlib.Path(__file__).parent.parent / "zwave_js_server/const/command_class/notification.py" ) notifications = {} params = {} for notification_payload in get_json("notifications.json"): notification_type = notification_payload["type"] notification_name = notification_payload["name"].title() notifications[notification_name] = { "type": notification_type, "events": {}, } for event in notification_payload.get("variables", []): event_name = event["name"].title() states = notifications[notification_name]["events"] for state_props in event["states"].values(): state_id = state_props["value"] state_name = state_props["label"].title() if ( state_name.lower() not in event_name.lower() and event_name.lower() not in state_name.lower() ): state_name = f"{event_name} {state_name}" states[state_name] = state_id if ( "parameter" in state_props and state_props["parameter"]["type"] == "enum" ): for enum_id, enum_name in state_props["parameter"]["values"].items(): enum_id = int(enum_id) params.setdefault(notification_name, {}).setdefault(state_name, {})[ enum_name.title() ] = enum_id for event_data in notification_payload.get("events", {}).values(): event_id = event_data["value"] notifications[notification_name]["events"][ event_data["label"].title() ] = event_id notifications = dict(sorted(notifications.items(), key=lambda kv: kv[0])) params = dict(sorted(params.items(), key=lambda kv: kv[0])) for notification_name, enum_data in params.items(): params[notification_name] = dict(sorted(enum_data.items(), key=lambda kv: kv[0])) def generate_int_enum_class_definition( class_name: str, enum_map: Mapping[str, int | str | dict], enum_ref_url: str | None = None, get_id_func: Callable | None = None, docstring_info: str = "", base_class: str = "IntEnum", ) -> list[str]: """Generate an IntEnum class definition as an array of lines of string.""" class_def: list[str] = [] class_def.append(f"class {class_name}({base_class}):") docstring = f'"""Enum for known {docstring_info}."""'.replace(" ", " ") class_def.append(f" {docstring}") if enum_ref_url: class_def.append(f" # {enum_ref_url}") class_def.append(" UNKNOWN = -1") for _enum_name, _enum_id in sorted(enum_map.items(), key=lambda x: x[0]): if get_id_func: _enum_id = get_id_func(_enum_id) class_def.append(f" {enum_name_format(_enum_name, False)} = {_enum_id}") class_def.extend( [ " @classmethod", f" def _missing_(cls: type, value: object) -> {class_name}: # noqa: ARG003", ' """Set default enum member if an unknown value is provided."""', f" return {class_name}.UNKNOWN", ] ) return class_def def generate_int_enum_base_class(class_name: str, docstring: str) -> list[str]: """Generate an IntEnum base class definition.""" class_def: list[str] = [] class_def.append(f"class {class_name}(IntEnum):") class_def.append(f" {docstring}") return class_def NOTIFICATIONS_URL = get_registry_location("Notifications.ts") lines = [ "# pylint: disable=line-too-long", '"""Constants for the Notification CC."""', *AUTO_GEN_PRE, "from __future__ import annotations", "", "from enum import IntEnum", 'CC_SPECIFIC_NOTIFICATION_TYPE = "notificationType"', ] lines.extend( generate_int_enum_class_definition( "NotificationType", notifications, NOTIFICATIONS_URL, get_id_func=lambda x: x["type"], docstring_info="notification types", ) ) lines.extend( generate_int_enum_base_class( "NotificationEvent", docstring='"""Common base class for Notification CC states enums."""', ) ) lines.extend( generate_int_enum_base_class( "NotificationEventValue", docstring='"""Common base class for Notification CC state value enums."""', ) ) # Add events that have enums _notification_type_to_notification_event_map = {} _notification_event_to_event_value_map = {} for notification_type, event_map in notifications.items(): notification_event_name = f"{notification_type} Notification Event" lines.extend( generate_int_enum_class_definition( format_for_class_name(notification_event_name), event_map["events"], NOTIFICATIONS_URL, docstring_info=notification_event_name.lower(), base_class="NotificationEvent", ) ) _notification_type_to_notification_event_map[notification_type] = ( format_for_class_name(notification_event_name) ) if notification_type in params: for event_name, event_values in params[notification_type].items(): notification_event_value_name = f"{event_name} Notification Event Value" lines.extend( generate_int_enum_class_definition( format_for_class_name(notification_event_value_name), event_values, NOTIFICATIONS_URL, docstring_info=notification_event_value_name.lower(), base_class="NotificationEventValue", ) ) _notification_event_to_event_value_map[ f"{format_for_class_name(notification_event_name)}.{enum_name_format(event_name, False)}" ] = format_for_class_name(notification_event_value_name) notification_type_to_notification_event_map = dict( sorted(_notification_type_to_notification_event_map.items(), key=lambda kv: kv[0]) ) notification_type_to_event_map_line = ( "NOTIFICATION_TYPE_TO_EVENT_MAP: dict[NotificationType, " "type[NotificationEvent]] = {" ) for ( notification_type, notification_event, ) in notification_type_to_notification_event_map.items(): notification_type_to_event_map_line += f" NotificationType.{enum_name_format(notification_type, False)}: {notification_event}," notification_type_to_event_map_line += "}" lines.append(notification_type_to_event_map_line) lines.append("") notification_event_to_event_value_map = dict( sorted(_notification_event_to_event_value_map.items(), key=lambda kv: kv[0]) ) notification_event_to_event_value_map_line = ( "NOTIFICATION_EVENT_TO_EVENT_VALUE_MAP: dict[NotificationEvent, " "type[NotificationEventValue]] = {" ) for ( notification_event, notification_event_value, ) in notification_event_to_event_value_map.items(): notification_event_to_event_value_map_line += ( f" {notification_event}: {notification_event_value}," ) notification_event_to_event_value_map_line += "}" lines.append(notification_event_to_event_value_map_line) lines.append("") lines.extend(AUTO_GEN_POST) lines.extend(get_manually_written_code(CONST_FILE_PATH)) CONST_FILE_PATH.write_text("\n".join(lines), encoding="utf-8") run_black(CONST_FILE_PATH) zwave-js-server-python-0.63.0/scripts/generate_zwave_js_registry_json.js000066400000000000000000000006721500374325600267130ustar00rootroot00000000000000import { getAllNotifications, getAllSensors } from "@zwave-js/core"; import fs from "fs"; for (const [filename, data] of Object.entries({ "notifications.json": getAllNotifications(), "sensors.json": getAllSensors(), })) { if (fs.existsSync(filename)) { fs.unlinkSync(filename); } fs.writeFileSync( filename, JSON.stringify(data, (_, value) => value instanceof Map ? Object.fromEntries(value) : value ) ); } zwave-js-server-python-0.63.0/scripts/helpers.py000066400000000000000000000062341500374325600217060ustar00rootroot00000000000000"""Helpers for scripts.""" import json import pathlib import re import subprocess import sys from const import BRANCH_NAME, GITHUB_PROJECT from slugify import slugify def check_dirty_repo(): """Check if repo is dirty and message user.""" if subprocess.run(["which", "git"], capture_output=True, check=True).stdout: if ( subprocess.run( ["git", "diff", "--stat"], check=True, ).stdout is not None ): print("Repo is dirty and needs to be committed!") sys.exit(1) else: print( "Could not run `git diff --stat` on repo, please run it to determine " "whether constants have changed." ) def get_registry_location(filename: str) -> str: """Get the registry location for the given filename.""" return ( f"https://github.com/{GITHUB_PROJECT}/blob/{BRANCH_NAME}/packages/core/" f"src/registries/{filename}" ) def run_black(file_path: str): """Run black on the given file path.""" if subprocess.run(["which", "black"], capture_output=True, check=True).stdout: subprocess.run( ["black", file_path], check=True, ) else: print("Could not run black on new file, please run it to properly format it.") def get_manually_written_code(file_path: str): """Get a list of manually written code from the given file path.""" existing_const_file = file_path.read_text(encoding="utf-8").splitlines() manually_written_code_start_idx = ( next( i for i, line in enumerate(existing_const_file) if "**END OF AUTOGENERATED CONTENT**" in line ) + 6 ) if len(existing_const_file) > manually_written_code_start_idx: return [ line.strip("\n") for line in existing_const_file[manually_written_code_start_idx:] ] return [] def remove_parenthesis(text: str) -> str: """Remove text in parenthesis from a string.""" return re.sub(r"\([^)]*\)", "", text) def enum_name_format(name: str, should_remove_parenthesis: bool) -> str: """Convert sensor/scale name to enum format.""" if should_remove_parenthesis: name = remove_parenthesis(name) return slugify(name, separator="_").upper() def separate_camel_case(my_str: str) -> str: """Split a camel case string.""" if all(char.islower() for char in my_str): return my_str.title() start_idx = [i for i, e in enumerate(my_str) if e.isupper()] + [len(my_str)] start_idx = [0] + start_idx return " ".join(my_str[x:y] for x, y in zip(start_idx, start_idx[1:])).title() def get_json(file_path: str) -> list | dict: """Get a JSON dict/list from the given file path.""" return json.loads(pathlib.Path(file_path).read_text()) def normalize_name(name: str) -> str: """Convert a sensor/scale name into a normalized name.""" return enum_name_format(name, True).replace("_", " ").title() def format_for_class_name(name: str, suffix: str = "") -> str: """Convert sensor/scale name to class name format.""" return f"{normalize_name(name).replace(' ', '')}{suffix}" zwave-js-server-python-0.63.0/scripts/run-in-env.sh000077500000000000000000000007121500374325600222220ustar00rootroot00000000000000#!/usr/bin/env sh set -eu # Activate pyenv and virtualenv if present, then run the specified command # pyenv, pyenv-virtualenv if [ -s .python-version ]; then PYENV_VERSION=$(head -n 1 .python-version) export PYENV_VERSION fi # other common virtualenvs my_path=$(git rev-parse --show-toplevel) for venv in venv .venv .; do if [ -f "${my_path}/${venv}/bin/activate" ]; then . "${my_path}/${venv}/bin/activate" break fi done exec "$@" zwave-js-server-python-0.63.0/scripts/run_mock_server.py000066400000000000000000000330441500374325600234460ustar00rootroot00000000000000"""Run a mock zwave-js-server instance off of a network state dump.""" from __future__ import annotations import argparse import asyncio from collections import defaultdict from collections.abc import Hashable import json import logging from typing import Any from aiohttp import WSMsgType, web, web_request from zwave_js_server.client import SIZE_PARSE_JSON_EXECUTOR from zwave_js_server.const import MAX_SERVER_SCHEMA_VERSION, MIN_SERVER_SCHEMA_VERSION from zwave_js_server.model.version import VersionInfoDataType DATEFMT = "%Y-%m-%d %H:%M:%S" FMT = "%(asctime)s [%(levelname)s] %(message)s" class ExitException(Exception): """Represent an exit error.""" # https://stackoverflow.com/a/1151686 class HashableDict(dict): """Dictionary that can be used as a key in a dictionary.""" def __key(self) -> tuple: """Return key representation of HashableDict.""" return tuple((k, self[k]) for k in sorted(self)) def __hash__(self) -> int: # type: ignore """Return hash representation of HashableDict.""" return hash(self.__key()) def __eq__(self, other: Any) -> bool: """Return whether HashableDict is equal to other.""" # pylint: disable=protected-access return isinstance(other, HashableDict) and self.__key() == other.__key() class MockZwaveJsServer: """ Class to represent a mock zwave-js-server instance. The last client that connected to the server will be the one that receives ws msgs. """ def __init__( self, network_state_dump: list[dict], events_to_replay: list[dict], command_results: defaultdict[HashableDict, list], ) -> None: """Initialize class.""" self.network_state_dump = network_state_dump self.app = web.Application() self.app.add_routes( [ web.get("/", self.server_handler), web.post("/replay", self.replay_handler), ] ) self.primary_ws_resp: web.WebSocketResponse | None = None self.events_to_replay = events_to_replay self.command_results = command_results async def send_json(self, data: dict) -> None: """Send JSON.""" logging.debug("Sending JSON: %s", data) assert self.primary_ws_resp is not None await self.primary_ws_resp.send_json(data) async def send_command_result( self, data: dict, message_id: str, ) -> None: """Send message.""" await self.send_json({**data, "messageId": message_id}) async def send_success_command_result( self, result: dict | None, message_id: str ) -> None: """Send success message.""" if result is None: result = {} await self.send_command_result( {"result": result, "type": "result", "success": True}, message_id ) async def process_record(self, record: dict) -> None: """Process a replay dump record.""" if record.get("record_type") not in ("event", "command"): raise TypeError(f"Malformed record: {record}") if record["record_type"] == "event": await self.send_json(record["event_msg"]) else: add_command_result(self.command_results, record) async def server_handler( self, request: web_request.Request ) -> web.WebSocketResponse: """Handle websocket requests to the server.""" ws_resp = web.WebSocketResponse(autoclose=False) self.primary_ws_resp = ws_resp await ws_resp.prepare(request) version_info: VersionInfoDataType = self.network_state_dump[0] # adjust min/max schemas if needed to get things to work version_info["maxSchemaVersion"] = max( MAX_SERVER_SCHEMA_VERSION, version_info["maxSchemaVersion"] ) version_info["minSchemaVersion"] = min( MIN_SERVER_SCHEMA_VERSION, version_info["minSchemaVersion"] ) await self.send_json(version_info) async for msg in ws_resp: if msg.type == WSMsgType.TEXT: logging.debug("Message received: %s", msg.data) if msg.data == "close": await ws_resp.close() elif msg.data == "error": logging.warning("Error from client: %s", msg.data) try: if len(msg.data) > SIZE_PARSE_JSON_EXECUTOR: data: dict = await asyncio.get_event_loop().run_in_executor( None, msg.json ) else: data = msg.json() except ValueError as err: raise ExitException(f"Received invalid JSON {msg.data}") from err if "command" not in data: raise ExitException(f"Malformed message: {data}") cmd = data["command"] message_id = data["messageId"] if cmd == "initialize": await self.send_json(self.network_state_dump[1]) elif cmd == "driver.get_log_config": await self.send_success_command_result( { "config": { "enabled": True, "level": "silly", "logToFile": False, "nodeFilter": [], "filename": None, "forceConsole": False, } }, message_id, ) elif cmd == "start_listening": await self.send_json(self.network_state_dump[2]) await asyncio.sleep(1) for event in self.events_to_replay: await self.send_json(event) elif resp_list := self.command_results[sanitize_msg(data)]: await self.send_command_result(resp_list.pop(0), message_id) else: raise ExitException(f"Unhandled command received: {data}") elif msg.type == WSMsgType.ERROR: logging.error( "Connection closed with exception %s", ws_resp.exception(), ) logging.info("Connection closed") return ws_resp async def replay_handler(self, request: web_request.Request) -> web.Response: """Handle requests to replay dump.""" try: data = await request.json() except json.decoder.JSONDecodeError: return web.Response(status=400, reason="Invalid JSON.") if isinstance(data, list): for record in data: try: await self.process_record(record) except Exception as err: return web.Response(status=400, reason=err.args[0]) elif isinstance(data, dict): try: await self.process_record(data) except Exception as err: return web.Response(status=400, reason=err.args[0]) else: return web.Response(status=400, reason=f"Malformed message: {data}") return web.Response(status=200) def _hashable_value(item: dict | list | Hashable) -> tuple | list | Hashable: """Return hashable value from item.""" if isinstance(item, dict): return make_dict_hashable(item) if isinstance(item, list): return make_list_hashable(item) return item def make_list_hashable(lst: list) -> tuple: """Make a list hashable.""" return tuple(_hashable_value(item) for item in lst) def make_dict_hashable(dct: dict) -> HashableDict: """Convert a dictionary to a hashable dictionary.""" return HashableDict({key: _hashable_value(value) for key, value in dct.items()}) def sanitize_msg(msg: dict) -> HashableDict: """Sanitize command message.""" msg = msg.copy() msg.pop("messageId", None) return make_dict_hashable(msg) def add_command_result( command_results: defaultdict[HashableDict, list], record: dict, ) -> None: """Add a command result to command_results map.""" if "result_msg" not in record: logging.warning( "The following record cannot be used because the client did not wait for " "a response: %s", record, ) return command_msg = sanitize_msg(record["command_msg"]) # Response message doesn't need to be sanitized here because it will be sanitized # in the MockZwaveJsServer.send_command_result method. result_msg = record["result_msg"] command_results[command_msg].append(result_msg) def get_args() -> argparse.Namespace: """Get arguments.""" parser = argparse.ArgumentParser(description="Mock Z-Wave JS Server") parser.add_argument( "network_state_path", type=str, help="File path to network state dump JSON." ) parser.add_argument("--host", type=str, help="Host to bind to", default="127.0.0.1") parser.add_argument( "--port", type=int, help="Port to run on (defaults to 3000)", default=3000 ) parser.add_argument( "--log-level", type=str.upper, help="Log level for the mock server instance", default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR"], ) parser.add_argument( "--events-to-replay-path", type=str, help=( "File path to events to replay JSON. Events provided by " "--combined-replay-dump-path option will be first, followed by events " "from this file." ), default=None, ) parser.add_argument( "--command-results-path", type=str, help=( "File path to command result JSON. Command results provided by " "--combined-replay-dump-path option will be first, followed by results " "from this file." ), default=None, ) parser.add_argument( "--combined-replay-dump-path", type=str, help=( "File path to the combined event and command result dump JSON. Events and " "command results will be extracted in the order they were received." ), default=None, ) return parser.parse_args() def main() -> None: """Run main entrypoint.""" args = get_args() with open(args.network_state_path, encoding="utf8") as fp: network_state_dump: list[dict] = json.load(fp) events_to_replay = [] command_results: defaultdict[HashableDict, list] = defaultdict(list) if args.combined_replay_dump_path: with open(args.combined_replay_dump_path, encoding="utf8") as fp: records: list[dict] = json.load(fp) for record in records: if record.get("record_type") not in ("event", "command"): raise ExitException( f"Invalid record in combined replay dump file: {record}" ) if record["record_type"] == "event": events_to_replay.append(record["event_msg"]) else: add_command_result(command_results, record) if args.events_to_replay_path: with open(args.events_to_replay_path, encoding="utf8") as fp: records = json.load(fp) if ( bad_record := next( ( record for record in records if record.get("record_type") != "event" ), None, ) ) is not None: raise ExitException( f"Malformed record in events to replay file: {bad_record}" ) events_to_replay.extend([record["event_msg"] for record in records]) if args.command_results_path: with open(args.command_results_path, encoding="utf8") as fp: records = json.load(fp) if ( bad_record := next( ( record for record in records if record.get("record_type") != "command" ), None, ) ) is not None: raise ExitException( f"Malformed record in command results dump file: {bad_record}" ) for record in records: add_command_result(command_results, record) # adapted from homeassistant.bootstrap.async_enable_logging logging.basicConfig(level=args.log_level) try: # pylint: disable=import-outside-toplevel from colorlog import ColoredFormatter colorfmt = f"%(log_color)s{FMT}%(reset)s" logging.getLogger().handlers[0].setFormatter( ColoredFormatter( colorfmt, datefmt=DATEFMT, log_colors={ "DEBUG": "cyan", "INFO": "green", "WARNING": "yellow", "ERROR": "red", "CRITICAL": "red", }, ) ) except ImportError: logging.getLogger().handlers[0].setFormatter( logging.Formatter(fmt=FMT, datefmt=DATEFMT) ) server = MockZwaveJsServer(network_state_dump, events_to_replay, command_results) web.run_app(server.app, host=args.host, port=args.port) if __name__ == "__main__": try: main() except ExitException as error: logging.error("Fatal error: %s", error) zwave-js-server-python-0.63.0/scripts/setup000077500000000000000000000003741500374325600207570ustar00rootroot00000000000000#!/usr/bin/env bash # Setups the repository. # Stop on errors set -e if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ];then python3 -m venv venv source venv/bin/activate fi python3 -m pip install -r requirements_dev.txt pre-commit install zwave-js-server-python-0.63.0/test/000077500000000000000000000000001500374325600171555ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/__init__.py000066400000000000000000000002701500374325600212650ustar00rootroot00000000000000"""Provide tests for zwave-js-server.""" import pathlib def load_fixture(name): """Load a fixture.""" return (pathlib.Path(__file__).parent / "fixtures" / name).read_text() zwave-js-server-python-0.63.0/test/common.py000066400000000000000000000013641500374325600210230ustar00rootroot00000000000000"""Common methods for tests.""" import asyncio from typing import Protocol from unittest.mock import AsyncMock class MockCommandProtocol(Protocol): """Represent the function signature of the mock_command callable.""" def __call__( self, command: dict, response: dict, success: bool = True ) -> list[dict]: """Represent the signature of the mock_command callable.""" def update_ws_client_msg_queue(fixture, new_messages): """Update a ws client fixture with a new message queue.""" to_receive = asyncio.Queue() for message in new_messages: to_receive.put_nowait(message) async def receive_json(): return await to_receive.get() fixture.receive_json = AsyncMock(side_effect=receive_json) zwave-js-server-python-0.63.0/test/conftest.py000066400000000000000000000410601500374325600213550ustar00rootroot00000000000000"""Provide common pytest fixtures.""" import asyncio from collections import deque from collections.abc import Generator from copy import deepcopy import json from typing import Any from unittest.mock import AsyncMock, Mock, patch from aiohttp import ClientSession, ClientWebSocketResponse from aiohttp.http_websocket import WSMessage, WSMsgType import pytest from zwave_js_server.client import Client from zwave_js_server.model.controller import Controller from zwave_js_server.model.driver import Driver from zwave_js_server.model.node import Node from . import load_fixture from .common import MockCommandProtocol # pylint: disable=protected-access, unused-argument TEST_URL = "ws://test.org:3000" @pytest.fixture(name="controller_state", scope="session") def controller_state_fixture() -> dict[str, Any]: """Load the controller state fixture data.""" return json.loads(load_fixture("controller_state.json")) @pytest.fixture(name="multisensor_6_state", scope="session") def multisensor_6_state_fixture(): """Load the multisensor 6 node state fixture data.""" return json.loads(load_fixture("multisensor_6_state.json")) @pytest.fixture(name="lock_schlage_be469_state", scope="session") def lock_schlage_be469_state_fixture(): """Load the schlage lock node state fixture data.""" return json.loads(load_fixture("lock_schlage_be469_state.json")) @pytest.fixture(name="timed_lock_state", scope="session") def timed_lock_state_fixture() -> dict[str, Any]: """Load the timed lock node state fixture data.""" return json.loads(load_fixture("timed_lock_state.json")) @pytest.fixture(name="climate_radio_thermostat_ct100_plus_state", scope="session") def climate_radio_thermostat_ct100_plus_state_fixture(): """Load the radio thermostat node state fixture data.""" return json.loads(load_fixture("climate_radio_thermostat_ct100_plus_state.json")) @pytest.fixture(name="cover_qubino_shutter_state", scope="session") def cover_qubino_shutter_state_fixture(): """Load the qubino shutter cover node state fixture data.""" return json.loads(load_fixture("cover_qubino_shutter_state.json")) @pytest.fixture(name="idl_101_lock_state", scope="session") def idl_101_lock_state_fixture(): """Load the bad string meta data node state fixture data.""" return json.loads(load_fixture("idl_101_lock_state.json")) @pytest.fixture(name="wallmote_central_scene_state", scope="session") def wallmote_central_scene_state_fixture(): """Load the wallmote central scene node state fixture data.""" return json.loads(load_fixture("wallmote_central_scene_state.json")) @pytest.fixture(name="unparseable_json_string_value_state", scope="session") def unparseable_json_string_value_state_fixture(): """Load the unparseable string json value node state fixture data.""" return json.loads(load_fixture("unparseable_json_string_value_state.json")) @pytest.fixture(name="partial_and_full_parameter_state", scope="session") def partial_and_full_parameter_state_fixture(): """Load the node that has both partial and full parameters state fixture data.""" return json.loads(load_fixture("partial_and_full_parameter_state.json")) @pytest.fixture(name="invalid_multilevel_sensor_type_state", scope="session") def invalid_multilevel_sensor_type_state_fixture(): """Load the node that has an invalid multilevel sensor type state fixture data.""" return json.loads(load_fixture("invalid_multilevel_sensor_type_state.json")) @pytest.fixture(name="inovelli_switch_state", scope="session") def inovelli_switch_state_fixture(): """Load the bad string meta data node state fixture data.""" return json.loads(load_fixture("inovelli_switch_state.json")) @pytest.fixture(name="ring_keypad_state", scope="session") def ring_keypad_state_fixture(): """Load the ring keypad node state fixture data.""" return json.loads(load_fixture("ring_keypad_state.json")) @pytest.fixture(name="endpoints_with_command_classes_state", scope="session") def endpoints_with_command_classes_state_fixture(): """Load the node state fixture data with command classes on the endpoint.""" return json.loads(load_fixture("endpoints_with_command_classes_state.json")) @pytest.fixture(name="switch_enbrighten_zw3010_state", scope="session") def switch_enbrighten_zw3010_state_fixture(): """Load the enbrighten zw3010 switch node state fixture data.""" return json.loads(load_fixture("switch_enbrighten_zw3010_state.json")) @pytest.fixture(name="energy_production_state", scope="session") def energy_production_state_fixture(): """Load a mock node with energy production CC state fixture data.""" return json.loads(load_fixture("energy_production_state.json")) @pytest.fixture(name="lock_ultraloq_ubolt_pro_state", scope="session") def lock_ultraloq_ubolt_pro_state_fixture(): """Load the ultraloq U-Bolt Pro lock state fixture data.""" return json.loads(load_fixture("lock_ultraloq_ubolt_pro_state.json")) @pytest.fixture(name="device_config", scope="session") def device_config_fixture() -> dict[str, Any]: """Load the device config fixture data.""" return json.loads(load_fixture("device_config.json")) @pytest.fixture(name="client_session") def client_session_fixture(ws_client: AsyncMock) -> AsyncMock: """Mock an aiohttp client session.""" client_session = AsyncMock(spec_set=ClientSession) client_session.ws_connect.side_effect = AsyncMock(return_value=ws_client) return client_session def create_ws_message(result: dict[str, Any]) -> Mock: """Return a mock WSMessage.""" message = Mock(spec_set=WSMessage) message.type = WSMsgType.TEXT message.data = json.dumps(result) message.json.return_value = result return message @pytest.fixture(name="messages") def messages_fixture() -> deque[Mock]: """Return a message buffer for the WS client.""" return deque() @pytest.fixture(name="ws_client") async def ws_client_fixture( version_data: dict[str, Any], ws_message: Mock, result: dict[str, Any], messages: deque[Mock], initialize_data: dict[str, Any], get_log_config_data: dict[str, Any], ) -> AsyncMock: """Mock a websocket client. This fixture only allows a single message to be received. """ ws_client = AsyncMock(spec_set=ClientWebSocketResponse, closed=False) ws_client.receive_json.side_effect = ( version_data, initialize_data, get_log_config_data, result, ) for data in (version_data, initialize_data, get_log_config_data, result): messages.append(create_ws_message(data)) async def receive() -> Mock: """Return a websocket message.""" await asyncio.sleep(0) try: message = messages.popleft() except IndexError: ws_client.closed = True return WSMessage(WSMsgType.CLOSED, None, None) return message ws_client.receive.side_effect = receive async def close_client(msg: dict[str, Any]) -> None: """Close the client.""" if msg["command"] in ("initialize", "start_listening"): return # We only want to skip for the initial call if ( msg["command"] == "driver.get_log_config" and msg["messageId"] == "get-initial-log-config" ): return await asyncio.sleep(0) ws_client.closed = True ws_client.send_json.side_effect = close_client async def reset_close() -> None: """Reset the websocket client close method.""" ws_client.closed = True ws_client.close.side_effect = reset_close return ws_client @pytest.fixture(name="await_other") async def await_other_fixture(): """Await all other task but the current task.""" async def wait_for_tasks(current_task): """Wait for the tasks.""" tasks = asyncio.all_tasks() - {current_task} await asyncio.gather(*tasks) return wait_for_tasks @pytest.fixture(name="driver_ready") async def driver_ready_fixture(): """Return an asyncio.Event for driver ready.""" return asyncio.Event() @pytest.fixture(name="version_data") def version_data_fixture() -> dict[str, Any]: """Return mock version data.""" return { "type": "version", "driverVersion": "test_driver_version", "serverVersion": "test_server_version", "homeId": "test_home_id", "minSchemaVersion": 0, "maxSchemaVersion": 40, } @pytest.fixture(name="initialize_data") def initialize_data_fixture() -> dict[str, Any]: """Return mock initialize data.""" return { "type": "result", "success": True, "result": {}, "messageId": "initialize", } @pytest.fixture(name="log_config") def log_config_fixture() -> dict[str, Any]: """Return log config.""" return { "enabled": True, "level": "info", "logToFile": False, "filename": "", "forceConsole": False, } @pytest.fixture(name="get_log_config_data") def get_log_config_data_fixture(log_config: dict[str, Any]) -> dict[str, Any]: """Return mock get_log_config data.""" return { "type": "result", "success": True, "result": {"config": log_config}, "messageId": "get-initial-log-config", } @pytest.fixture(name="url") def url_fixture(): """Return a test url.""" return TEST_URL @pytest.fixture(name="result") def result_fixture(controller_state: dict[str, Any], uuid4: str) -> dict[str, Any]: """Return a server result message.""" return { "type": "result", "success": True, "result": {"state": controller_state}, "messageId": uuid4, } @pytest.fixture(name="ws_message") def ws_message_fixture(result: dict[str, Any]) -> Mock: """Return a mock WSMessage.""" return create_ws_message(result) @pytest.fixture(name="uuid4") def mock_uuid_fixture() -> Generator[str, None, None]: """Patch uuid4.""" uuid4_hex = "1234" with patch("uuid.uuid4") as uuid4: uuid4.return_value.hex = uuid4_hex yield uuid4_hex @pytest.fixture(name="client") async def client_fixture( client_session: AsyncMock, ws_client: AsyncMock, uuid4: str, ) -> Client: """Return a client with a mock websocket transport. This fixture needs to be a coroutine function to get an event loop when creating the client. """ client = Client("ws://test.org", client_session) client._client = ws_client return client @pytest.fixture(name="mock_command") def mock_command_fixture( ws_client: AsyncMock, client: Client, uuid4: str ) -> MockCommandProtocol: """Mock a command and response.""" mock_responses: list[tuple[dict, dict, bool]] = [] ack_commands: list[dict] = [] def apply_mock_command( match_command: dict, response: dict, success: bool = True ) -> list[dict]: """Apply the mock command and response return value to the transport. Return the list with correctly acknowledged commands. """ mock_responses.append((match_command, response, success)) return ack_commands async def set_response(message: dict[str, Any]) -> None: """Check the message and set the mocked response if a command matches.""" for match_command, response, success in mock_responses: if all(message[key] == value for key, value in match_command.items()): ack_commands.append(message) received_message = { "type": "result", "messageId": uuid4, "success": success, } if success: received_message["result"] = response else: received_message.update(response) client._handle_incoming_message(received_message) return raise RuntimeError("Command not mocked!") ws_client.send_json.side_effect = set_response return apply_mock_command @pytest.fixture(name="driver") def driver_fixture( client: Client, controller_state: dict[str, Any], log_config: dict[str, Any], ) -> Driver: """Return a driver instance with a supporting client.""" client.driver = Driver(client, deepcopy(controller_state), log_config) return client.driver @pytest.fixture(name="multisensor_6") def multisensor_6_fixture(driver, multisensor_6_state): """Mock a multisensor 6 node.""" node = Node(driver.client, deepcopy(multisensor_6_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="lock_schlage_be469") def lock_schlage_be469_fixture(driver, lock_schlage_be469_state): """Mock a schlage lock node.""" node = Node(driver.client, deepcopy(lock_schlage_be469_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="timed_lock") def timed_lock_fixture(driver: Driver, timed_lock_state: dict[str, Any]) -> Node: """Mock a schlage lock node.""" node = Node(driver.client, deepcopy(timed_lock_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="climate_radio_thermostat_ct100_plus") def climate_radio_thermostat_ct100_plus_fixture( driver, climate_radio_thermostat_ct100_plus_state ): """Mock a radio thermostat node.""" node = Node(driver.client, deepcopy(climate_radio_thermostat_ct100_plus_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="cover_qubino_shutter") def cover_qubino_shutter_fixture(driver, cover_qubino_shutter_state): """Mock a qubino shutter cover node.""" node = Node(driver.client, deepcopy(cover_qubino_shutter_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="wallmote_central_scene") def wallmote_central_scene_fixture(driver, wallmote_central_scene_state): """Mock a wallmote central scene node.""" node = Node(driver.client, deepcopy(wallmote_central_scene_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="controller") def controller_fixture(driver, controller_state): """Return a controller instance with a supporting client.""" controller = Controller(driver.client, deepcopy(controller_state)) return controller @pytest.fixture(name="inovelli_switch") def inovelli_switch_fixture(driver, inovelli_switch_state): """Mock a inovelli switch node.""" node = Node(driver.client, deepcopy(inovelli_switch_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="ring_keypad") def ring_keypad_fixture(driver, ring_keypad_state): """Mock a ring keypad node.""" node = Node(driver.client, deepcopy(ring_keypad_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="partial_and_full_parameter") def partial_and_full_parameter_fixture(driver, partial_and_full_parameter_state): """Mock a node that has both partial and full parameters.""" node = Node(driver.client, deepcopy(partial_and_full_parameter_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="invalid_multilevel_sensor_type") def invalid_multilevel_sensor_type_fixture( driver, invalid_multilevel_sensor_type_state ): """Mock a node that has invalid multilevel sensor type.""" node = Node(driver.client, deepcopy(invalid_multilevel_sensor_type_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="endpoints_with_command_classes") def endpoints_with_command_classes_fixture( driver, endpoints_with_command_classes_state ): """Mock a node with command classes on an endpoint.""" node = Node(driver.client, deepcopy(endpoints_with_command_classes_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="switch_enbrighten_zw3010") def switch_enbrighten_zw3010_fixture(driver, switch_enbrighten_zw3010_state): """Mock an Enbrighten ZW3010 switch node.""" node = Node(driver.client, deepcopy(switch_enbrighten_zw3010_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="energy_production") def energy_prodution_fixture(driver, energy_production_state): """Mock a mock node with Energy Production CC.""" node = Node(driver.client, deepcopy(energy_production_state)) driver.controller.nodes[node.node_id] = node return node @pytest.fixture(name="lock_ultraloq_ubolt_pro") def lock_ultraloq_ubolt_pro_fixture(driver, lock_ultraloq_ubolt_pro_state): """Mock an Ultraloq U-Bolt Pro lock node.""" node = Node(driver.client, deepcopy(lock_ultraloq_ubolt_pro_state)) driver.controller.nodes[node.node_id] = node return node zwave-js-server-python-0.63.0/test/const/000077500000000000000000000000001500374325600203035ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/const/__init__.py000066400000000000000000000000321500374325600224070ustar00rootroot00000000000000"""Test the constants.""" zwave-js-server-python-0.63.0/test/const/command_class/000077500000000000000000000000001500374325600231065ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/const/command_class/__init__.py000066400000000000000000000000501500374325600252120ustar00rootroot00000000000000"""Test the command class constants.""" zwave-js-server-python-0.63.0/test/const/command_class/test_multilevel_sensor.py000066400000000000000000000011631500374325600302730ustar00rootroot00000000000000"""Test the multilevel sensor command class constants.""" from zwave_js_server.const.command_class.multilevel_sensor import ( UNIT_ABSOLUTE_HUMIDITY, UNIT_HERTZ, UNIT_KILOGRAM, UNIT_MOLE_PER_CUBIC_METER, UNIT_PERCENTAGE_VALUE, ) def test_multilevel_sensor_constants(): """Test some of the multilevel sensor command class constants. Ensure that the enums are not overwriting each other. """ assert len(UNIT_ABSOLUTE_HUMIDITY) == 1 assert len(UNIT_HERTZ) == 2 assert len(UNIT_KILOGRAM) == 2 assert len(UNIT_MOLE_PER_CUBIC_METER) == 7 assert len(UNIT_PERCENTAGE_VALUE) == 6 zwave-js-server-python-0.63.0/test/fixtures/000077500000000000000000000000001500374325600210265ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/fixtures/basic_dump.txt000066400000000000000000003100771500374325600237050ustar00rootroot00000000000000{"type":"result","success":true,"messageId":"start-listening-result","result":{"state":{"controller":{"sdkVersion":"Z-Wave 3.95","isRebuildingRoutes":false,"type":1,"homeId":3601639587,"ownNodeId":1,"isPrimary":true,"isUsingHomeIdFromOtherNetwork":false,"isSISPresent":true,"wasRealPrimary":true,"isSUC":true,"nodeType":0,"firmwareVersion":"1.0","manufacturerId":134,"productType":257,"productId":90,"supportedFunctionTypes":[2,3,4,5,6,7,8,9,16,17,18,19,20,21,22,23,24,28,32,33,34,35,36,39,41,42,43,44,45,65,66,68,69,70,71,72,73,74,75,76,77,80,81,83,84,85,86,87,94,96,97,98,99,102,103,128,144,146,147,152,180,182,183,184,185,186,189,190,191,210,211,212,238,239],"sucNodeId":1,"supportsTimers":false,"inclusionState": 0},"nodes":[{"nodeId":1,"index":0,"status":4,"ready":true,"isListening":true,"isRouting":false,"isSecure":false,"manufacturerId":134,"productId":90,"productType":257,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0086/zw090.json","manufacturer":"AEON Labs","manufacturerId":134,"label":"ZW090","description":"Z‐Stick Gen5 USB Controller","devices":[{"productType":1,"productId":90},{"productType":257,"productId":90},{"productType":513,"productId":90}],"firmwareVersion":{"min":"0.0","max":"255.255"},"associations":{},"paramInformation":{"_map":{}},"metadata":{"reset":"Use this procedure only in the event that the primary controller is missing or otherwise inoperable.\n\nPress and hold the Action Button on Z-Stick for 20 seconds and then release","manual":"https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/1355/Z%20Stick%20Gen5%20manual%201.pdf"}},"label":"ZW090","neighbors":[23,26,5,6],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":1,"index":0,"deviceClass":{"basic":{"key":2,"label":"Static Controller"},"generic":{"key":2,"label":"Static Controller"},"specific":{"key":1,"label":"PC Controller"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[32]},"commandClasses":[]}],"values":[],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":0,"deviceClass":{"basic":{"key":2,"label":"Static Controller"},"generic":{"key":2,"label":"Static Controller"},"specific":{"key":1,"label":"PC Controller"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[32]},"isControllerNode":false,"keepAwake":false},{"nodeId":2,"index":0,"installerIcon":1536,"userIcon":1536,"status":4,"ready":true,"isListening":true,"isRouting":true,"isSecure":false,"manufacturerId":99,"productId":12344,"productType":18756,"firmwareVersion":"5.26","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0063/ge_14294_zw3005.json","manufacturer":"GE/Jasco","manufacturerId":99,"label":"14294 / ZW3005","description":"In-Wall Dimmer Switch","devices":[{"productType":18756,"productId":12344}],"firmwareVersion":{"min":"0.0","max":"255.255"},"associations":{},"paramInformation":{"_map":{}},"compat":{"valueIdRegex":{},"treatBasicSetAsEvent":true}},"label":"14294 / ZW3005","neighbors":[23,26,3,4,5,6],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":2,"index":0,"installerIcon":1536,"userIcon":1536,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"currentValue","propertyName":"currentValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99}},{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"targetValue","propertyName":"targetValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"targetValue","propertyName":"targetValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"duration","propertyName":"duration","ccVersion":2,"metadata":{"type":"duration","readable":true,"writeable":true,"label":"Transition duration"}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"currentValue","propertyName":"currentValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99},"value":99},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Up","propertyName":"Up","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Up)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Down","propertyName":"Down","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Down)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"sceneId","propertyName":"sceneId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Scene ID","min":1,"max":255}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"dimmingDuration","propertyName":"dimmingDuration","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":true,"label":"Dimming duration"}},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Night Light","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Defines the behavior of the blue LED. Default is on when switch is off.","label":"Night Light","min":0,"max":2,"states":{"0":"LED on when switch is OFF","1":"LED on when switch is ON","2":"LED always off"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Invert Switch","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Invert the ON/OFF Switch State.","label":"Invert Switch","min":0,"max":1,"states":{"0":"No","1":"Yes"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"Dim Rate Steps (Z-Wave Command)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Z-Wave Command)","min":0,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":8,"propertyName":"Dim Rate Timing (Z-Wave)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (Z-Wave)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":9,"propertyName":"Dim Rate Steps (Manual)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Manual)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":10,"propertyName":"Dim Rate Timing (Manual)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps","label":"Dim Rate Timing (Manual)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":11,"propertyName":"Dim Rate Steps (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (All-On/All-Off)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":12,"propertyName":"Dim Rate Timing (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (All-On/All-Off)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":99},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":18756},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":12344},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.34"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["5.26"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":5,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]},"commandClasses":[{"id":32,"name":"Basic","version":1,"isSecure":false},{"id":38,"name":"Multilevel Switch","version":2,"isSecure":false},{"id":43,"name":"Scene Activation","version":1,"isSecure":false},{"id":44,"name":"Scene Actuator Configuration","version":1,"isSecure":false},{"id":86,"name":"CRC-16 Encapsulation","version":1,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false}]},{"nodeId":3,"index":0,"installerIcon":1536,"userIcon":1536,"status":4,"ready":true,"isListening":true,"isRouting":true,"isSecure":false,"manufacturerId":99,"productId":12344,"productType":18756,"firmwareVersion":"5.26","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0063/ge_14294_zw3005.json","manufacturer":"GE/Jasco","manufacturerId":99,"label":"14294 / ZW3005","description":"In-Wall Dimmer Switch","devices":[{"productType":18756,"productId":12344}],"firmwareVersion":{"min":"0.0","max":"255.255"},"associations":{},"paramInformation":{"_map":{}},"compat":{"valueIdRegex":{},"treatBasicSetAsEvent":true}},"label":"14294 / ZW3005","neighbors":[2,23,26,4,5],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":3,"index":0,"installerIcon":1536,"userIcon":1536,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"currentValue","propertyName":"currentValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99}},{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"targetValue","propertyName":"targetValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"targetValue","propertyName":"targetValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"duration","propertyName":"duration","ccVersion":2,"metadata":{"type":"duration","readable":true,"writeable":true,"label":"Transition duration"}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"currentValue","propertyName":"currentValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99},"value":99},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Up","propertyName":"Up","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Up)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Down","propertyName":"Down","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Down)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"sceneId","propertyName":"sceneId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Scene ID","min":1,"max":255}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"dimmingDuration","propertyName":"dimmingDuration","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":true,"label":"Dimming duration"}},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Night Light","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Defines the behavior of the blue LED. Default is on when switch is off.","label":"Night Light","min":0,"max":2,"states":{"0":"LED on when switch is OFF","1":"LED on when switch is ON","2":"LED always off"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Invert Switch","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Invert the ON/OFF Switch State.","label":"Invert Switch","min":0,"max":1,"states":{"0":"No","1":"Yes"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"Dim Rate Steps (Z-Wave Command)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Z-Wave Command)","min":0,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":8,"propertyName":"Dim Rate Timing (Z-Wave)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (Z-Wave)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":9,"propertyName":"Dim Rate Steps (Manual)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Manual)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":10,"propertyName":"Dim Rate Timing (Manual)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps","label":"Dim Rate Timing (Manual)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":11,"propertyName":"Dim Rate Steps (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (All-On/All-Off)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":12,"propertyName":"Dim Rate Timing (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (All-On/All-Off)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":99},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":18756},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":12344},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.34"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["5.26"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":5,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]},"commandClasses":[{"id":32,"name":"Basic","version":1,"isSecure":false},{"id":38,"name":"Multilevel Switch","version":2,"isSecure":false},{"id":43,"name":"Scene Activation","version":1,"isSecure":false},{"id":44,"name":"Scene Actuator Configuration","version":1,"isSecure":false},{"id":86,"name":"CRC-16 Encapsulation","version":1,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false}]},{"nodeId":4,"index":0,"installerIcon":1536,"userIcon":1536,"status":4,"ready":true,"isListening":true,"isRouting":true,"isSecure":false,"manufacturerId":99,"productId":12344,"productType":18756,"firmwareVersion":"5.26","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0063/ge_14294_zw3005.json","manufacturer":"GE/Jasco","manufacturerId":99,"label":"14294 / ZW3005","description":"In-Wall Dimmer Switch","devices":[{"productType":18756,"productId":12344}],"firmwareVersion":{"min":"0.0","max":"255.255"},"associations":{},"paramInformation":{"_map":{}},"compat":{"valueIdRegex":{},"treatBasicSetAsEvent":true}},"label":"14294 / ZW3005","neighbors":[2,23,26,3,5,6],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":4,"index":0,"installerIcon":1536,"userIcon":1536,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"currentValue","propertyName":"currentValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99}},{"endpoint":0,"commandClass":32,"commandClassName":"Basic","property":"targetValue","propertyName":"targetValue","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"targetValue","propertyName":"targetValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"duration","propertyName":"duration","ccVersion":2,"metadata":{"type":"duration","readable":true,"writeable":true,"label":"Transition duration"}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"currentValue","propertyName":"currentValue","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99},"value":99},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Up","propertyName":"Up","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Up)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":38,"commandClassName":"Multilevel Switch","property":"Down","propertyName":"Down","ccVersion":2,"metadata":{"type":"boolean","readable":true,"writeable":true,"label":"Perform a level change (Down)","ccSpecific":{"switchType":2}}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"sceneId","propertyName":"sceneId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Scene ID","min":1,"max":255}},{"endpoint":0,"commandClass":43,"commandClassName":"Scene Activation","property":"dimmingDuration","propertyName":"dimmingDuration","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":true,"label":"Dimming duration"}},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Night Light","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Defines the behavior of the blue LED. Default is on when switch is off.","label":"Night Light","min":0,"max":2,"states":{"0":"LED on when switch is OFF","1":"LED on when switch is ON","2":"LED always off"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Invert Switch","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Invert the ON/OFF Switch State.","label":"Invert Switch","min":0,"max":1,"states":{"0":"No","1":"Yes"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"Dim Rate Steps (Z-Wave Command)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Z-Wave Command)","min":0,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":8,"propertyName":"Dim Rate Timing (Z-Wave)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (Z-Wave)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":9,"propertyName":"Dim Rate Steps (Manual)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (Manual)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":10,"propertyName":"Dim Rate Timing (Manual)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps","label":"Dim Rate Timing (Manual)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":11,"propertyName":"Dim Rate Steps (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Number of steps or levels","label":"Dim Rate Steps (All-On/All-Off)","min":1,"max":99},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":12,"propertyName":"Dim Rate Timing (All-On/All-Off)","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"description":"Timing of steps or levels","label":"Dim Rate Timing (All-On/All-Off)","min":1,"max":255,"unit":"10ms"},"value":3},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":99},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":18756},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":12344},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.34"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["5.26"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":5,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":17,"label":"Multilevel Switch"},"specific":{"key":1,"label":"Multilevel Power Switch"},"mandatorySupportedCCs":[32,38,39],"mandatoryControlledCCs":[]},"commandClasses":[{"id":32,"name":"Basic","version":1,"isSecure":false},{"id":38,"name":"Multilevel Switch","version":2,"isSecure":false},{"id":43,"name":"Scene Activation","version":1,"isSecure":false},{"id":44,"name":"Scene Actuator Configuration","version":1,"isSecure":false},{"id":86,"name":"CRC-16 Encapsulation","version":1,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false}]},{"nodeId":5,"index":0,"installerIcon":3079,"userIcon":3079,"status":1,"ready":true,"isListening":false,"isRouting":true,"isSecure":false,"manufacturerId":265,"productId":8449,"productType":8225,"firmwareVersion":"5.1","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0109/zse40.json","manufacturer":"Vision Security","manufacturerId":265,"label":"ZSE40","description":"Zooz 4-in-one motion/temperature/humidity/luminance sensor","devices":[{"productType":8225,"productId":8449}],"firmwareVersion":{"min":"0.0","max":"255.255"},"paramInformation":{"_map":{}},"metadata":{"inclusion":"To add the ZP3111 to the Z-Wave network (inclusion), place the Z-Wave primary controller into inclusion mode. Press the Program Switch of ZP3111 for sending the NIF. After sending NIF, Z-Wave will send the auto inclusion, otherwise, ZP3111 will go to sleep after 20 seconds.","exclusion":"To remove the ZP3111 from the Z-Wave network (exclusion), place the Z-Wave primary controller into “exclusion” mode, and following its instruction to delete the ZP3111 to the controller. Press the Program Switch of ZP3111 once to be excluded.","reset":"Remove cover to trigged tamper switch, LED flash once & send out Alarm Report. Press Program Switch 10 times within 10 seconds, ZP3111 will send the “Device Reset Locally Notification” command and reset to the factory default. (Remark: This is to be used only in the case of primary controller being inoperable or otherwise unavailable.)","manual":"https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf"}},"label":"ZSE40","neighbors":[1,2,3,4],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":5,"index":0,"installerIcon":3079,"userIcon":3079,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":7,"label":"Notification Sensor"},"specific":{"key":1,"label":"Notification Sensor"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Air temperature","propertyName":"Air temperature","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Air temperature","ccSpecific":{"sensorType":1,"scale":1},"unit":"°F"},"value":68.42},{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Illuminance","propertyName":"Illuminance","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Illuminance","ccSpecific":{"sensorType":3,"scale":0},"unit":"%"},"value":20.03},{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Humidity","propertyName":"Humidity","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Humidity","ccSpecific":{"sensorType":5,"scale":0},"unit":"%"},"value":43.53},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":1,"propertyName":"Temperature Scale","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Temperature Scale","min":0,"max":1,"states":{"0":"Celsius","1":"Fahrenheit"}},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":2,"propertyName":"Temperature offset","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"label":"Temperature offset","min":0,"max":50},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Humidity","ccVersion":1,"metadata":{"type":"number","default":10,"readable":true,"writeable":true,"description":"Configure Relative Humidity","label":"Humidity","min":1,"max":50,"unit":"percent"},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Light Sensor","ccVersion":1,"metadata":{"type":"number","default":10,"readable":true,"writeable":true,"label":"Light Sensor","min":1,"max":50,"unit":"percent"},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":5,"propertyName":"Trigger Interval","ccVersion":1,"metadata":{"type":"number","default":180,"readable":true,"writeable":true,"description":"Set the trigger interval for motion sensor re-activation.","label":"Trigger Interval","min":1,"max":255,"unit":"seconds"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":6,"propertyName":"Motion Sensor Sensitivity","ccVersion":1,"metadata":{"type":"number","default":4,"readable":true,"writeable":true,"description":"Adjust sensitivity of the motion sensor.","label":"Motion Sensor Sensitivity","min":1,"max":7,"states":{"1":"highest","2":"higher","3":"high","4":"normal","5":"low","6":"lower","7":"lowest"}},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"LED indicator mode","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"label":"LED indicator mode","min":1,"max":3,"states":{"1":"Off","2":"Pulsing Temperature, Flashing Motion","3":"Flashing Temperature and Motion"}},"value":1},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Home Security","propertyKey":"Motion sensor status","propertyName":"Home Security","propertyKeyName":"Motion sensor status","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Motion sensor status","ccSpecific":{"notificationType":7},"min":0,"max":255,"states":{"0":"idle","8":"Motion detection"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Home Security","propertyKey":"Cover status","propertyName":"Home Security","propertyKeyName":"Cover status","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Cover status","ccSpecific":{"notificationType":7},"min":0,"max":255,"states":{"0":"idle","3":"Tampering, product cover removed"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"alarmType","propertyName":"alarmType","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Alarm Type","min":0,"max":255}},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"alarmLevel","propertyName":"alarmLevel","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Alarm Level","min":0,"max":255}},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":265},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":8225},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":8449},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"level","propertyName":"level","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Battery level","min":0,"max":100,"unit":"%"},"value":50},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"isLow","propertyName":"isLow","ccVersion":1,"metadata":{"type":"boolean","readable":true,"writeable":false,"label":"Low battery level"},"value":false},{"endpoint":0,"commandClass":132,"commandClassName":"Wake Up","property":"wakeUpInterval","propertyName":"wakeUpInterval","ccVersion":1,"metadata":{"type":"number","default":3600,"readable":false,"writeable":true,"label":"Wake Up interval","min":600,"max":604800,"steps":600},"value":3600},{"endpoint":0,"commandClass":132,"commandClassName":"Wake Up","property":"controllerNodeId","propertyName":"controllerNodeId","ccVersion":1,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Node ID of the controller"},"value":1},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.5"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["5.1"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":6,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":7,"label":"Notification Sensor"},"specific":{"key":1,"label":"Notification Sensor"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[]},"commandClasses":[{"id":49,"name":"Multilevel Sensor","version":7,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":113,"name":"Notification","version":4,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":128,"name":"Battery","version":1,"isSecure":false},{"id":132,"name":"Wake Up","version":1,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false}]},{"nodeId":6,"index":0,"installerIcon":3079,"userIcon":3079,"status":1,"ready":true,"isListening":false,"isRouting":true,"isSecure":false,"manufacturerId":265,"productId":8449,"productType":8225,"firmwareVersion":"5.1","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0109/zse40.json","manufacturer":"Vision Security","manufacturerId":265,"label":"ZSE40","description":"Zooz 4-in-one motion/temperature/humidity/luminance sensor","devices":[{"productType":8225,"productId":8449}],"firmwareVersion":{"min":"0.0","max":"255.255"},"paramInformation":{"_map":{}},"metadata":{"inclusion":"To add the ZP3111 to the Z-Wave network (inclusion), place the Z-Wave primary controller into inclusion mode. Press the Program Switch of ZP3111 for sending the NIF. After sending NIF, Z-Wave will send the auto inclusion, otherwise, ZP3111 will go to sleep after 20 seconds.","exclusion":"To remove the ZP3111 from the Z-Wave network (exclusion), place the Z-Wave primary controller into “exclusion” mode, and following its instruction to delete the ZP3111 to the controller. Press the Program Switch of ZP3111 once to be excluded.","reset":"Remove cover to trigged tamper switch, LED flash once & send out Alarm Report. Press Program Switch 10 times within 10 seconds, ZP3111 will send the “Device Reset Locally Notification” command and reset to the factory default. (Remark: This is to be used only in the case of primary controller being inoperable or otherwise unavailable.)","manual":"https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf"}},"label":"ZSE40","neighbors":[1,2,4],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":6,"index":0,"installerIcon":3079,"userIcon":3079,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":7,"label":"Notification Sensor"},"specific":{"key":1,"label":"Notification Sensor"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Air temperature","propertyName":"Air temperature","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Air temperature","ccSpecific":{"sensorType":1,"scale":1},"unit":"°F"},"value":69.36},{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Illuminance","propertyName":"Illuminance","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Illuminance","ccSpecific":{"sensorType":3,"scale":0},"unit":"%"},"value":19.51},{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Humidity","propertyName":"Humidity","ccVersion":7,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Humidity","ccSpecific":{"sensorType":5,"scale":0},"unit":"%"},"value":42.24},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":1,"propertyName":"Temperature Scale","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Temperature Scale","min":0,"max":1,"states":{"0":"Celsius","1":"Fahrenheit"}},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":2,"propertyName":"Temperature offset","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"label":"Temperature offset","min":0,"max":50},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Humidity","ccVersion":1,"metadata":{"type":"number","default":10,"readable":true,"writeable":true,"description":"Configure Relative Humidity","label":"Humidity","min":1,"max":50,"unit":"percent"},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Light Sensor","ccVersion":1,"metadata":{"type":"number","default":10,"readable":true,"writeable":true,"label":"Light Sensor","min":1,"max":50,"unit":"percent"},"value":10},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":5,"propertyName":"Trigger Interval","ccVersion":1,"metadata":{"type":"number","default":180,"readable":true,"writeable":true,"description":"Set the trigger interval for motion sensor re-activation.","label":"Trigger Interval","min":1,"max":255,"unit":"seconds"},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":6,"propertyName":"Motion Sensor Sensitivity","ccVersion":1,"metadata":{"type":"number","default":4,"readable":true,"writeable":true,"description":"Adjust sensitivity of the motion sensor.","label":"Motion Sensor Sensitivity","min":1,"max":7,"states":{"1":"highest","2":"higher","3":"high","4":"normal","5":"low","6":"lower","7":"lowest"}},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"LED indicator mode","ccVersion":1,"metadata":{"type":"number","default":3,"readable":true,"writeable":true,"label":"LED indicator mode","min":1,"max":3,"states":{"1":"Off","2":"Pulsing Temperature, Flashing Motion","3":"Flashing Temperature and Motion"}},"value":1},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Home Security","propertyKey":"Motion sensor status","propertyName":"Home Security","propertyKeyName":"Motion sensor status","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Motion sensor status","ccSpecific":{"notificationType":7},"min":0,"max":255,"states":{"0":"idle","8":"Motion detection"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Home Security","propertyKey":"Cover status","propertyName":"Home Security","propertyKeyName":"Cover status","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Cover status","ccSpecific":{"notificationType":7},"min":0,"max":255,"states":{"0":"idle","3":"Tampering, product cover removed"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"alarmType","propertyName":"alarmType","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Alarm Type","min":0,"max":255}},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"alarmLevel","propertyName":"alarmLevel","ccVersion":4,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Alarm Level","min":0,"max":255}},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":265},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":8225},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":8449},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"level","propertyName":"level","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Battery level","min":0,"max":100,"unit":"%"},"value":80},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"isLow","propertyName":"isLow","ccVersion":1,"metadata":{"type":"boolean","readable":true,"writeable":false,"label":"Low battery level"},"value":false},{"endpoint":0,"commandClass":132,"commandClassName":"Wake Up","property":"wakeUpInterval","propertyName":"wakeUpInterval","ccVersion":1,"metadata":{"type":"number","default":3600,"readable":false,"writeable":true,"label":"Wake Up interval","min":600,"max":604800,"steps":600},"value":3600},{"endpoint":0,"commandClass":132,"commandClassName":"Wake Up","property":"controllerNodeId","propertyName":"controllerNodeId","ccVersion":1,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Node ID of the controller"},"value":1},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.5"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["5.1"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":6,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":7,"label":"Notification Sensor"},"specific":{"key":1,"label":"Notification Sensor"},"mandatorySupportedCCs":[],"mandatoryControlledCCs":[]},"commandClasses":[{"id":49,"name":"Multilevel Sensor","version":7,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":113,"name":"Notification","version":4,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":128,"name":"Battery","version":1,"isSecure":false},{"id":132,"name":"Wake Up","version":1,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false}]},{"nodeId":23,"index":0,"status":4,"ready":true,"isListening":false,"isRouting":true,"isSecure":true,"manufacturerId":59,"productId":20548,"productType":25409,"firmwareVersion":"113.22","deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x003b/be469.json","manufacturer":"Allegion","manufacturerId":59,"label":"BE469","description":"Touchscreen Deadbolt","devices":[{"productType":25409,"productId":20548}],"firmwareVersion":{"min":"0.0","max":"255.255"},"associations":{},"paramInformation":{"_map":{}}},"label":"BE469","neighbors":[1,2,26,3,4],"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":23,"index":0,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":64,"label":"Entry Control"},"specific":{"key":3,"label":"Secure Keypad Door Lock"},"mandatorySupportedCCs":[32,98,99,114,152,134],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"currentMode","propertyName":"currentMode","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current lock mode","min":0,"max":255,"states":{"0":"Unsecured","1":"UnsecuredWithTimeout","16":"InsideUnsecured","17":"InsideUnsecuredWithTimeout","32":"OutsideUnsecured","33":"OutsideUnsecuredWithTimeout","254":"Unknown","255":"Secured"}},"value":0},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"targetMode","propertyName":"targetMode","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target lock mode","min":0,"max":255,"states":{"0":"Unsecured","1":"UnsecuredWithTimeout","16":"InsideUnsecured","17":"InsideUnsecuredWithTimeout","32":"OutsideUnsecured","33":"OutsideUnsecuredWithTimeout","254":"Unknown","255":"Secured"}}},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"outsideHandlesCanOpenDoor","propertyName":"outsideHandlesCanOpenDoor","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Which outside handles can open the door (actual status)"},"value":[false,false,false,false]},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"insideHandlesCanOpenDoor","propertyName":"insideHandlesCanOpenDoor","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Which inside handles can open the door (actual status)"},"value":[false,false,false,false]},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"latchStatus","propertyName":"latchStatus","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"The current status of the latch"},"value":"open"},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"boltStatus","propertyName":"boltStatus","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"The current status of the bolt"},"value":"locked"},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"doorStatus","propertyName":"doorStatus","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"The current status of the door"},"value":"open"},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"lockTimeout","propertyName":"lockTimeout","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Seconds until lock mode times out"}},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"operationType","propertyName":"operationType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Lock operation type","min":0,"max":255,"states":{"1":"Constant","2":"Timed"}},"value":1},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"outsideHandlesCanOpenDoorConfiguration","propertyName":"outsideHandlesCanOpenDoorConfiguration","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":true,"label":"Which outside handles can open the door (configuration)"},"value":[false,false,false,false]},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"insideHandlesCanOpenDoorConfiguration","propertyName":"insideHandlesCanOpenDoorConfiguration","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":true,"label":"Which inside handles can open the door (configuration)"},"value":[false,false,false,false]},{"endpoint":0,"commandClass":98,"commandClassName":"Door Lock","property":"lockTimeoutConfiguration","propertyName":"lockTimeoutConfiguration","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Duration of timed mode in seconds","min":0,"max":65535}},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":1,"propertyName":"userIdStatus","propertyKeyName":"1","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (1)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":1},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":1,"propertyName":"userCode","propertyKeyName":"1","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (1)","minLength":4,"maxLength":10},"value":"**********"},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":2,"propertyName":"userIdStatus","propertyKeyName":"2","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (2)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":1},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":2,"propertyName":"userCode","propertyKeyName":"2","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (2)","minLength":4,"maxLength":10},"value":"**********"},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":3,"propertyName":"userIdStatus","propertyKeyName":"3","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (3)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":1},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":3,"propertyName":"userCode","propertyKeyName":"3","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (3)","minLength":4,"maxLength":10},"value":"**********"},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":4,"propertyName":"userIdStatus","propertyKeyName":"4","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (4)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":4,"propertyName":"userCode","propertyKeyName":"4","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (4)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":5,"propertyName":"userIdStatus","propertyKeyName":"5","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (5)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":5,"propertyName":"userCode","propertyKeyName":"5","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (5)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":6,"propertyName":"userIdStatus","propertyKeyName":"6","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (6)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":6,"propertyName":"userCode","propertyKeyName":"6","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (6)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":7,"propertyName":"userIdStatus","propertyKeyName":"7","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (7)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":7,"propertyName":"userCode","propertyKeyName":"7","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (7)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":8,"propertyName":"userIdStatus","propertyKeyName":"8","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (8)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":8,"propertyName":"userCode","propertyKeyName":"8","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (8)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":9,"propertyName":"userIdStatus","propertyKeyName":"9","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (9)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":9,"propertyName":"userCode","propertyKeyName":"9","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (9)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":10,"propertyName":"userIdStatus","propertyKeyName":"10","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (10)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":10,"propertyName":"userCode","propertyKeyName":"10","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (10)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":11,"propertyName":"userIdStatus","propertyKeyName":"11","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (11)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":11,"propertyName":"userCode","propertyKeyName":"11","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (11)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":12,"propertyName":"userIdStatus","propertyKeyName":"12","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (12)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":12,"propertyName":"userCode","propertyKeyName":"12","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (12)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":13,"propertyName":"userIdStatus","propertyKeyName":"13","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (13)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":13,"propertyName":"userCode","propertyKeyName":"13","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (13)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":14,"propertyName":"userIdStatus","propertyKeyName":"14","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (14)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":14,"propertyName":"userCode","propertyKeyName":"14","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (14)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":15,"propertyName":"userIdStatus","propertyKeyName":"15","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (15)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":15,"propertyName":"userCode","propertyKeyName":"15","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (15)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":16,"propertyName":"userIdStatus","propertyKeyName":"16","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (16)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":16,"propertyName":"userCode","propertyKeyName":"16","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (16)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":17,"propertyName":"userIdStatus","propertyKeyName":"17","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (17)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":17,"propertyName":"userCode","propertyKeyName":"17","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (17)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":18,"propertyName":"userIdStatus","propertyKeyName":"18","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (18)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":18,"propertyName":"userCode","propertyKeyName":"18","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (18)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":19,"propertyName":"userIdStatus","propertyKeyName":"19","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (19)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":19,"propertyName":"userCode","propertyKeyName":"19","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (19)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":20,"propertyName":"userIdStatus","propertyKeyName":"20","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (20)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":20,"propertyName":"userCode","propertyKeyName":"20","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (20)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":21,"propertyName":"userIdStatus","propertyKeyName":"21","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (21)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":21,"propertyName":"userCode","propertyKeyName":"21","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (21)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":22,"propertyName":"userIdStatus","propertyKeyName":"22","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (22)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":22,"propertyName":"userCode","propertyKeyName":"22","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (22)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":23,"propertyName":"userIdStatus","propertyKeyName":"23","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (23)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":23,"propertyName":"userCode","propertyKeyName":"23","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (23)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":24,"propertyName":"userIdStatus","propertyKeyName":"24","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (24)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":24,"propertyName":"userCode","propertyKeyName":"24","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (24)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":25,"propertyName":"userIdStatus","propertyKeyName":"25","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (25)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":25,"propertyName":"userCode","propertyKeyName":"25","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (25)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":26,"propertyName":"userIdStatus","propertyKeyName":"26","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (26)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":26,"propertyName":"userCode","propertyKeyName":"26","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (26)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":27,"propertyName":"userIdStatus","propertyKeyName":"27","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (27)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":27,"propertyName":"userCode","propertyKeyName":"27","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (27)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":28,"propertyName":"userIdStatus","propertyKeyName":"28","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (28)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":28,"propertyName":"userCode","propertyKeyName":"28","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (28)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":29,"propertyName":"userIdStatus","propertyKeyName":"29","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (29)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":29,"propertyName":"userCode","propertyKeyName":"29","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (29)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userIdStatus","propertyKey":30,"propertyName":"userIdStatus","propertyKeyName":"30","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"User ID status (30)","states":{"0":"Available","1":"Enabled","2":"Disabled"}},"value":0},{"endpoint":0,"commandClass":99,"commandClassName":"User Code","property":"userCode","propertyKey":30,"propertyName":"userCode","propertyKeyName":"30","ccVersion":1,"metadata":{"type":"string","readable":true,"writeable":true,"label":"User Code (30)","minLength":4,"maxLength":10},"value":""},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Beeper","ccVersion":1,"metadata":{"type":"number","default":255,"readable":true,"writeable":true,"label":"Beeper","min":0,"max":255,"states":{"0":"Disable Beeper","255":"Enable Beeper"}},"value":255},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Vacation Mode","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Vacation Mode","min":0,"max":255,"states":{"0":"Disable Vacation Mode","255":"Enable Vacation Mode"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":5,"propertyName":"Lock & Leave","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Lock & Leave","min":0,"max":255,"states":{"0":"Disable Lock & Leave","255":"Enable Lock & Leave"}},"value":255},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":6,"propertyName":"User Slot Status","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"label":"User Slot Status","min":0,"max":255},"value":117440512},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"Lock Specific Alarm Mode","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"BE469 Only","label":"Lock Specific Alarm Mode","min":0,"max":3,"states":{"0":"Alarm Off","1":"Alert","2":"Tamper","3":"Forced Entry"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":8,"propertyName":"Lock Specific Alarm Alert Sensitivity","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Lock Specific Alarm Alert Sensitivity","min":0,"max":5,"states":{"0":"Not Supported","1":"Most Sensitive","2":"More Sensitive","3":"Medium Sensitivity","4":"Less Sensitive","5":"Least Sensitive"}},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":9,"propertyName":"Lock Specific Alarm Tamper Sensitivity","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Lock Specific Alarm Tamper Sensitivity","min":0,"max":5,"states":{"0":"Not Supported","1":"Most Sensitive","2":"More Sensitive","3":"Medium Sensitivity","4":"Less Sensitive","5":"Least Sensitive"}},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":10,"propertyName":"Lock Specific Alarm Kick Sensitivity","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"BE469 Only","label":"Lock Specific Alarm Kick Sensitivity","min":0,"max":5,"states":{"0":"Not Supported","1":"Most Sensitive","2":"More Sensitive","3":"Medium Sensitivity","4":"Less Sensitive","5":"Least Sensitive"}},"value":3},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":11,"propertyName":"Lock Specific Alarm Disable—Local Controls","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Lock Specific Alarm Disable—Local Controls","min":0,"max":255,"states":{"0":"Disable Local Control","255":"Enable Local Control"}},"value":255},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":12,"propertyName":"Electronic Transition Count","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"label":"Electronic Transition Count","min":0,"max":2147483647},"value":2406},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":13,"propertyName":"Mechanical Transition Count","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"label":"Mechanical Transition Count","min":0,"max":2147483647},"value":2336},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":14,"propertyName":"Electronic Failed Count","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"label":"Electronic Failed Count","min":0,"max":2147483647},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":15,"propertyName":"Auto Lock","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"label":"Auto Lock","min":0,"max":255,"states":{"0":"Disable Auto Lock","255":"Enable Auto Lock"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":16,"propertyName":"User Code PIN Length","ccVersion":1,"metadata":{"type":"number","default":4,"readable":true,"writeable":true,"description":"User Code PIN length, a value between 4 and 8 (default 4)","label":"User Code PIN Length","min":4,"max":8,"states":{"4":"Four Digits","5":"Five Digits","6":"Six Digits","7":"Seven Digits","8":"Eight Digits"}},"value":4},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":18,"propertyName":"Get Bootloader Version","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"label":"Get Bootloader Version","min":0,"max":255},"value":1},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Access Control","propertyKey":"Lock state","propertyName":"Access Control","propertyKeyName":"Lock state","ccVersion":3,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Lock state","ccSpecific":{"notificationType":6},"min":0,"max":255,"states":{"0":"idle","11":"Lock jammed"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Access Control","propertyKey":"Keypad state","propertyName":"Access Control","propertyKeyName":"Keypad state","ccVersion":3,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Keypad state","ccSpecific":{"notificationType":6},"min":0,"max":255,"states":{"0":"idle","16":"Keypad temporary disabled"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Home Security","propertyKey":"Sensor status","propertyName":"Home Security","propertyKeyName":"Sensor status","ccVersion":3,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Sensor status","ccSpecific":{"notificationType":7},"min":0,"max":255,"states":{"0":"idle","2":"Intrusion"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"Power Management","propertyKey":"Battery maintenance status","propertyName":"Power Management","propertyKeyName":"Battery maintenance status","ccVersion":3,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Battery maintenance status","ccSpecific":{"notificationType":8},"min":0,"max":255,"states":{"0":"idle","10":"Replace battery soon","11":"Replace battery now"}},"value":0},{"endpoint":0,"commandClass":113,"commandClassName":"Notification","property":"System","propertyKey":"Hardware status","propertyName":"System","propertyKeyName":"Hardware status","ccVersion":3,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Hardware status","ccSpecific":{"notificationType":9},"min":0,"max":255,"states":{"0":"idle","1":"System hardware failure"}},"value":0},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":59},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":25409},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":20548},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"level","propertyName":"level","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Battery level","min":0,"max":100,"unit":"%"},"value":97},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"isLow","propertyName":"isLow","ccVersion":1,"metadata":{"type":"boolean","readable":true,"writeable":false,"label":"Low battery level"},"value":false},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":1,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":6},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":1,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"3.42"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":1,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["113.22"]}],"isFrequentListening":"1000ms","maxDataRate":40000,"supportedDataRates":[40000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":64,"label":"Entry Control"},"specific":{"key":3,"label":"Secure Keypad Door Lock"},"mandatorySupportedCCs":[32,98,99,114,152,134],"mandatoryControlledCCs":[]},"commandClasses":[{"id":98,"name":"Door Lock","version":2,"isSecure":true},{"id":99,"name":"User Code","version":1,"isSecure":true},{"id":112,"name":"Configuration","version":1,"isSecure":true},{"id":113,"name":"Notification","version":3,"isSecure":true},{"id":114,"name":"Manufacturer Specific","version":1,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":2,"isSecure":false},{"id":128,"name":"Battery","version":1,"isSecure":true},{"id":133,"name":"Association","version":1,"isSecure":true},{"id":134,"name":"Version","version":1,"isSecure":false},{"id":152,"name":"Security","version":1,"isSecure":true}]},{"nodeId":26,"index":0,"installerIcon":4608,"userIcon":4608,"status":4,"ready":true,"isListening":true,"isRouting":true,"isSecure":false,"manufacturerId":152,"productId":256,"productType":25602,"firmwareVersion":"10.7","zwavePlusVersion":1,"deviceConfig":{"filename":"/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0098/ct100_plus.json","manufacturer":"Radio Thermostat Company of America (RTC)","manufacturerId":152,"label":"CT100 Plus","description":"Z-Wave Thermostat","devices":[{"productType":25602,"productId":256}],"firmwareVersion":{"min":"0.0","max":"255.255"},"paramInformation":{"_map":{}}},"label":"CT100 Plus","neighbors":[1,2,23,3,4],"endpointCountIsDynamic":false,"endpointsHaveIdenticalCapabilities":false,"individualEndpointCount":2,"aggregatedEndpointCount":0,"interviewAttempts":0,"interviewStage":"Neighbors","endpoints":[{"nodeId":26,"index":0,"installerIcon":4608,"userIcon":4608,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":8,"label":"Thermostat"},"specific":{"key":6,"label":"General Thermostat V2"},"mandatorySupportedCCs":[32,114,64,67,134],"mandatoryControlledCCs":[]}},{"nodeId":26,"index":1,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":8,"label":"Thermostat"},"specific":{"key":6,"label":"General Thermostat V2"},"mandatorySupportedCCs":[32,114,64,67,134],"mandatoryControlledCCs":[]}},{"nodeId":26,"index":2,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":8,"label":"Thermostat"},"specific":{"key":6,"label":"General Thermostat V2"},"mandatorySupportedCCs":[32,114,64,67,134],"mandatoryControlledCCs":[]}}],"values":[{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Air temperature","propertyName":"Air temperature","ccVersion":5,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Air temperature","ccSpecific":{"sensorType":1,"scale":1},"unit":"°F"},"value":72.5},{"endpoint":0,"commandClass":49,"commandClassName":"Multilevel Sensor","property":"Humidity","propertyName":"Humidity","ccVersion":5,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Humidity","ccSpecific":{"sensorType":5,"scale":0},"unit":"%"},"value":34},{"endpoint":0,"commandClass":66,"commandClassName":"Thermostat Operating State","property":"state","propertyName":"state","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Operating state","min":0,"max":255,"states":{"0":"Idle","1":"Heating","2":"Cooling","3":"Fan Only","4":"Pending Heat","5":"Pending Cool","6":"Vent/Economizer","7":"Aux Heating","8":"2nd Stage Heating","9":"2nd Stage Cooling","10":"2nd Stage Aux Heat","11":"3rd Stage Aux Heat"}},"value":0},{"endpoint":0,"commandClass":67,"commandClassName":"Thermostat Setpoint","property":"setpoint","propertyKey":1,"propertyName":"setpoint","propertyKeyName":"Heating","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"ccSpecific":{"setpointType":1},"unit":"°F"},"value":68},{"endpoint":0,"commandClass":67,"commandClassName":"Thermostat Setpoint","property":"setpoint","propertyKey":2,"propertyName":"setpoint","propertyKeyName":"Cooling","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":true,"ccSpecific":{"setpointType":2},"unit":"°F"},"value":69},{"endpoint":0,"commandClass":68,"commandClassName":"Thermostat Fan Mode","property":"mode","propertyName":"mode","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Thermostat fan mode","min":0,"max":255,"states":{"0":"Auto low","1":"Low"}}},{"endpoint":0,"commandClass":69,"commandClassName":"Thermostat Fan State","property":"state","propertyName":"state","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Thermostat fan state","min":0,"max":255,"states":{"0":"Idle / off","1":"Running / running low","2":"Running high","3":"Running medium","4":"Circulation mode","5":"Humidity circulation mode","6":"Right - left circulation mode","7":"Up - down circulation mode","8":"Quiet circulation mode"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":1,"propertyName":"Temperature Reporting Threshold","ccVersion":1,"metadata":{"type":"number","default":2,"readable":true,"writeable":true,"description":"Reporting threshold for changes in the ambient temperature","label":"Temperature Reporting Threshold","min":0,"max":4,"states":{"0":"Disabled","1":"0.5° F","2":"1.0° F","3":"1.5° F","4":"2.0° F"}},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":2,"propertyName":"HVAC Settings","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"description":"Configured HVAC settings","label":"HVAC Settings","min":0,"max":0},"value":17891329},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":4,"propertyName":"Power Status","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":false,"description":"C-Wire / Battery Status","label":"Power Status","min":0,"max":0},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":7,"propertyName":"Thermostat Swing Temperature","ccVersion":1,"metadata":{"type":"number","default":2,"readable":true,"writeable":true,"description":"Variance allowed from setpoint to engage HVAC","label":"Thermostat Swing Temperature","min":1,"max":8,"states":{"1":"0.5° F","2":"1.0° F","3":"1.5° F","4":"2.0° F","5":"2.5° F","6":"3.0° F","7":"3.5° F","8":"4.0° F"}},"value":2},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":8,"propertyName":"Thermostat Diff Temperature","ccVersion":1,"metadata":{"type":"number","default":4,"readable":true,"writeable":true,"description":"Configures additional stages","label":"Thermostat Diff Temperature","min":4,"max":12,"states":{"4":"2.0° F","8":"4.0° F","12":"6.0° F"}},"value":1028},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":9,"propertyName":"Thermostat Recovery Mode","ccVersion":1,"metadata":{"type":"number","default":2,"readable":true,"writeable":true,"description":"Fast or Economy recovery mode","label":"Thermostat Recovery Mode","min":1,"max":2,"states":{"1":"Fast recovery mode","2":"Economy recovery mode"}},"value":2},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":10,"propertyName":"Temperature Reporting Filter","ccVersion":1,"metadata":{"type":"number","default":124,"readable":true,"writeable":true,"description":"Upper/Lower bounds for thermostat temperature reporting","label":"Temperature Reporting Filter","min":0,"max":124},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":11,"propertyName":"Simple UI Mode","ccVersion":1,"metadata":{"type":"number","default":1,"readable":true,"writeable":true,"description":"Simple mode enable/disable","label":"Simple UI Mode","min":0,"max":1,"states":{"0":"Normal mode enabled","1":"Simple mode enabled"}},"value":1},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":12,"propertyName":"Multicast","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Enable or disables Multicast","label":"Multicast","min":0,"max":1,"states":{"0":"Multicast disabled","1":"Multicast enabled"}},"value":0},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":3,"propertyName":"Utility Lock Enable/Disable","ccVersion":1,"metadata":{"type":"number","default":0,"readable":false,"writeable":true,"description":"Prevents setpoint changes at thermostat","label":"Utility Lock Enable/Disable","min":0,"max":255,"states":{"0":"Utility lock disabled","1":"Utility lock enabled"}}},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":5,"propertyName":"Humidity Reporting Threshold","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Reporting threshold for changes in the relative humidity","label":"Humidity Reporting Threshold","min":0,"max":255,"states":{"0":"Disabled","1":"3% RH","2":"5% RH","3":"10% RH"}}},{"endpoint":0,"commandClass":112,"commandClassName":"Configuration","property":6,"propertyName":"Auxiliary/Emergency","ccVersion":1,"metadata":{"type":"number","default":0,"readable":true,"writeable":true,"description":"Enables or disables auxiliary / emergency heating","label":"Auxiliary/Emergency","min":0,"max":255,"states":{"0":"Auxiliary/Emergency heat disabled","1":"Auxiliary/Emergency heat enabled"}}},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535},"value":152},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535},"value":25602},{"endpoint":0,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":2,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535},"value":256},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"level","propertyName":"level","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Battery level","min":0,"max":100,"unit":"%"},"value":100},{"endpoint":0,"commandClass":128,"commandClassName":"Battery","property":"isLow","propertyName":"isLow","ccVersion":1,"metadata":{"type":"boolean","readable":true,"writeable":false,"label":"Low battery level"},"value":false},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"},"value":3},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"},"value":"4.24"},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"},"value":["10.7"]},{"endpoint":0,"commandClass":134,"commandClassName":"Version","property":"hardwareVersion","propertyName":"hardwareVersion","ccVersion":2,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip hardware version"}},{"endpoint":0,"commandClass":135,"commandClassName":"Indicator","property":"value","propertyName":"value","ccVersion":1,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Indicator value","ccSpecific":{"indicatorId":0},"min":0,"max":255},"value":0},{"endpoint":1,"commandClass":32,"commandClassName":"Basic","property":"currentValue","propertyName":"currentValue","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99}},{"endpoint":1,"commandClass":32,"commandClassName":"Basic","property":"targetValue","propertyName":"targetValue","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":1,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535}},{"endpoint":1,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535}},{"endpoint":1,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535}},{"endpoint":1,"commandClass":64,"commandClassName":"Thermostat Mode","property":"mode","propertyName":"mode","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Thermostat mode","min":0,"max":255,"states":{"0":"Off","1":"Heat","2":"Cool","3":"Auto","4":"Auxiliary","5":"Resume (on)","6":"Fan","7":"Furnace","8":"Dry","9":"Moist","10":"Auto changeover","11":"Energy heat","12":"Energy cool","13":"Away","15":"Full power","31":"Manufacturer specific"}}},{"endpoint":1,"commandClass":64,"commandClassName":"Thermostat Mode","property":"manufacturerData","propertyName":"manufacturerData","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":true}},{"endpoint":1,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"}},{"endpoint":1,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"}},{"endpoint":1,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"}},{"endpoint":2,"commandClass":32,"commandClassName":"Basic","property":"currentValue","propertyName":"currentValue","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Current value","min":0,"max":99}},{"endpoint":2,"commandClass":32,"commandClassName":"Basic","property":"targetValue","propertyName":"targetValue","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Target value","min":0,"max":99}},{"endpoint":2,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"manufacturerId","propertyName":"manufacturerId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Manufacturer ID","min":0,"max":65535}},{"endpoint":2,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productType","propertyName":"productType","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product type","min":0,"max":65535}},{"endpoint":2,"commandClass":114,"commandClassName":"Manufacturer Specific","property":"productId","propertyName":"productId","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":false,"label":"Product ID","min":0,"max":65535}},{"endpoint":2,"commandClass":64,"commandClassName":"Thermostat Mode","property":"mode","propertyName":"mode","ccVersion":0,"metadata":{"type":"number","readable":true,"writeable":true,"label":"Thermostat mode","min":0,"max":255,"states":{"0":"Off","1":"Heat","2":"Cool","3":"Auto","4":"Auxiliary","5":"Resume (on)","6":"Fan","7":"Furnace","8":"Dry","9":"Moist","10":"Auto changeover","11":"Energy heat","12":"Energy cool","13":"Away","15":"Full power","31":"Manufacturer specific"}}},{"endpoint":2,"commandClass":64,"commandClassName":"Thermostat Mode","property":"manufacturerData","propertyName":"manufacturerData","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":true}},{"endpoint":2,"commandClass":134,"commandClassName":"Version","property":"libraryType","propertyName":"libraryType","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Library type"}},{"endpoint":2,"commandClass":134,"commandClassName":"Version","property":"protocolVersion","propertyName":"protocolVersion","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave protocol version"}},{"endpoint":2,"commandClass":134,"commandClassName":"Version","property":"firmwareVersions","propertyName":"firmwareVersions","ccVersion":0,"metadata":{"type":"any","readable":true,"writeable":false,"label":"Z-Wave chip firmware versions"}}],"isFrequentListening":false,"maxDataRate":100000,"supportedDataRates":[40000,100000],"protocolVersion":3,"supportsBeaming":true,"supportsSecurity":false,"nodeType":1,"zwavePlusNodeType":0,"zwavePlusRoleType":5,"deviceClass":{"basic":{"key":4,"label":"Routing Slave"},"generic":{"key":8,"label":"Thermostat"},"specific":{"key":6,"label":"General Thermostat V2"},"mandatorySupportedCCs":[32,114,64,67,134],"mandatoryControlledCCs":[]},"commandClasses":[{"id":49,"name":"Multilevel Sensor","version":5,"isSecure":false},{"id":64,"name":"Thermostat Mode","version":2,"isSecure":false},{"id":66,"name":"Thermostat Operating State","version":2,"isSecure":false},{"id":67,"name":"Thermostat Setpoint","version":2,"isSecure":false},{"id":68,"name":"Thermostat Fan Mode","version":1,"isSecure":false},{"id":69,"name":"Thermostat Fan State","version":1,"isSecure":false},{"id":89,"name":"Association Group Information","version":1,"isSecure":false},{"id":90,"name":"Device Reset Locally","version":1,"isSecure":false},{"id":94,"name":"Z-Wave Plus Info","version":2,"isSecure":false},{"id":96,"name":"Multi Channel","version":4,"isSecure":false},{"id":112,"name":"Configuration","version":1,"isSecure":false},{"id":114,"name":"Manufacturer Specific","version":2,"isSecure":false},{"id":122,"name":"Firmware Update Meta Data","version":3,"isSecure":false},{"id":128,"name":"Battery","version":1,"isSecure":false},{"id":129,"name":"Clock","version":1,"isSecure":false},{"id":133,"name":"Association","version":2,"isSecure":false},{"id":134,"name":"Version","version":2,"isSecure":false},{"id":135,"name":"Indicator","version":1,"isSecure":false},{"id":142,"name":"Multi Channel Association","version":3,"isSecure":false}]}]}}}zwave-js-server-python-0.63.0/test/fixtures/climate_radio_thermostat_ct100_plus_state.json000066400000000000000000000425131500374325600321460ustar00rootroot00000000000000{ "nodeId": 13, "index": 0, "installerIcon": 4608, "userIcon": 4608, "status": 4, "ready": true, "deviceClass": { "basic": { "key": 1, "label": "Static Controller" }, "generic": { "key": 2, "label": "Thermostat" }, "specific": { "key": 3, "label": "Thermostat General V2" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": true, "isFrequentListening": false, "isRouting": true, "maxBaudRate": 40000, "isSecure": false, "version": 4, "isBeaming": true, "manufacturerId": 152, "productId": 256, "productType": 25602, "firmwareVersion": "10.7", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 5, "deviceConfig": { "manufacturerId": 152, "manufacturer": "Radio Thermostat Company of America (RTC)", "label": "CT100 Plus", "description": "Z-Wave Thermostat", "devices": [{ "productType": "0x6402", "productId": "0x0100" }], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} } }, "label": "CT100 Plus", "neighbors": [1, 2, 3, 4, 20], "endpointCountIsDynamic": false, "endpointsHaveIdenticalCapabilities": false, "individualEndpointCount": 2, "aggregatedEndpointCount": 0, "interviewAttempts": 1, "endpoints": [ { "nodeId": 13, "index": 0, "installerIcon": 4608, "userIcon": 4608 }, { "nodeId": 13, "index": 1, "installerIcon": 4608, "userIcon": 4608 }, { "nodeId": 13, "index": 2 } ], "commandClasses": [], "values": [ { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "manufacturerId", "propertyName": "manufacturerId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 152 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productType", "propertyName": "productType", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 25602 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productId", "propertyName": "productId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 256 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "libraryType", "propertyName": "libraryType", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "protocolVersion", "propertyName": "protocolVersion", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "4.24" }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "firmwareVersions", "propertyName": "firmwareVersions", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["10.7"] }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "hardwareVersion", "propertyName": "hardwareVersion", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } }, { "commandClassName": "Indicator", "commandClass": 135, "endpoint": 0, "property": "value", "propertyName": "value", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Indicator value", "ccSpecific": { "indicatorId": 0 } }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 1, "propertyName": "Temperature Reporting Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 4, "default": 2, "format": 0, "allowManualEntry": false, "states": { "0": "Disabled", "1": "0.5° F", "2": "1.0° F", "3": "1.5° F", "4": "2.0° F" }, "label": "Temperature Reporting Threshold", "description": "Reporting threshold for changes in the ambient temperature", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 2, "propertyName": "HVAC Settings", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 4, "min": 0, "max": 0, "default": 0, "format": 0, "allowManualEntry": true, "label": "HVAC Settings", "description": "Configured HVAC settings", "isFromConfig": true }, "value": 17891329 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 4, "propertyName": "Power Status", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 1, "min": 0, "max": 0, "default": 0, "format": 0, "allowManualEntry": true, "label": "Power Status", "description": "C-Wire / Battery Status", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 7, "propertyName": "Thermostat Swing Temperature", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 8, "default": 2, "format": 0, "allowManualEntry": false, "states": { "1": "0.5° F", "2": "1.0° F", "3": "1.5° F", "4": "2.0° F", "5": "2.5° F", "6": "3.0° F", "7": "3.5° F", "8": "4.0° F" }, "label": "Thermostat Swing Temperature", "description": "Variance allowed from setpoint to engage HVAC", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 8, "propertyName": "Thermostat Diff Temperature", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 4, "max": 12, "default": 4, "format": 0, "allowManualEntry": false, "states": { "4": "2.0° F", "8": "4.0° F", "12": "6.0° F" }, "label": "Thermostat Diff Temperature", "description": "Configures additional stages", "isFromConfig": true }, "value": 1028 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 9, "propertyName": "Thermostat Recovery Mode", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 2, "default": 2, "format": 0, "allowManualEntry": false, "states": { "1": "Fast recovery mode", "2": "Economy recovery mode" }, "label": "Thermostat Recovery Mode", "description": "Fast or Economy recovery mode", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 10, "propertyName": "Temperature Reporting Filter", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 124, "default": 124, "format": 0, "allowManualEntry": true, "label": "Temperature Reporting Filter", "description": "Upper/Lower bounds for thermostat temperature reporting", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 11, "propertyName": "Simple UI Mode", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Normal mode enabled", "1": "Simple mode enabled" }, "label": "Simple UI Mode", "description": "Simple mode enable/disable", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 12, "propertyName": "Multicast", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Multicast disabled", "1": "Multicast enabled" }, "label": "Multicast", "description": "Enable or disables Multicast", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 3, "propertyName": "Utility Lock Enable/Disable", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Utility lock disabled", "1": "Utility lock enabled" }, "label": "Utility Lock Enable/Disable", "description": "Prevents setpoint changes at thermostat", "isFromConfig": true } }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 5, "propertyName": "Humidity Reporting Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disabled", "1": "3% RH", "2": "5% RH", "3": "10% RH" }, "label": "Humidity Reporting Threshold", "description": "Reporting threshold for changes in the relative humidity", "isFromConfig": true } }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 6, "propertyName": "Auxiliary/Emergency", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Auxiliary/Emergency heat disabled", "1": "Auxiliary/Emergency heat enabled" }, "label": "Auxiliary/Emergency", "description": "Enables or disables auxiliary / emergency heating", "isFromConfig": true } }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "level", "propertyName": "level", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "isLow", "propertyName": "isLow", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "commandClassName": "Indicator", "commandClass": 135, "endpoint": 1, "property": "value", "propertyName": "value", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Indicator value", "ccSpecific": { "indicatorId": 0 } }, "value": 0 }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 1, "property": "Air temperature", "propertyName": "Air temperature", "metadata": { "type": "number", "readable": true, "writeable": false, "unit": "°F", "label": "Air temperature", "ccSpecific": { "sensorType": 1, "scale": 1 } }, "value": 72 }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 1, "property": "Humidity", "propertyName": "Humidity", "metadata": { "type": "number", "readable": true, "writeable": false, "unit": "%", "label": "Humidity", "ccSpecific": { "sensorType": 5, "scale": 0 } }, "value": 30 }, { "commandClassName": "Thermostat Mode", "commandClass": 64, "endpoint": 1, "property": "mode", "propertyName": "mode", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 31, "label": "Thermostat mode", "states": { "0": "Off", "1": "Heat", "2": "Cool", "3": "Auto" } }, "value": 1 }, { "commandClassName": "Thermostat Mode", "commandClass": 64, "endpoint": 1, "property": "manufacturerData", "propertyName": "manufacturerData", "metadata": { "type": "any", "readable": true, "writeable": true } }, { "commandClassName": "Thermostat Operating State", "commandClass": 66, "endpoint": 1, "property": "state", "propertyName": "state", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Operating state", "states": { "0": "Idle", "1": "Heating", "2": "Cooling", "3": "Fan Only", "4": "Pending Heat", "5": "Pending Cool", "6": "Vent/Economizer", "7": "Aux Heating", "8": "2nd Stage Heating", "9": "2nd Stage Cooling", "10": "2nd Stage Aux Heat", "11": "3rd Stage Aux Heat" } }, "value": 0 }, { "commandClassName": "Thermostat Setpoint", "commandClass": 67, "endpoint": 1, "property": "setpoint", "propertyKey": 1, "propertyName": "setpoint", "propertyKeyName": "Heating", "metadata": { "type": "number", "readable": true, "writeable": true, "unit": "°F", "ccSpecific": { "setpointType": 1 } }, "value": 72 }, { "commandClassName": "Thermostat Setpoint", "commandClass": 67, "endpoint": 1, "property": "setpoint", "propertyKey": 2, "propertyName": "setpoint", "propertyKeyName": "Cooling", "metadata": { "type": "number", "readable": true, "writeable": true, "unit": "°F", "ccSpecific": { "setpointType": 2 } }, "value": 73 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 1, "property": "level", "propertyName": "level", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 1, "property": "isLow", "propertyName": "isLow", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 1, "property": "isHigh", "propertyName": "isHigh", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "High battery level" } } ] } zwave-js-server-python-0.63.0/test/fixtures/controller_state.json000066400000000000000000000024461500374325600253120ustar00rootroot00000000000000{ "controller": { "sdkVersion": "Z-Wave 3.95", "type": 1, "homeId": 3245146787, "ownNodeId": 1, "isSecondary": false, "isUsingHomeIdFromOtherNetwork": false, "isSISPresent": true, "wasRealPrimary": true, "isStaticUpdateController": true, "isSlave": false, "firmwareVersion": "1.0", "manufacturerId": 134, "productType": 257, "productId": 90, "supportedFunctionTypes": [ 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 28, 32, 33, 34, 35, 36, 39, 41, 42, 43, 44, 45, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 80, 81, 83, 84, 85, 86, 87, 94, 96, 97, 98, 99, 102, 103, 128, 144, 146, 147, 152, 180, 182, 183, 184, 185, 186, 189, 190, 191, 210, 211, 212, 238, 239 ], "sucNodeId": 1, "supportsTimers": false, "isRebuildingRoutes": false, "inclusionState": 0 }, "nodes": [] } zwave-js-server-python-0.63.0/test/fixtures/cover_qubino_shutter_state.json000066400000000000000000000464331500374325600274040ustar00rootroot00000000000000{ "nodeId": 5, "index": 0, "installerIcon": 6656, "userIcon": 6656, "status": 4, "ready": true, "deviceClass": { "basic": { "key": 1, "label": "Routing Slave" }, "generic": { "key": 2, "label": "Multilevel Switch" }, "specific": { "key": 3, "label": "Motor Control Class C" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": true, "isFrequentListening": false, "isRouting": true, "maxBaudRate": 40000, "isSecure": false, "version": 4, "isBeaming": true, "manufacturerId": 345, "productId": 83, "productType": 3, "firmwareVersion": "7.2", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 5, "deviceConfig": { "manufacturerId": 345, "manufacturer": "Qubino", "label": "ZMNHOD", "description": "Flush Shutter DC", "devices": [{ "productType": "0x0003", "productId": "0x0053" }], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} } }, "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0x0159:0x0003:0x0053:0.0", "label": "ZMNHOD", "neighbors": [1, 2], "interviewAttempts": 1, "endpoints": [ { "nodeId": 5, "index": 0, "installerIcon": 6656, "userIcon": 6656 } ], "commandClasses": [], "values": [ { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 99, "label": "Target value" } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "duration", "propertyName": "duration", "ccVersion": 3, "metadata": { "type": "duration", "readable": true, "writeable": true, "label": "Transition duration" } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 99, "label": "Current value" }, "value": "unknown" }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "Up", "propertyName": "Up", "ccVersion": 3, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Perform a level change (Up)", "ccSpecific": { "switchType": 2 } } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "Down", "propertyName": "Down", "ccVersion": 3, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Perform a level change (Down)", "ccSpecific": { "switchType": 2 } } }, { "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Current value" }, "value": "unknown" }, { "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Target value" } }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 345 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 3 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 83 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "4.38" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["7.2"] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 65537, "propertyName": "value", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh]", "unit": "kWh", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 65537, "propertyName": "deltaTime", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. time delta)", "unit": "s", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 66049, "propertyName": "value", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W]", "unit": "W", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 66049, "propertyName": "deltaTime", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. time delta)", "unit": "s", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "reset", "propertyName": "reset", "ccVersion": 4, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Reset accumulated values" } }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 65537, "propertyName": "previousValue", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. value)", "unit": "kWh", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } } }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 66049, "propertyName": "previousValue", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. value)", "unit": "W", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "alarmType", "propertyName": "alarmType", "ccVersion": 5, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Alarm Type" } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "alarmLevel", "propertyName": "alarmLevel", "ccVersion": 5, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Alarm Level" } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Over-load status", "propertyName": "Power Management", "propertyKeyName": "Over-load status", "ccVersion": 5, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Over-load status", "states": { "0": "idle", "8": "Over-load detected" }, "ccSpecific": { "notificationType": 8 } }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 10, "propertyName": "Activate/deactivate functions ALL ON / ALL OFF", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 65535, "default": 255, "format": 1, "allowManualEntry": false, "states": { "0": "ALL ON is not active, ALL OFF is not active", "1": "ALL ON is not active ALL OFF active", "2": "ALL ON is not active ALL OFF is not active", "255": "ALL ON active, ALL OFF active" }, "label": "Activate/deactivate functions ALL ON / ALL OFF", "isFromConfig": true }, "value": 255 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 40, "propertyName": "Power report (Watts) on power change for Q1 or Q2", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 1, "format": 0, "allowManualEntry": true, "label": "Power report (Watts) on power change for Q1 or Q2", "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 42, "propertyName": "Power report (Watts) by time interval for Q1 or Q2", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 32767, "default": 300, "format": 0, "allowManualEntry": true, "label": "Power report (Watts) by time interval for Q1 or Q2", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 71, "propertyName": "Operating modes", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Shutter mode.", "1": "Venetian mode (up/down and slate rotation)" }, "label": "Operating modes", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 72, "propertyName": "Slats tilting full turn time", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 32767, "default": 150, "format": 0, "allowManualEntry": true, "label": "Slats tilting full turn time", "isFromConfig": true }, "value": 630 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 73, "propertyName": "Slats position", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 1, "format": 1, "allowManualEntry": false, "states": { "0": "Return to previous position only with Z-wave", "1": "Return to previous position with Z-wave or button" }, "label": "Slats position", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 74, "propertyName": "Motor moving up/down time", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 32767, "default": 0, "format": 0, "allowManualEntry": true, "label": "Motor moving up/down time", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 76, "propertyName": "Motor operation detection", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 6, "format": 0, "allowManualEntry": true, "label": "Motor operation detection", "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 78, "propertyName": "Forced Shutter DC calibration", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Default", "1": "Start calibration process." }, "label": "Forced Shutter DC calibration", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 85, "propertyName": "Power consumption max delay time", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 3, "max": 50, "default": 8, "format": 0, "allowManualEntry": true, "label": "Power consumption max delay time", "isFromConfig": true }, "value": 8 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 86, "propertyName": "Power consumption at limit switch delay time", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 3, "max": 50, "default": 8, "format": 0, "allowManualEntry": true, "label": "Power consumption at limit switch delay time", "isFromConfig": true }, "value": 8 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 90, "propertyName": "Time delay for next motor movement", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 30, "default": 5, "format": 0, "allowManualEntry": true, "label": "Time delay for next motor movement", "isFromConfig": true }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 110, "propertyName": "Temperature sensor offset settings", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 1, "max": 32536, "default": 32536, "format": 0, "allowManualEntry": true, "label": "Temperature sensor offset settings", "isFromConfig": true }, "value": 32536 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 120, "propertyName": "Digital temperature sensor reporting", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 127, "default": 5, "format": 0, "allowManualEntry": true, "label": "Digital temperature sensor reporting", "isFromConfig": true }, "value": 5 } ] } zwave-js-server-python-0.63.0/test/fixtures/device_config.json000066400000000000000000000006741500374325600245140ustar00rootroot00000000000000{ "filename": "test_device.json", "manufacturer": "Test Manufacturer", "manufacturerId": "0x1234", "label": "Test Device", "description": "Test Device Description", "devices": [ { "productType": "0x5678", "productId": "0x9ABC" } ], "firmwareVersion": { "min": "1.0", "max": "2.0" }, "associations": {}, "paramInformation": {}, "supportsZWavePlus": true, "proprietary": {}, "compat": {} } zwave-js-server-python-0.63.0/test/fixtures/endpoints_with_command_classes_state.json000066400000000000000000000120071500374325600313720ustar00rootroot00000000000000{ "nodeId": 45, "index": 0, "installerIcon": 1536, "userIcon": 1536, "status": 0, "ready": false, "isListening": true, "isRouting": true, "isSecure": "unknown", "manufacturerId": 798, "productId": 1, "productType": 1, "firmwareVersion": "1.57", "zwavePlusVersion": 1, "deviceConfig": { "filename": "/data/db/devices/0x031e/lzw31-sn.json", "isEmbedded": true, "manufacturer": "Inovelli", "manufacturerId": 798, "label": "LZW31-SN", "description": "Red Series Dimmer", "devices": [{ "productType": 1, "productId": 1 }], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} }, "metadata": { "inclusion": "Start the inclusion process again on your HUB and tap the Configuration Button three (3) times.\\n\\nPlease Note: If this doesn't work, you can check to see if your switch is within Z-Wave Range by holding down the Configuration Button for 5-10 seconds (if it's not within range, the LED Bar will indicate Red and if it is within Range, the LED Bar will indicate Green). If your switch indicates Red, please move the switch closer to the HUB. If your switch indicates Green, please try running an Exclusion to reset your switch", "exclusion": "To Exclude your dimmer, put your HUB in exclusion mode and press the Configuration Button three (3) times", "reset": "You may factory reset the switch by holding down the Config Button for twenty (20) or more seconds. The LED Bar will turn Red and blink three (3) times to confirm. \\n\\nHowever, we recommend using a certified Z-Wave controller to remove the device from your network for factory resetting the switch. \\n\\nOnly use either of these procedures in the event that the network primary controller is missing or otherwise inoperable", "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=product_documents/4206/LZW31-SN%20Manual%20-%20Inovelli%20Dimmer%20Switch%20(Red%20Series)%20-%2006.28.21.pdf" } }, "label": "LZW31-SN", "interviewAttempts": 0, "endpoints": [ { "nodeId": 45, "index": 0, "installerIcon": 1536, "userIcon": 1536, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 17, "label": "Multilevel Switch" }, "specific": { "key": 1, "label": "Multilevel Power Switch" }, "mandatorySupportedCCs": [32, 38, 39], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 38, "name": "Multilevel Switch", "version": 2, "isSecure": false }, { "id": 50, "name": "Meter", "version": 3, "isSecure": false }, { "id": 85, "name": "Transport Service", "version": 2, "isSecure": false }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": false }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": false }, { "id": 91, "name": "Central Scene", "version": 3, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": false }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": false }, { "id": 115, "name": "Powerlevel", "version": 1, "isSecure": false }, { "id": 117, "name": "Protection", "version": 2, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 2, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true }, { "id": 159, "name": "Security 2", "version": 1, "isSecure": true } ] } ], "values": [], "isFrequentListening": false, "maxDataRate": 100000, "supportedDataRates": [40000, 100000], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 5, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 17, "label": "Multilevel Switch" }, "specific": { "key": 1, "label": "Multilevel Power Switch" }, "mandatorySupportedCCs": [32, 38, 39], "mandatoryControlledCCs": [] }, "interviewStage": "Complete", "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0x031e:0x0001:0x0001:1.57", "statistics": { "commandsTX": 0, "commandsRX": 0, "commandsDroppedRX": 0, "commandsDroppedTX": 0, "timeoutResponse": 0 }, "isControllerNode": false, "keepAwake": false } zwave-js-server-python-0.63.0/test/fixtures/energy_production_state.json000066400000000000000000000126151500374325600266650ustar00rootroot00000000000000{ "nodeId": 2, "index": 0, "status": 4, "ready": true, "isListening": true, "isRouting": true, "isSecure": false, "interviewAttempts": 1, "endpoints": [ { "nodeId": 2, "index": 0, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 6, "label": "Appliance" }, "specific": { "key": 1, "label": "General Appliance" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 134, "name": "Version", "version": 1, "isSecure": false }, { "id": 144, "name": "Energy Production", "version": 1, "isSecure": false } ] } ], "values": [ { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 1, "metadata": { "type": "string[]", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions", "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Library type", "states": { "0": "Unknown", "1": "Static Controller", "2": "Controller", "3": "Enhanced Slave", "4": "Slave", "5": "Installer", "6": "Routing Slave", "7": "Bridge Controller", "8": "Device under Test", "9": "N/A", "10": "AV Remote", "11": "AV Device" }, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version", "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 144, "commandClassName": "Energy Production", "property": "value", "propertyKey": 0, "propertyName": "value", "propertyKeyName": "0", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Power", "ccSpecific": { "parameter": 0, "scale": 0 }, "unit": "W", "stateful": true, "secret": false }, "value": 1.23 }, { "endpoint": 0, "commandClass": 144, "commandClassName": "Energy Production", "property": "value", "propertyKey": 1, "propertyName": "value", "propertyKeyName": "1", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Production Total", "ccSpecific": { "parameter": 1, "scale": 0 }, "unit": "Wh", "stateful": true, "secret": false }, "value": 1234.56 }, { "endpoint": 0, "commandClass": 144, "commandClassName": "Energy Production", "property": "value", "propertyKey": 2, "propertyName": "value", "propertyKeyName": "2", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Production Today", "ccSpecific": { "parameter": 2, "scale": 0 }, "unit": "Wh", "stateful": true, "secret": false }, "value": 123.45 }, { "endpoint": 0, "commandClass": 144, "commandClassName": "Energy Production", "property": "value", "propertyKey": 3, "propertyName": "value", "propertyKeyName": "3", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Total Time", "ccSpecific": { "parameter": 3, "scale": 0 }, "unit": "seconds", "stateful": true, "secret": false }, "value": 123456 } ], "isFrequentListening": false, "maxDataRate": 100000, "supportedDataRates": [ 40000, 9600, 100000 ], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 6, "label": "Appliance" }, "specific": { "key": 1, "label": "General Appliance" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "interviewStage": "Complete", "statistics": { "commandsTX": 10, "commandsRX": 7, "commandsDroppedRX": 0, "commandsDroppedTX": 0, "timeoutResponse": 1, "rtt": 84.8 }, "highestSecurityClass": -1, "isControllerNode": false, "keepAwake": false }zwave-js-server-python-0.63.0/test/fixtures/idl_101_lock_state.json000066400000000000000000001672561500374325600253030ustar00rootroot00000000000000{ "nodeId": 26, "index": 0, "installerIcon": 768, "userIcon": 768, "status": 4, "ready": true, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 2, "label": "Entry Control" }, "specific": { "key": 3, "label": "Secure Keypad Door Lock" }, "mandatorySupportedCCs": [ "Basic", "Door Lock", "User Code", "Manufacturer Specific", "Security", "Version" ], "mandatoryControlledCCs": [] }, "isListening": false, "isFrequentListening": true, "isRouting": true, "maxBaudRate": 40000, "isSecure": true, "version": 4, "isBeaming": true, "manufacturerId": 560, "productId": 1, "productType": 3, "firmwareVersion": "1.0", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 7, "deviceConfig": { "manufacturerId": 560, "manufacturer": "Alphonsus Tech", "label": "IDL-101", "description": "Z-Wave Lock", "devices": [{ "productType": "0x0003", "productId": "0x0001" }], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} } }, "label": "IDL-101", "neighbors": [1, 6, 8, 9, 10, 21, 54, 55, 59, 60, 61, 62, 65], "interviewAttempts": 1, "interviewStage": "Complete", "endpoints": [ { "nodeId": 26, "index": 0, "installerIcon": 768, "userIcon": 768 } ], "values": [ { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "currentMode", "propertyName": "currentMode", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Current lock mode", "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" } }, "value": 255 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "targetMode", "propertyName": "targetMode", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Target lock mode", "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" } }, "value": 0 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoor", "propertyName": "outsideHandlesCanOpenDoor", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which outside handles can open the door (actual status)" }, "value": [false, false, false, false] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoor", "propertyName": "insideHandlesCanOpenDoor", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which inside handles can open the door (actual status)" }, "value": [false, false, false, false] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "latchStatus", "propertyName": "latchStatus", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the latch" }, "value": "open" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "boltStatus", "propertyName": "boltStatus", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the bolt" }, "value": "locked" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "doorStatus", "propertyName": "doorStatus", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the door" }, "value": "closed" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeout", "propertyName": "lockTimeout", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Seconds until lock mode times out" } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "operationType", "propertyName": "operationType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Lock operation type", "states": { "1": "Constant", "2": "Timed" } }, "value": 1 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoorConfiguration", "propertyName": "outsideHandlesCanOpenDoorConfiguration", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which outside handles can open the door (configuration)" }, "value": [true, true, true, true] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoorConfiguration", "propertyName": "insideHandlesCanOpenDoorConfiguration", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which inside handles can open the door (configuration)" }, "value": [true, true, true, true] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeoutConfiguration", "propertyName": "lockTimeoutConfiguration", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 65535, "label": "Duration of timed mode in seconds" } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 1, "propertyName": "userIdStatus", "propertyKeyName": "1", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (1)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 1, "propertyName": "userCode", "propertyKeyName": "1", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (1)" }, "value": "57823" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 2, "propertyName": "userIdStatus", "propertyKeyName": "2", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (2)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 2, "propertyName": "userCode", "propertyKeyName": "2", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (2)" }, "value": "6910" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 3, "propertyName": "userIdStatus", "propertyKeyName": "3", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (3)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 3, "propertyName": "userCode", "propertyKeyName": "3", "ccVersion": 1, "metadata": { "type": "buffer", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (3)" }, "value": { "type": "Buffer", "data": [164, 14, 170, 86] } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 4, "propertyName": "userIdStatus", "propertyKeyName": "4", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (4)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 4, "propertyName": "userCode", "propertyKeyName": "4", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (4)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 5, "propertyName": "userIdStatus", "propertyKeyName": "5", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (5)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 5, "propertyName": "userCode", "propertyKeyName": "5", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (5)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 6, "propertyName": "userIdStatus", "propertyKeyName": "6", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (6)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 6, "propertyName": "userCode", "propertyKeyName": "6", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (6)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 7, "propertyName": "userIdStatus", "propertyKeyName": "7", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (7)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 7, "propertyName": "userCode", "propertyKeyName": "7", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (7)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 8, "propertyName": "userIdStatus", "propertyKeyName": "8", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (8)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 8, "propertyName": "userCode", "propertyKeyName": "8", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (8)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 9, "propertyName": "userIdStatus", "propertyKeyName": "9", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (9)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 9, "propertyName": "userCode", "propertyKeyName": "9", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (9)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 10, "propertyName": "userIdStatus", "propertyKeyName": "10", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (10)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 10, "propertyName": "userCode", "propertyKeyName": "10", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (10)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 11, "propertyName": "userIdStatus", "propertyKeyName": "11", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (11)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 11, "propertyName": "userCode", "propertyKeyName": "11", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (11)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 12, "propertyName": "userIdStatus", "propertyKeyName": "12", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (12)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 12, "propertyName": "userCode", "propertyKeyName": "12", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (12)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 13, "propertyName": "userIdStatus", "propertyKeyName": "13", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (13)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 13, "propertyName": "userCode", "propertyKeyName": "13", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (13)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 14, "propertyName": "userIdStatus", "propertyKeyName": "14", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (14)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 14, "propertyName": "userCode", "propertyKeyName": "14", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (14)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 15, "propertyName": "userIdStatus", "propertyKeyName": "15", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (15)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 15, "propertyName": "userCode", "propertyKeyName": "15", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (15)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 16, "propertyName": "userIdStatus", "propertyKeyName": "16", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (16)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 16, "propertyName": "userCode", "propertyKeyName": "16", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (16)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 17, "propertyName": "userIdStatus", "propertyKeyName": "17", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (17)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 17, "propertyName": "userCode", "propertyKeyName": "17", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (17)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 18, "propertyName": "userIdStatus", "propertyKeyName": "18", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (18)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 18, "propertyName": "userCode", "propertyKeyName": "18", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (18)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 19, "propertyName": "userIdStatus", "propertyKeyName": "19", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (19)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 19, "propertyName": "userCode", "propertyKeyName": "19", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (19)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 20, "propertyName": "userIdStatus", "propertyKeyName": "20", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (20)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 20, "propertyName": "userCode", "propertyKeyName": "20", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (20)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 21, "propertyName": "userIdStatus", "propertyKeyName": "21", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (21)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 21, "propertyName": "userCode", "propertyKeyName": "21", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (21)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 22, "propertyName": "userIdStatus", "propertyKeyName": "22", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (22)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 22, "propertyName": "userCode", "propertyKeyName": "22", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (22)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 23, "propertyName": "userIdStatus", "propertyKeyName": "23", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (23)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 23, "propertyName": "userCode", "propertyKeyName": "23", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (23)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 24, "propertyName": "userIdStatus", "propertyKeyName": "24", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (24)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 24, "propertyName": "userCode", "propertyKeyName": "24", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (24)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 25, "propertyName": "userIdStatus", "propertyKeyName": "25", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (25)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 25, "propertyName": "userCode", "propertyKeyName": "25", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (25)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 26, "propertyName": "userIdStatus", "propertyKeyName": "26", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (26)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 26, "propertyName": "userCode", "propertyKeyName": "26", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (26)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 27, "propertyName": "userIdStatus", "propertyKeyName": "27", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (27)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 27, "propertyName": "userCode", "propertyKeyName": "27", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (27)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 28, "propertyName": "userIdStatus", "propertyKeyName": "28", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (28)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 28, "propertyName": "userCode", "propertyKeyName": "28", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (28)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 29, "propertyName": "userIdStatus", "propertyKeyName": "29", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (29)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 29, "propertyName": "userCode", "propertyKeyName": "29", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (29)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 30, "propertyName": "userIdStatus", "propertyKeyName": "30", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (30)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 30, "propertyName": "userCode", "propertyKeyName": "30", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (30)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 31, "propertyName": "userIdStatus", "propertyKeyName": "31", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (31)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 31, "propertyName": "userCode", "propertyKeyName": "31", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (31)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 32, "propertyName": "userIdStatus", "propertyKeyName": "32", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (32)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 32, "propertyName": "userCode", "propertyKeyName": "32", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (32)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 33, "propertyName": "userIdStatus", "propertyKeyName": "33", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (33)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 33, "propertyName": "userCode", "propertyKeyName": "33", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (33)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 34, "propertyName": "userIdStatus", "propertyKeyName": "34", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (34)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 34, "propertyName": "userCode", "propertyKeyName": "34", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (34)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 35, "propertyName": "userIdStatus", "propertyKeyName": "35", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (35)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 35, "propertyName": "userCode", "propertyKeyName": "35", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (35)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 36, "propertyName": "userIdStatus", "propertyKeyName": "36", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (36)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 36, "propertyName": "userCode", "propertyKeyName": "36", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (36)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 37, "propertyName": "userIdStatus", "propertyKeyName": "37", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (37)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 37, "propertyName": "userCode", "propertyKeyName": "37", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (37)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 38, "propertyName": "userIdStatus", "propertyKeyName": "38", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (38)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 38, "propertyName": "userCode", "propertyKeyName": "38", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (38)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 39, "propertyName": "userIdStatus", "propertyKeyName": "39", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (39)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 39, "propertyName": "userCode", "propertyKeyName": "39", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (39)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 40, "propertyName": "userIdStatus", "propertyKeyName": "40", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (40)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 40, "propertyName": "userCode", "propertyKeyName": "40", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (40)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 41, "propertyName": "userIdStatus", "propertyKeyName": "41", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (41)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 41, "propertyName": "userCode", "propertyKeyName": "41", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (41)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 42, "propertyName": "userIdStatus", "propertyKeyName": "42", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (42)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 42, "propertyName": "userCode", "propertyKeyName": "42", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (42)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 43, "propertyName": "userIdStatus", "propertyKeyName": "43", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (43)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 43, "propertyName": "userCode", "propertyKeyName": "43", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (43)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 44, "propertyName": "userIdStatus", "propertyKeyName": "44", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (44)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 44, "propertyName": "userCode", "propertyKeyName": "44", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (44)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 45, "propertyName": "userIdStatus", "propertyKeyName": "45", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (45)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 45, "propertyName": "userCode", "propertyKeyName": "45", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (45)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 46, "propertyName": "userIdStatus", "propertyKeyName": "46", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (46)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 46, "propertyName": "userCode", "propertyKeyName": "46", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (46)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 47, "propertyName": "userIdStatus", "propertyKeyName": "47", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (47)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 47, "propertyName": "userCode", "propertyKeyName": "47", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (47)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 48, "propertyName": "userIdStatus", "propertyKeyName": "48", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (48)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 48, "propertyName": "userCode", "propertyKeyName": "48", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (48)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 49, "propertyName": "userIdStatus", "propertyKeyName": "49", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (49)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 49, "propertyName": "userCode", "propertyKeyName": "49", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (49)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 50, "propertyName": "userIdStatus", "propertyKeyName": "50", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (50)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 50, "propertyName": "userCode", "propertyKeyName": "50", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (50)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 51, "propertyName": "userIdStatus", "propertyKeyName": "51", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (51)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 51, "propertyName": "userCode", "propertyKeyName": "51", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (51)" }, "value": "" }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 52, "propertyName": "userIdStatus", "propertyKeyName": "52", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (52)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 52, "propertyName": "userCode", "propertyKeyName": "52", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (52)" }, "value": "" }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 1, "propertyName": "Door Lock Mode", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 3, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Disable Away Manual Lock", "1": "Disable Away Auto Lock", "2": "Enable Away Manual Lock", "3": "Enable Away Auto Lock" }, "label": "Door Lock Mode", "description": "Sets the door lock mode", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "alarmType", "propertyName": "alarmType", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Alarm Type" } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "alarmLevel", "propertyName": "alarmLevel", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Alarm Level" } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Home Security", "propertyKey": "Motion sensor status", "propertyName": "Home Security", "propertyKeyName": "Motion sensor status", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Motion sensor status", "states": { "0": "idle", "8": "Motion detection" }, "ccSpecific": { "notificationType": 7 } }, "value": 0 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 560 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 3 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 1 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "level", "propertyName": "level", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "isLow", "propertyName": "isLow", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "4.5" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["1.0"] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } } ] } zwave-js-server-python-0.63.0/test/fixtures/inovelli_switch_state.json000066400000000000000000000634001500374325600263260ustar00rootroot00000000000000{ "nodeId": 31, "index": 0, "installerIcon": 1793, "userIcon": 1793, "status": 4, "ready": true, "isListening": true, "isFrequentListening": false, "isRouting": true, "maxBaudRate": 40000, "isSecure": false, "version": 4, "isBeaming": true, "manufacturerId": 798, "productId": 1, "productType": 2, "firmwareVersion": "1.9", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 5, "deviceConfig": { "filename": "/usr/src/app/node_modules/@zwave-js/config/config/devices/0x031e/lzw30-sn.json", "manufacturerId": 798, "manufacturer": "Inovelli", "label": "LZW30-SN", "description": "Red Series On/Off switch", "devices": [ { "productType": "0x0002", "productId": "0x0001" } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} } }, "label": "LZW30-SN", "neighbors": [ 17, 32, 33, 36, 37, 38, 39, 41, 42 ], "interviewAttempts": 1, "interviewStage": "Complete", "endpoints": [ { "nodeId": 31, "index": 0, "installerIcon": 1793, "userIcon": 1793 } ], "values": [ { "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Current value" }, "value": false }, { "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Target value" }, "value": false }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 65537, "propertyName": "value", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh]", "unit": "kWh", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } }, "value": 26.75 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 65537, "propertyName": "previousValue", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. value)", "unit": "kWh", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } }, "value": 26.75 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 65537, "propertyName": "deltaTime", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. time delta)", "unit": "s", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 } }, "value": 3600 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 66049, "propertyName": "value", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W]", "unit": "W", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 66049, "propertyName": "deltaTime", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. time delta)", "unit": "s", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "reset", "propertyName": "reset", "ccVersion": 3, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Reset accumulated values" } }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 66049, "propertyName": "previousValue", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. value)", "unit": "W", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "slowRefresh", "propertyName": "slowRefresh", "ccVersion": 3, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Send held down notifications at a slow rate", "description": "When this is true, KeyHeldDown notifications are sent every 55s. When this is false, the notifications are sent every 200ms." } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "001", "propertyName": "scene", "propertyKeyName": "001", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 001", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x", "5": "KeyPressed4x", "6": "KeyPressed5x" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "002", "propertyName": "scene", "propertyKeyName": "002", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 002", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x", "5": "KeyPressed4x", "6": "KeyPressed5x" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "003", "propertyName": "scene", "propertyKeyName": "003", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 003", "states": { "0": "KeyPressed" } } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 1, "propertyName": "Power On State", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 2, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Prior State", "1": "On", "2": "Off" }, "label": "Power On State", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 2, "propertyName": "Invert Switch", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Disabled", "1": "Enabled" }, "label": "Invert Switch", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "Auto Off Timer", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 32767, "default": 0, "unit": "seconds", "format": 0, "allowManualEntry": true, "label": "Auto Off Timer", "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Association Behavior", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 15, "default": 15, "format": 0, "allowManualEntry": true, "label": "Association Behavior", "isFromConfig": true }, "value": 15 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 5, "propertyName": "LED Indicator Color", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 255, "default": 170, "format": 0, "allowManualEntry": true, "states": { "0": "Red", "21": "Orange", "42": "Yellow", "85": "Green", "127": "Cyan", "170": "Blue", "212": "Violet", "234": "Pink" }, "label": "LED Indicator Color", "isFromConfig": true }, "value": 170 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 6, "propertyName": "LED Indicator Intensity", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 10, "default": 5, "format": 0, "allowManualEntry": false, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "label": "LED Indicator Intensity", "isFromConfig": true }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 7, "propertyName": "LED Indicator Intensity (When Off)", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 10, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "label": "LED Indicator Intensity (When Off)", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 9, "propertyName": "LED Strip Timeout", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 10, "default": 0, "unit": "seconds", "format": 0, "allowManualEntry": false, "states": { "0": "Stay Off", "1": "One Second", "2": "Two Seconds", "3": "Three Seconds", "4": "Four Seconds", "5": "Five Seconds", "6": "Six Seconds", "7": "Seven Seconds", "8": "Eight Seconds", "9": "Nine Seconds", "10": "Ten Seconds" }, "label": "LED Strip Timeout", "isFromConfig": true }, "value": 3 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 10, "propertyName": "Active Power Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 10, "unit": "percent", "format": 0, "allowManualEntry": true, "label": "Active Power Reports", "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 11, "propertyName": "Periodic Power & Energy Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 32767, "default": 3600, "unit": "seconds", "format": 0, "allowManualEntry": true, "label": "Periodic Power & Energy Reports", "isFromConfig": true }, "value": 3600 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 12, "propertyName": "Energy Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 10, "unit": "percent", "format": 0, "allowManualEntry": true, "label": "Energy Reports", "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 255, "propertyName": "LED Strip Effect (Color)", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 255, "default": 0, "format": 0, "allowManualEntry": true, "states": { "0": "Red", "21": "Orange", "42": "Yellow", "85": "Green", "127": "Cyan", "170": "Blue", "212": "Violet", "234": "Pink" }, "label": "LED Strip Effect (Color)", "isFromConfig": true }, "value": 180 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 65280, "propertyName": "LED Strip Effect (Brightness)", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 10, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "label": "LED Strip Effect (Brightness)", "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 16711680, "propertyName": "LED Strip Effect (Duration)", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 255, "default": 0, "format": 0, "allowManualEntry": true, "label": "LED Strip Effect (Duration)", "isFromConfig": true }, "value": 255 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 2130706432, "propertyName": "LED Strip Effect (Effect)", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 4, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Off", "1": "Solid", "2": "Fast Blink", "3": "Slow Blink", "4": "Pulse" }, "label": "LED Strip Effect (Effect)", "isFromConfig": true }, "value": 4 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 798 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 2 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 1 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "local", "propertyName": "local", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Local protection state", "states": { "8": "unknown (0x08)", "9": "unknown (0x09)", "10": "unknown (0x0a)" } }, "value": 0 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "rf", "propertyName": "rf", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "RF protection state", "states": { "8": "unknown (0x08)", "9": "unknown (0x09)", "10": "unknown (0x0a)" } }, "value": 0 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "exclusiveControlNodeId", "propertyName": "exclusiveControlNodeId", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true } }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "timeout", "propertyName": "timeout", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true } }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "6.4" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": [ "1.9" ] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } } ], "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 16, "label": "Binary Switch" }, "specific": { "key": 1, "label": "Binary Power Switch" }, "mandatorySupportedCCs": [ 32, 37, 39 ], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 37, "name": "Binary Switch", "version": 1, "isSecure": false }, { "id": 50, "name": "Meter", "version": 3, "isSecure": false }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": false }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": false }, { "id": 91, "name": "Central Scene", "version": 3, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": false }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": false }, { "id": 117, "name": "Protection", "version": 2, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 2, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true } ] } zwave-js-server-python-0.63.0/test/fixtures/invalid_multilevel_sensor_type_state.json000066400000000000000000001116221500374325600314460ustar00rootroot00000000000000{ "nodeId": 74, "index": 0, "installerIcon": 4608, "userIcon": 4609, "status": 4, "ready": true, "isListening": true, "isRouting": true, "isSecure": false, "manufacturerId": 411, "productId": 515, "productType": 3, "firmwareVersion": "4.0", "zwavePlusVersion": 1, "deviceConfig": { "filename": "/usr/src/node_modules/@zwave-js/config/config/devices/0x019b/z-trm3.json", "manufacturer": "ThermoFloor", "manufacturerId": 411, "label": "Heatit Z-TRM3", "description": "Floor thermostat", "devices": [ { "productType": 3, "productId": 515 } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} }, "compat": { "valueIdRegex": {}, "overrideFloatEncoding": { "size": 2 }, "addCCs": {} }, "isEmbedded": true }, "label": "Heatit Z-TRM3", "endpointCountIsDynamic": false, "endpointsHaveIdenticalCapabilities": false, "individualEndpointCount": 4, "aggregatedEndpointCount": 0, "interviewAttempts": 0, "endpoints": [ { "nodeId": 74, "index": 0, "installerIcon": 4608, "userIcon": 4609, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 8, "label": "Thermostat" }, "specific": { "key": 6, "label": "General Thermostat V2" }, "mandatorySupportedCCs": [32, 114, 64, 67, 134], "mandatoryControlledCCs": [] } }, { "nodeId": 74, "index": 1, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 8, "label": "Thermostat" }, "specific": { "key": 6, "label": "General Thermostat V2" }, "mandatorySupportedCCs": [32, 114, 64, 67, 134], "mandatoryControlledCCs": [] } }, { "nodeId": 74, "index": 2, "installerIcon": 3328, "userIcon": 3329, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 33, "label": "Multilevel Sensor" }, "specific": { "key": 1, "label": "Routing Multilevel Sensor" }, "mandatorySupportedCCs": [32, 49], "mandatoryControlledCCs": [] } }, { "nodeId": 74, "index": 3, "installerIcon": 3328, "userIcon": 3329, "deviceClass": null }, { "nodeId": 74, "index": 4, "installerIcon": 3328, "userIcon": 3329, "deviceClass": null } ], "values": [ { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 66049, "propertyName": "value", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W]", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 }, "unit": "W" }, "value": 0.17 }, { "endpoint": 0, "commandClass": 96, "commandClassName": "Multi Channel", "property": "endpointIndizes", "propertyName": "endpointIndizes", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": [1, 2, 3, 4] }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 2, "propertyName": "Sensor mode", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Sensor mode", "default": 1, "min": 0, "max": 4, "states": { "0": "F-mode, floor sensor mode", "1": "A-mode, internal room sensor mode", "2": "AF-mode, internal sensor and floor sensor mode", "3": "A2-mode, external room sensor mode", "4": "A2F-mode, external sensor with floor limitation" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "Floor sensor type", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Floor sensor type", "default": 0, "min": 0, "max": 5, "states": { "0": "10K-NTC", "1": "12K-NTC", "2": "15K-NTC", "3": "22K-NTC", "4": "33K-NTC", "5": "47K-NTC" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Temperature control hysteresis (DIFF I)", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Temperature control hysteresis (DIFF I)", "default": 5, "min": 3, "max": 30, "unit": ".1\u00b0C", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 5, "propertyName": "Floor minimum temperature limit (FLo)", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Floor minimum temperature limit (FLo)", "default": 50, "min": 50, "max": 400, "unit": ".1\u00b0C", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 6, "propertyName": "Floor maximum temperature (FHi)", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Floor maximum temperature (FHi)", "default": 400, "min": 50, "max": 400, "unit": "0.1\u00b0C", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 7, "propertyName": "Air minimum temperature limit (ALo)", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Air minimum temperature limit (ALo)", "default": 50, "min": 50, "max": 400, "unit": ".1\u00b0C", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyName": "Air maximum temperature limit (AHi)", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Air maximum temperature limit (AHi)", "default": 400, "min": 50, "max": 400, "unit": ".1\u00b0C", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 10, "propertyName": "Room sensor calibration", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Room sensor calibration", "default": 0, "min": -60, "max": 60, "unit": ".1\u00b0C", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 11, "propertyName": "Floor sensor calibration", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Floor sensor calibration", "default": 0, "min": -60, "max": 60, "unit": ".1\u00b0C", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 12, "propertyName": "External sensor calibration", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "External sensor calibration", "default": 0, "min": -60, "max": 60, "unit": ".1\u00b0C", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 13, "propertyName": "Temperature display", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Selects which temperature is shown on the display.", "label": "Temperature display", "default": 0, "min": 0, "max": 1, "states": { "0": "Display setpoint temperature", "1": "Display calculated temperature" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 14, "propertyName": "Button brightness - dimmed state", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Button brightness - dimmed state", "default": 50, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 15, "propertyName": "Button brightness - active state", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Button brightness - active state", "default": 100, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 16, "propertyName": "Display brightness - dimmed state", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Display brightness - dimmed state", "default": 50, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 17, "propertyName": "Display brightness - active state", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Display brightness - active state", "default": 100, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 18, "propertyName": "Temperature report interval", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Temperature report interval", "default": 60, "min": 0, "max": 32767, "unit": "seconds", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 19, "propertyName": "Temperature report hysteresis", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Temperature report hysteresis", "default": 10, "min": 1, "max": 100, "unit": "\u00b0C/10", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 20, "propertyName": "Meter report interval", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Meter report interval", "default": 90, "min": 0, "max": 32767, "unit": "seconds", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 21, "propertyName": "Meter report delta value", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Meter report delta value", "default": 10, "min": 0, "max": 255, "unit": "kWh/10", "valueSize": 1, "format": 1, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535 }, "value": 411 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535 }, "value": 3 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535 }, "value": 515 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "6.7" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["4.0", "3.2"] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" }, "value": 2 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "sdkVersion", "propertyName": "sdkVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": "6.81.6" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkAPIVersion", "propertyName": "applicationFrameworkAPIVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": "4.3.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkBuildNumber", "propertyName": "applicationFrameworkBuildNumber", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": 52445 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceVersion", "propertyName": "hostInterfaceVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": "unused" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceBuildNumber", "propertyName": "hostInterfaceBuildNumber", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolVersion", "propertyName": "zWaveProtocolVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": "6.7.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolBuildNumber", "propertyName": "zWaveProtocolBuildNumber", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": 97 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationVersion", "propertyName": "applicationVersion", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": "4.0.10" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationBuildNumber", "propertyName": "applicationBuildNumber", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": 52445 }, { "endpoint": 1, "commandClass": 64, "commandClassName": "Thermostat Mode", "property": "mode", "propertyName": "mode", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Thermostat mode", "min": 0, "max": 255, "states": { "0": "Off", "1": "Heat" } }, "value": 1 }, { "endpoint": 1, "commandClass": 64, "commandClassName": "Thermostat Mode", "property": "manufacturerData", "propertyName": "manufacturerData", "ccVersion": 3, "metadata": { "type": "any", "readable": true, "writeable": true } }, { "endpoint": 1, "commandClass": 67, "commandClassName": "Thermostat Setpoint", "property": "setpoint", "propertyKey": 1, "propertyName": "setpoint", "propertyKeyName": "Heating", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "ccSpecific": { "setpointType": 1 }, "min": 5, "max": 35, "unit": "\u00b0C" }, "value": 8 }, { "endpoint": 1, "commandClass": 66, "commandClassName": "Thermostat Operating State", "property": "state", "propertyName": "state", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Operating state", "min": 0, "max": 255, "states": { "0": "Idle", "1": "Heating", "2": "Cooling", "3": "Fan Only", "4": "Pending Heat", "5": "Pending Cool", "6": "Vent/Economizer", "7": "Aux Heating", "8": "2nd Stage Heating", "9": "2nd Stage Cooling", "10": "2nd Stage Aux Heat", "11": "3rd Stage Aux Heat" } }, "value": 0 }, { "endpoint": 1, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 65537, "propertyName": "value", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh]", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 }, "unit": "kWh" }, "value": 2422.8 }, { "endpoint": 1, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 66561, "propertyName": "value", "propertyKeyName": "Electric_V_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [V]", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 4 }, "unit": "V" }, "value": 242.1 }, { "endpoint": 2, "commandClass": 32, "commandClassName": "Basic", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Current value", "min": 0, "max": 99 }, "value": 99 }, { "endpoint": 2, "commandClass": 32, "commandClassName": "Basic", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Target value", "min": 0, "max": 99 } }, { "endpoint": 2, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "Air temperature", "propertyName": "Air temperature", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Air temperature", "ccSpecific": { "sensorType": 1, "scale": 0 }, "unit": "\u00b0C" }, "value": 22.5 }, { "endpoint": 2, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "UNKNOWN (0x00)", "propertyName": "UNKNOWN (0x00)", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "UNKNOWN (0x00)", "ccSpecific": { "sensorType": 0, "scale": 0 } }, "value": 23 }, { "endpoint": 3, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "Air temperature", "propertyName": "Air temperature", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Air temperature", "ccSpecific": { "sensorType": 1, "scale": 0 }, "unit": "\u00b0C" }, "value": 0 }, { "endpoint": 3, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "UNKNOWN (0x00)", "propertyName": "UNKNOWN (0x00)", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "UNKNOWN (0x00)", "ccSpecific": { "sensorType": 0, "scale": 0 } }, "value": 0 }, { "endpoint": 3, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "Time", "propertyName": "Time", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Time", "ccSpecific": { "sensorType": 33, "scale": 0 }, "unit": "s" }, "value": 3.2 }, { "endpoint": 4, "commandClass": 49, "commandClassName": "Multilevel Sensor", "property": "Air temperature", "propertyName": "Air temperature", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Air temperature", "ccSpecific": { "sensorType": 1, "scale": 0 }, "unit": "\u00b0C" }, "value": 15.3 } ], "neighbors": [1, 24, 25, 87, 88], "isFrequentListening": false, "maxDataRate": 100000, "supportedDataRates": [40000, 100000], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 5, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 8, "label": "Thermostat" }, "specific": { "key": 6, "label": "General Thermostat V2" }, "mandatorySupportedCCs": [32, 114, 64, 67, 134], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 50, "name": "Meter", "version": 3, "isSecure": false }, { "id": 64, "name": "Thermostat Mode", "version": 3, "isSecure": false }, { "id": 66, "name": "Thermostat Operating State", "version": 1, "isSecure": false }, { "id": 67, "name": "Thermostat Setpoint", "version": 3, "isSecure": false }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": false }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 96, "name": "Multi Channel", "version": 4, "isSecure": false }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 112, "name": "Configuration", "version": 3, "isSecure": false }, { "id": 114, "name": "Manufacturer Specific", "version": 1, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 3, "isSecure": false }, { "id": 142, "name": "Multi Channel Association", "version": 3, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true } ], "interviewStage": "Complete" } zwave-js-server-python-0.63.0/test/fixtures/lock_schlage_be469_state.json000066400000000000000000001450651500374325600264630ustar00rootroot00000000000000{ "nodeId": 20, "index": 0, "status": 4, "ready": true, "deviceClass": { "basic": { "key": 1, "label": "Static Controller" }, "generic": { "key": 2, "label": "Entry Control" }, "specific": { "key": 3, "label": "Secure Keypad Door Lock" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": false, "isFrequentListening": true, "isRouting": true, "maxBaudRate": 40000, "isSecure": true, "version": 4, "isBeaming": true, "manufacturerId": 59, "productId": 20548, "productType": 25409, "firmwareVersion": "113.22", "deviceConfig": { "manufacturerId": 59, "manufacturer": "Allegion", "label": "BE469", "description": "Touchscreen Deadbolt", "devices": [ { "productType": "0x6341", "productId": "0x5044" } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "associations": {}, "paramInformation": { "_map": {} } }, "label": "BE469", "lastSeen": "2023-07-18T15:42:34.701Z", "neighbors": [1, 2, 3, 4, 13], "interviewAttempts": 1, "endpoints": [ { "nodeId": 20, "index": 0, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 3, "label": "Secure Keypad Door Lock" }, "mandatorySupportedCCs": [ 32, 98, 99, 114, 134 ], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 98, "name": "Door Lock", "version": 2, "isSecure": true }, { "id": 99, "name": "User Code", "version": 1, "isSecure": true }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": true }, { "id": 113, "name": "Notification", "version": 3, "isSecure": true }, { "id": 114, "name": "Manufacturer Specific", "version": 1, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 2, "isSecure": false }, { "id": 128, "name": "Battery", "version": 1, "isSecure": true }, { "id": 133, "name": "Association", "version": 1, "isSecure": true }, { "id": 134, "name": "Version", "version": 1, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true } ] } ], "commandClasses": [], "values": [ { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "currentMode", "propertyName": "currentMode", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Current lock mode", "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" } }, "value": 0 }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "targetMode", "propertyName": "targetMode", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Target lock mode", "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" } } }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "outsideHandlesCanOpenDoor", "propertyName": "outsideHandlesCanOpenDoor", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which outside handles can open the door (actual status)" }, "value": [false, false, false, false] }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "insideHandlesCanOpenDoor", "propertyName": "insideHandlesCanOpenDoor", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which inside handles can open the door (actual status)" }, "value": [false, false, false, false] }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "latchStatus", "propertyName": "latchStatus", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the latch" }, "value": "open" }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "boltStatus", "propertyName": "boltStatus", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the bolt" }, "value": "unlocked" }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "doorStatus", "propertyName": "doorStatus", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "The current status of the door" }, "value": "open" }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "lockTimeout", "propertyName": "lockTimeout", "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Seconds until lock mode times out" } }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "operationType", "propertyName": "operationType", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 255, "label": "Lock operation type", "states": { "1": "Constant", "2": "Timed" } }, "value": 1 }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "outsideHandlesCanOpenDoorConfiguration", "propertyName": "outsideHandlesCanOpenDoorConfiguration", "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which outside handles can open the door (configuration)" }, "value": [false, false, false, false] }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "insideHandlesCanOpenDoorConfiguration", "propertyName": "insideHandlesCanOpenDoorConfiguration", "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which inside handles can open the door (configuration)" }, "value": [false, false, false, false] }, { "commandClassName": "Door Lock", "commandClass": 98, "endpoint": 0, "property": "lockTimeoutConfiguration", "propertyName": "lockTimeoutConfiguration", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 65535, "label": "Duration of timed mode in seconds" } }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 1, "propertyName": "userIdStatus", "propertyKeyName": "1", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (1)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 1, "propertyName": "userCode", "propertyKeyName": "1", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (1)" }, "value": "**********" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 2, "propertyName": "userIdStatus", "propertyKeyName": "2", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (2)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 2, "propertyName": "userCode", "propertyKeyName": "2", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (2)" }, "value": "**********" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 3, "propertyName": "userIdStatus", "propertyKeyName": "3", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (3)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 3, "propertyName": "userCode", "propertyKeyName": "3", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (3)" }, "value": "**********" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 4, "propertyName": "userIdStatus", "propertyKeyName": "4", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (4)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 1 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 4, "propertyName": "userCode", "propertyKeyName": "4", "metadata": { "type": "buffer", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (4)" }, "value": "{ \"type\": \"Buffer\", \"data\": [55, 48, 51, 48, 10, 13] }" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 5, "propertyName": "userIdStatus", "propertyKeyName": "5", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (5)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 5, "propertyName": "userCode", "propertyKeyName": "5", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (5)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 6, "propertyName": "userIdStatus", "propertyKeyName": "6", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (6)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 6, "propertyName": "userCode", "propertyKeyName": "6", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (6)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 7, "propertyName": "userIdStatus", "propertyKeyName": "7", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (7)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 7, "propertyName": "userCode", "propertyKeyName": "7", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (7)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 8, "propertyName": "userIdStatus", "propertyKeyName": "8", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (8)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 8, "propertyName": "userCode", "propertyKeyName": "8", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (8)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 9, "propertyName": "userIdStatus", "propertyKeyName": "9", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (9)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 9, "propertyName": "userCode", "propertyKeyName": "9", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (9)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 10, "propertyName": "userIdStatus", "propertyKeyName": "10", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (10)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 10, "propertyName": "userCode", "propertyKeyName": "10", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (10)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 11, "propertyName": "userIdStatus", "propertyKeyName": "11", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (11)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 11, "propertyName": "userCode", "propertyKeyName": "11", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (11)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 12, "propertyName": "userIdStatus", "propertyKeyName": "12", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (12)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 12, "propertyName": "userCode", "propertyKeyName": "12", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (12)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 13, "propertyName": "userIdStatus", "propertyKeyName": "13", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (13)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 13, "propertyName": "userCode", "propertyKeyName": "13", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (13)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 14, "propertyName": "userIdStatus", "propertyKeyName": "14", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (14)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 14, "propertyName": "userCode", "propertyKeyName": "14", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (14)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 15, "propertyName": "userIdStatus", "propertyKeyName": "15", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (15)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 15, "propertyName": "userCode", "propertyKeyName": "15", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (15)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 16, "propertyName": "userIdStatus", "propertyKeyName": "16", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (16)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 16, "propertyName": "userCode", "propertyKeyName": "16", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (16)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 17, "propertyName": "userIdStatus", "propertyKeyName": "17", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (17)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 17, "propertyName": "userCode", "propertyKeyName": "17", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (17)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 18, "propertyName": "userIdStatus", "propertyKeyName": "18", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (18)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 18, "propertyName": "userCode", "propertyKeyName": "18", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (18)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 19, "propertyName": "userIdStatus", "propertyKeyName": "19", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (19)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 19, "propertyName": "userCode", "propertyKeyName": "19", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (19)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 20, "propertyName": "userIdStatus", "propertyKeyName": "20", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (20)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 20, "propertyName": "userCode", "propertyKeyName": "20", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (20)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 21, "propertyName": "userIdStatus", "propertyKeyName": "21", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (21)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 21, "propertyName": "userCode", "propertyKeyName": "21", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (21)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 22, "propertyName": "userIdStatus", "propertyKeyName": "22", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (22)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 22, "propertyName": "userCode", "propertyKeyName": "22", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (22)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 23, "propertyName": "userIdStatus", "propertyKeyName": "23", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (23)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 23, "propertyName": "userCode", "propertyKeyName": "23", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (23)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 24, "propertyName": "userIdStatus", "propertyKeyName": "24", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (24)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 24, "propertyName": "userCode", "propertyKeyName": "24", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (24)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 25, "propertyName": "userIdStatus", "propertyKeyName": "25", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (25)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 25, "propertyName": "userCode", "propertyKeyName": "25", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (25)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 26, "propertyName": "userIdStatus", "propertyKeyName": "26", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (26)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 26, "propertyName": "userCode", "propertyKeyName": "26", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (26)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 27, "propertyName": "userIdStatus", "propertyKeyName": "27", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (27)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 27, "propertyName": "userCode", "propertyKeyName": "27", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (27)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 28, "propertyName": "userIdStatus", "propertyKeyName": "28", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (28)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 28, "propertyName": "userCode", "propertyKeyName": "28", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (28)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 29, "propertyName": "userIdStatus", "propertyKeyName": "29", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (29)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } }, "value": 0 }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 29, "propertyName": "userCode", "propertyKeyName": "29", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (29)" }, "value": "" }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 30, "propertyName": "userIdStatus", "propertyKeyName": "30", "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (30)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 30, "propertyName": "userCode", "propertyKeyName": "30", "metadata": { "type": "string", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (30)" } }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "manufacturerId", "propertyName": "manufacturerId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 59 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productType", "propertyName": "productType", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 25409 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productId", "propertyName": "productId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 20548 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "libraryType", "propertyName": "libraryType", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 6 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "protocolVersion", "propertyName": "protocolVersion", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "3.42" }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "firmwareVersions", "propertyName": "firmwareVersions", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["113.22"] }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "level", "propertyName": "level", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "isLow", "propertyName": "isLow", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 3, "propertyName": "Beeper", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 255, "format": 1, "allowManualEntry": false, "states": { "0": "Disable Beeper", "255": "Enable Beeper" }, "label": "Beeper", "isFromConfig": true, "secret": false, "stateful": true }, "value": 255 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 4, "propertyName": "Vacation Mode", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disable Vacation Mode", "255": "Enable Vacation Mode" }, "label": "Vacation Mode", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 5, "propertyName": "Lock & Leave", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disable Lock & Leave", "255": "Enable Lock & Leave" }, "label": "Lock & Leave", "isFromConfig": true }, "value": 255 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 6, "propertyName": "User Slot Status", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 4, "min": 0, "max": 255, "default": 0, "format": 0, "allowManualEntry": true, "label": "User Slot Status", "description": "User slot status", "isFromConfig": true }, "value": 117440512 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 7, "propertyName": "Lock Specific Alarm Mode", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 3, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Alarm Off", "1": "Alert", "2": "Tamper", "3": "Forced Entry" }, "label": "Lock Specific Alarm Mode", "description": "BE469 Only", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 8, "propertyName": "Lock Specific Alarm Alert Sensitivity", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 5, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Not Supported", "1": "Most Sensitive", "2": "More Sensitive", "3": "Medium Sensitivity", "4": "Less Sensitive", "5": "Least Sensitive" }, "label": "Lock Specific Alarm Alert Sensitivity", "isFromConfig": true }, "value": 3 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 9, "propertyName": "Lock Specific Alarm Tamper Sensitivity", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 5, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Not Supported", "1": "Most Sensitive", "2": "More Sensitive", "3": "Medium Sensitivity", "4": "Less Sensitive", "5": "Least Sensitive" }, "label": "Lock Specific Alarm Tamper Sensitivity", "isFromConfig": true }, "value": 3 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 10, "propertyName": "Lock Specific Alarm Kick Sensitivity", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 5, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Not Supported", "1": "Most Sensitive", "2": "More Sensitive", "3": "Medium Sensitivity", "4": "Less Sensitive", "5": "Least Sensitive" }, "label": "Lock Specific Alarm Kick Sensitivity", "description": "BE469 Only", "isFromConfig": true }, "value": 3 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 11, "propertyName": "Lock Specific Alarm Disable—Local Controls", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disable Local Control", "255": "Enable Local Control" }, "label": "Lock Specific Alarm Disable—Local Controls", "isFromConfig": true }, "value": 255 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 12, "propertyName": "Electronic Transition Count", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 4, "min": 0, "max": 2147483647, "default": 0, "format": 0, "allowManualEntry": true, "label": "Electronic Transition Count", "isFromConfig": true }, "value": 2260 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 13, "propertyName": "Mechanical Transition Count", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 4, "min": 0, "max": 2147483647, "default": 0, "format": 0, "allowManualEntry": true, "label": "Mechanical Transition Count", "isFromConfig": true }, "value": 2166 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 14, "propertyName": "Electronic Failed Count", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 4, "min": 0, "max": 2147483647, "default": 0, "format": 0, "allowManualEntry": true, "label": "Electronic Failed Count", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 15, "propertyName": "Auto Lock", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disable Auto Lock", "255": "Enable Auto Lock" }, "label": "Auto Lock", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 16, "propertyName": "User Code PIN Length", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 4, "max": 8, "default": 4, "format": 0, "allowManualEntry": false, "states": { "4": "Four Digits", "5": "Five Digits", "6": "Six Digits", "7": "Seven Digits", "8": "Eight Digits" }, "label": "User Code PIN Length", "description": "User Code PIN length, a value between 4 and 8 (default 4)", "isFromConfig": true }, "value": 4 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 18, "propertyName": "Get Bootloader Version", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": true, "label": "Get Bootloader Version", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Access Control", "propertyKey": "Lock state", "propertyName": "Access Control", "propertyKeyName": "Lock state", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Lock state", "states": { "0": "idle", "11": "Lock jammed" }, "ccSpecific": { "notificationType": 6 } }, "value": 0 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Access Control", "propertyKey": "Keypad state", "propertyName": "Access Control", "propertyKeyName": "Keypad state", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Keypad state", "states": { "0": "idle", "16": "Keypad temporary disabled" }, "ccSpecific": { "notificationType": 6 } }, "value": 0 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Home Security", "propertyKey": "Sensor status", "propertyName": "Home Security", "propertyKeyName": "Sensor status", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Sensor status", "states": { "0": "idle", "2": "Intrusion" }, "ccSpecific": { "notificationType": 7 } }, "value": 0 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Power Management", "propertyKey": "Battery maintenance status", "propertyName": "Power Management", "propertyKeyName": "Battery maintenance status", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Battery maintenance status", "states": { "0": "idle", "10": "Replace battery soon", "11": "Replace battery now" }, "ccSpecific": { "notificationType": 8 } }, "value": 0 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "System", "propertyKey": "Hardware status", "propertyName": "System", "propertyKeyName": "Hardware status", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Hardware status", "states": { "0": "idle", "1": "System hardware failure" }, "ccSpecific": { "notificationType": 9 } }, "value": 0 } ], "highestSecurityClass": 7 } zwave-js-server-python-0.63.0/test/fixtures/lock_ultraloq_ubolt_pro_state.json000066400000000000000000002110121500374325600300560ustar00rootroot00000000000000{ "nodeId": 34, "index": 0, "installerIcon": 768, "userIcon": 768, "status": 4, "ready": true, "isListening": false, "isRouting": true, "isSecure": true, "manufacturerId": 1106, "productId": 1, "productType": 4, "firmwareVersion": "1.1.3", "zwavePlusVersion": 2, "deviceConfig": { "filename": "/data/db/devices/0x0452/u-bolt-pro-zwave.json", "isEmbedded": true, "manufacturer": "Ultraloq", "manufacturerId": 1106, "label": "U-BOLT-PRO-ZWAVE", "description": "U-Bolt Pro Z-Wave Smart Lock", "devices": [ { "productType": 4, "productId": 1 } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "associations": {}, "metadata": { "inclusion": "Step1\nSet the Z-Wave network main controller or hub into inclusion mode.\n\nStep2\nPress the button 5 on the lock keypad, until you hear beep sound and the indicator light flashes blue. \nIf your Z-Wave hub is Security 2 enabled and requires the Z-Wave QR code or pin code to add the lock automatically, please \ufb01nd it on the back of the battery cover of your smart lock.\n\nStep3\nFollow the instructions of your Z-Wave hub to finish the inclusion process", "exclusion": "Step1\nSet the Z-Wave network main controller or hub into exclusion mode.\n\nStep2\nPress the button 5 on the lock keypad, until you hear the beep sound and the indicator light flashes red. \n\nStep3\nFollow the instructions of your Z-Wave hub to finish the exclusion process", "reset": "CAUTION: Resetting a Z-Wave device without notifying the hub may cause performance problems. Use this procedure only when the Z-Wave hub is missing or otherwise inoperable.\n\nIf you are using U-tec App as Owner, please click \u201cDelete and Reset\u201d to remove the lock from your U-tec Account, then use a Reset Needle to push the Reset Button (at the bottom of Interior Assembly) for around 3 seconds until you hear one long beep and two short beeps.\n\nIf U-Bolt Pro Z-Wave is working as Standalone Mode without the App, please use a Reset Needle to push the Reset Button (at the bottom of Interior Assembly) for around 3 seconds until you hear one long beep and two short beeps.", "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=product_documents/4115/U-Bolt%20Pro%20Z-Wave%20QuickGuide%20V1.4%20\u6210\u54c195x210cm(\u51fa\u884098mmx216mm)%2080g%20\u53cc\u80f6\u7eb8%20\u517142P%20\u9a91\u9a6c\u9489\u88c5\u8ba2.pdf" } }, "label": "U-BOLT-PRO-ZWAVE", "interviewAttempts": 1, "endpoints": [ { "nodeId": 34, "index": 0, "installerIcon": 768, "userIcon": 768, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 1, "label": "Door Lock" }, "mandatorySupportedCCs": [ 32, 118 ], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 118, "name": "Lock", "version": 1, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 85, "name": "Transport Service", "version": 2, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true }, { "id": 159, "name": "Security 2", "version": 1, "isSecure": true }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 134, "name": "Version", "version": 3, "isSecure": true }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": true }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": true }, { "id": 135, "name": "Indicator", "version": 3, "isSecure": true }, { "id": 115, "name": "Powerlevel", "version": 1, "isSecure": true }, { "id": 128, "name": "Battery", "version": 1, "isSecure": true }, { "id": 98, "name": "Door Lock", "version": 4, "isSecure": true }, { "id": 99, "name": "User Code", "version": 1, "isSecure": true }, { "id": 133, "name": "Association", "version": 2, "isSecure": true }, { "id": 142, "name": "Multi Channel Association", "version": 3, "isSecure": true }, { "id": 89, "name": "Association Group Information", "version": 3, "isSecure": true }, { "id": 122, "name": "Firmware Update Meta Data", "version": 5, "isSecure": true } ] } ], "values": [ { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "targetMode", "propertyName": "targetMode", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Target lock mode", "min": 0, "max": 255, "states": { "0": "Unsecured", "255": "Secured" } }, "value": 255 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "operationType", "propertyName": "operationType", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Lock operation type", "min": 0, "max": 255, "states": { "1": "Constant" } }, "value": 1 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "latchStatus", "propertyName": "latchStatus", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Current status of the latch" }, "value": "open" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "boltStatus", "propertyName": "boltStatus", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Current status of the bolt" }, "value": "locked" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoorConfiguration", "propertyName": "outsideHandlesCanOpenDoorConfiguration", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which outside handles can open the door (configuration)" }, "value": [ true, false, false, false ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoorConfiguration", "propertyName": "insideHandlesCanOpenDoorConfiguration", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which inside handles can open the door (configuration)" }, "value": [ false, false, false, false ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "autoRelockTime", "propertyName": "autoRelockTime", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration in seconds until lock returns to secure state", "min": 0, "max": 65535 }, "value": 0 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "holdAndReleaseTime", "propertyName": "holdAndReleaseTime", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration in seconds the latch stays retracted", "min": 0, "max": 65535 }, "value": 0 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "twistAssist", "propertyName": "twistAssist", "ccVersion": 4, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Twist Assist enabled" }, "value": false }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "blockToBlock", "propertyName": "blockToBlock", "ccVersion": 4, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Block-to-block functionality enabled" }, "value": false }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "currentMode", "propertyName": "currentMode", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Current lock mode", "min": 0, "max": 255, "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" } }, "value": 255 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "duration", "propertyName": "duration", "ccVersion": 4, "metadata": { "type": "duration", "readable": true, "writeable": false, "label": "Remaining duration until target lock mode" }, "value": { "value": 0, "unit": "seconds" } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoor", "propertyName": "outsideHandlesCanOpenDoor", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which outside handles can open the door (actual status)" }, "value": [ false, false, false, false ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoor", "propertyName": "insideHandlesCanOpenDoor", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which inside handles can open the door (actual status)" }, "value": [ false, false, false, false ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "doorStatus", "propertyName": "doorStatus", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Current status of the door" } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeoutConfiguration", "propertyName": "lockTimeoutConfiguration", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration of timed mode in seconds", "min": 0, "max": 65535 } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeout", "propertyName": "lockTimeout", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Seconds until lock mode times out", "min": 0, "max": 65535 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 1, "propertyName": "userIdStatus", "propertyKeyName": "1", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (1)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 1, "propertyName": "userCode", "propertyKeyName": "1", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (1)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 2, "propertyName": "userIdStatus", "propertyKeyName": "2", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (2)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 2, "propertyName": "userCode", "propertyKeyName": "2", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (2)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 3, "propertyName": "userIdStatus", "propertyKeyName": "3", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (3)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 3, "propertyName": "userCode", "propertyKeyName": "3", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (3)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 4, "propertyName": "userIdStatus", "propertyKeyName": "4", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (4)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 4, "propertyName": "userCode", "propertyKeyName": "4", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (4)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 5, "propertyName": "userIdStatus", "propertyKeyName": "5", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (5)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 5, "propertyName": "userCode", "propertyKeyName": "5", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (5)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 6, "propertyName": "userIdStatus", "propertyKeyName": "6", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (6)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 6, "propertyName": "userCode", "propertyKeyName": "6", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (6)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 7, "propertyName": "userIdStatus", "propertyKeyName": "7", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (7)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 7, "propertyName": "userCode", "propertyKeyName": "7", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (7)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 8, "propertyName": "userIdStatus", "propertyKeyName": "8", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (8)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 8, "propertyName": "userCode", "propertyKeyName": "8", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (8)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 9, "propertyName": "userIdStatus", "propertyKeyName": "9", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (9)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 9, "propertyName": "userCode", "propertyKeyName": "9", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (9)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 10, "propertyName": "userIdStatus", "propertyKeyName": "10", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (10)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 10, "propertyName": "userCode", "propertyKeyName": "10", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (10)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 11, "propertyName": "userIdStatus", "propertyKeyName": "11", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (11)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 11, "propertyName": "userCode", "propertyKeyName": "11", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (11)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 12, "propertyName": "userIdStatus", "propertyKeyName": "12", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (12)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 12, "propertyName": "userCode", "propertyKeyName": "12", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (12)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 13, "propertyName": "userIdStatus", "propertyKeyName": "13", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (13)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 13, "propertyName": "userCode", "propertyKeyName": "13", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (13)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 14, "propertyName": "userIdStatus", "propertyKeyName": "14", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (14)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 14, "propertyName": "userCode", "propertyKeyName": "14", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (14)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 15, "propertyName": "userIdStatus", "propertyKeyName": "15", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (15)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 15, "propertyName": "userCode", "propertyKeyName": "15", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (15)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 16, "propertyName": "userIdStatus", "propertyKeyName": "16", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (16)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 16, "propertyName": "userCode", "propertyKeyName": "16", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (16)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 17, "propertyName": "userIdStatus", "propertyKeyName": "17", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (17)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 17, "propertyName": "userCode", "propertyKeyName": "17", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (17)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 18, "propertyName": "userIdStatus", "propertyKeyName": "18", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (18)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 18, "propertyName": "userCode", "propertyKeyName": "18", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (18)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 19, "propertyName": "userIdStatus", "propertyKeyName": "19", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (19)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 19, "propertyName": "userCode", "propertyKeyName": "19", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (19)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 20, "propertyName": "userIdStatus", "propertyKeyName": "20", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (20)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 20, "propertyName": "userCode", "propertyKeyName": "20", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (20)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 21, "propertyName": "userIdStatus", "propertyKeyName": "21", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (21)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 21, "propertyName": "userCode", "propertyKeyName": "21", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (21)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 22, "propertyName": "userIdStatus", "propertyKeyName": "22", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (22)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 22, "propertyName": "userCode", "propertyKeyName": "22", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (22)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 23, "propertyName": "userIdStatus", "propertyKeyName": "23", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (23)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 23, "propertyName": "userCode", "propertyKeyName": "23", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (23)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 24, "propertyName": "userIdStatus", "propertyKeyName": "24", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (24)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 24, "propertyName": "userCode", "propertyKeyName": "24", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (24)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 25, "propertyName": "userIdStatus", "propertyKeyName": "25", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (25)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 25, "propertyName": "userCode", "propertyKeyName": "25", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (25)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 26, "propertyName": "userIdStatus", "propertyKeyName": "26", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (26)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 26, "propertyName": "userCode", "propertyKeyName": "26", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (26)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 27, "propertyName": "userIdStatus", "propertyKeyName": "27", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (27)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 27, "propertyName": "userCode", "propertyKeyName": "27", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (27)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 28, "propertyName": "userIdStatus", "propertyKeyName": "28", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (28)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 28, "propertyName": "userCode", "propertyKeyName": "28", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (28)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 29, "propertyName": "userIdStatus", "propertyKeyName": "29", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (29)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 29, "propertyName": "userCode", "propertyKeyName": "29", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (29)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 30, "propertyName": "userIdStatus", "propertyKeyName": "30", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (30)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 30, "propertyName": "userCode", "propertyKeyName": "30", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (30)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 31, "propertyName": "userIdStatus", "propertyKeyName": "31", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (31)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 31, "propertyName": "userCode", "propertyKeyName": "31", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (31)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 32, "propertyName": "userIdStatus", "propertyKeyName": "32", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (32)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 32, "propertyName": "userCode", "propertyKeyName": "32", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (32)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 33, "propertyName": "userIdStatus", "propertyKeyName": "33", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (33)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 33, "propertyName": "userCode", "propertyKeyName": "33", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (33)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 34, "propertyName": "userIdStatus", "propertyKeyName": "34", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (34)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 34, "propertyName": "userCode", "propertyKeyName": "34", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (34)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 35, "propertyName": "userIdStatus", "propertyKeyName": "35", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (35)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 35, "propertyName": "userCode", "propertyKeyName": "35", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (35)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 36, "propertyName": "userIdStatus", "propertyKeyName": "36", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (36)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 36, "propertyName": "userCode", "propertyKeyName": "36", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (36)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 37, "propertyName": "userIdStatus", "propertyKeyName": "37", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (37)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 37, "propertyName": "userCode", "propertyKeyName": "37", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (37)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 38, "propertyName": "userIdStatus", "propertyKeyName": "38", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (38)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 38, "propertyName": "userCode", "propertyKeyName": "38", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (38)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 39, "propertyName": "userIdStatus", "propertyKeyName": "39", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (39)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 39, "propertyName": "userCode", "propertyKeyName": "39", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (39)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 40, "propertyName": "userIdStatus", "propertyKeyName": "40", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (40)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 40, "propertyName": "userCode", "propertyKeyName": "40", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (40)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 41, "propertyName": "userIdStatus", "propertyKeyName": "41", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (41)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 41, "propertyName": "userCode", "propertyKeyName": "41", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (41)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 42, "propertyName": "userIdStatus", "propertyKeyName": "42", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (42)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 42, "propertyName": "userCode", "propertyKeyName": "42", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (42)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 43, "propertyName": "userIdStatus", "propertyKeyName": "43", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (43)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 43, "propertyName": "userCode", "propertyKeyName": "43", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (43)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 44, "propertyName": "userIdStatus", "propertyKeyName": "44", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (44)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 44, "propertyName": "userCode", "propertyKeyName": "44", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (44)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 45, "propertyName": "userIdStatus", "propertyKeyName": "45", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (45)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 45, "propertyName": "userCode", "propertyKeyName": "45", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (45)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 46, "propertyName": "userIdStatus", "propertyKeyName": "46", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (46)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 46, "propertyName": "userCode", "propertyKeyName": "46", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (46)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 47, "propertyName": "userIdStatus", "propertyKeyName": "47", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (47)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 47, "propertyName": "userCode", "propertyKeyName": "47", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (47)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 48, "propertyName": "userIdStatus", "propertyKeyName": "48", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (48)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 48, "propertyName": "userCode", "propertyKeyName": "48", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (48)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userIdStatus", "propertyKey": 49, "propertyName": "userIdStatus", "propertyKeyName": "49", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "User ID status (49)", "states": { "0": "Available", "1": "Enabled", "2": "Disabled" } } }, { "endpoint": 0, "commandClass": 99, "commandClassName": "User Code", "property": "userCode", "propertyKey": 49, "propertyName": "userCode", "propertyKeyName": "49", "ccVersion": 1, "metadata": { "type": "string", "readable": true, "writeable": true, "label": "User Code (49)", "minLength": 4, "maxLength": 10 } }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535 }, "value": 1106 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535 }, "value": 4 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535 }, "value": 1 }, { "endpoint": 0, "commandClass": 118, "commandClassName": "Lock", "property": "locked", "propertyName": "locked", "ccVersion": 0, "metadata": { "type": "boolean", "readable": true, "writeable": true, "description": "Whether the lock is locked", "label": "Locked" } }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "level", "propertyName": "level", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Battery level", "min": 0, "max": 100, "unit": "%" }, "value": 100 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "isLow", "propertyName": "isLow", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Library type", "states": { "0": "Unknown", "1": "Static Controller", "2": "Controller", "3": "Enhanced Slave", "4": "Slave", "5": "Installer", "6": "Routing Slave", "7": "Bridge Controller", "8": "Device under Test", "9": "N/A", "10": "AV Remote", "11": "AV Device" } }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "7.14" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 3, "metadata": { "type": "string[]", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": [ "1.1" ] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" }, "value": 1 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "sdkVersion", "propertyName": "sdkVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "SDK version" }, "value": "7.14.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkAPIVersion", "propertyName": "applicationFrameworkAPIVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API version" }, "value": "10.14.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkBuildNumber", "propertyName": "applicationFrameworkBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API build number" }, "value": 298 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceVersion", "propertyName": "hostInterfaceVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API version" }, "value": "unused" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceBuildNumber", "propertyName": "hostInterfaceBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API build number" }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolVersion", "propertyName": "zWaveProtocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "7.14.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolBuildNumber", "propertyName": "zWaveProtocolBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol build number" }, "value": 298 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationVersion", "propertyName": "applicationVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application version" }, "value": "1.1.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationBuildNumber", "propertyName": "applicationBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application build number" }, "value": 43707 }, { "endpoint": 0, "commandClass": 135, "commandClassName": "Indicator", "property": 80, "propertyKey": 3, "propertyName": "Node Identify", "propertyKeyName": "On/Off Period: Duration", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Sets the duration of an on/off period in 1/10th seconds. Must be set together with \"On/Off Cycle Count\"", "label": "Node Identify - On/Off Period: Duration", "ccSpecific": { "indicatorId": 80, "propertyId": 3 } }, "value": 0 }, { "endpoint": 0, "commandClass": 135, "commandClassName": "Indicator", "property": 80, "propertyKey": 4, "propertyName": "Node Identify", "propertyKeyName": "On/Off Cycle Count", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Sets the number of on/off periods. 0xff means infinite. Must be set together with \"On/Off Period duration\"", "label": "Node Identify - On/Off Cycle Count", "ccSpecific": { "indicatorId": 80, "propertyId": 4 } }, "value": 0 }, { "endpoint": 0, "commandClass": 135, "commandClassName": "Indicator", "property": 80, "propertyKey": 5, "propertyName": "Node Identify", "propertyKeyName": "On/Off Period: On time", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "This property is used to set the length of the On time during an On/Off period. It allows asymmetric On/Off periods. The value 0x00 MUST represent symmetric On/Off period (On time equal to Off time)", "label": "Node Identify - On/Off Period: On time", "ccSpecific": { "indicatorId": 80, "propertyId": 5 } }, "value": 0 }, { "endpoint": 0, "commandClass": 135, "commandClassName": "Indicator", "property": "value", "propertyName": "value", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Indicator value", "ccSpecific": { "indicatorId": 0 }, "min": 0, "max": 255 } } ], "isFrequentListening": "1000ms", "maxDataRate": 100000, "supportedDataRates": [ 40000, 100000 ], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 7, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 1, "label": "Door Lock" }, "mandatorySupportedCCs": [ 32, 118 ], "mandatoryControlledCCs": [] }, "interviewStage": "Complete", "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0x0452:0x0004:0x0001:1.1.3", "statistics": { "commandsTX": 57, "commandsRX": 56, "commandsDroppedRX": 2, "commandsDroppedTX": 0, "timeoutResponse": 1, "rtt": 29.1, "rssi": -71, "lwr": { "protocolDataRate": 2, "repeaters": [], "rssi": -71, "repeaterRSSI": [] } }, "highestSecurityClass": 2, "isControllerNode": false, "keepAwake": false }zwave-js-server-python-0.63.0/test/fixtures/multisensor_6_state.json000066400000000000000000001344031500374325600257370ustar00rootroot00000000000000{ "nodeId": 52, "index": 0, "installerIcon": 3079, "userIcon": 3079, "status": 1, "ready": true, "deviceClass": { "basic": { "key": 1, "label": "Static Controller" }, "generic": { "key": 2, "label": "Multilevel Sensor" }, "specific": { "key": 3, "label": "Routing Multilevel Sensor" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": true, "isFrequentListening": false, "isRouting": true, "maxBaudRate": 40000, "isSecure": false, "version": 4, "isBeaming": true, "manufacturerId": 134, "productId": 100, "productType": 258, "firmwareVersion": "1.12", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 5, "deviceConfig": { "manufacturerId": 134, "manufacturer": "AEON Labs", "label": "ZW100", "description": "Multisensor 6", "devices": [ { "productType": "0x0002", "productId": "0x0064" }, { "productType": "0x0102", "productId": "0x0064" }, { "productType": "0x0202", "productId": "0x0064" } ], "firmwareVersion": { "min": "1.10", "max": "255.255" }, "paramInformation": { "_map": {} } }, "label": "ZW100", "neighbors": [1, 32], "interviewAttempts": 1, "keepAwake": true, "endpoints": [ { "nodeId": 52, "index": 0, "installerIcon": 3079, "userIcon": 3079 } ], "commandClasses": [], "values": [ { "commandClassName": "Basic", "commandClass": 32, "endpoint": 0, "property": "currentValue", "propertyName": "currentValue", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 99, "label": "Current value" }, "value": 255 }, { "commandClassName": "Basic", "commandClass": 32, "endpoint": 0, "property": "targetValue", "propertyName": "targetValue", "metadata": { "type": "number", "readable": true, "writeable": true, "min": 0, "max": 99, "label": "Target value", "valueChangeOptions": ["transitionDuration"] } }, { "commandClassName": "Binary Sensor", "commandClass": 48, "endpoint": 0, "property": "Any", "propertyName": "Any", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Any", "ccSpecific": { "sensorType": 255 } }, "value": false }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 0, "property": "Air temperature", "propertyName": "Air temperature", "metadata": { "type": "number", "readable": true, "writeable": false, "unit": "°C", "label": "Air temperature", "ccSpecific": { "sensorType": 1, "scale": 0 } }, "value": 9 }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 0, "property": "Illuminance", "propertyName": "Illuminance", "metadata": { "type": "number", "readable": true, "writeable": false, "unit": "Lux", "label": "Illuminance", "ccSpecific": { "sensorType": 3, "scale": 1 } }, "value": 0 }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 0, "property": "Humidity", "propertyName": "Humidity", "metadata": { "type": "number", "readable": true, "writeable": false, "unit": "%", "label": "Humidity", "ccSpecific": { "sensorType": 5, "scale": 0 } }, "value": 65 }, { "commandClassName": "Multilevel Sensor", "commandClass": 49, "endpoint": 0, "property": "Ultraviolet", "propertyName": "Ultraviolet", "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Ultraviolet", "ccSpecific": { "sensorType": 27, "scale": 0 } }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 2, "propertyName": "Stay Awake in Battery Mode", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Stay Awake in Battery Mode", "description": "Stay awake for 10 minutes at power on", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 3, "propertyName": "Motion Sensor reset timeout", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 10, "max": 3600, "default": 240, "format": 0, "allowManualEntry": true, "label": "Motion Sensor reset timeout", "description": "Motion Sensor reset timeout", "isFromConfig": true }, "value": 240 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 4, "propertyName": "Motion sensor sensitivity", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 5, "format": 1, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable, sensitivity level 1 (minimum)", "2": "Enable, sensitivity level 2", "3": "Enable, sensitivity level 3", "4": "Enable, sensitivity level 4", "5": "Enable, sensitivity level 5 (maximum)" }, "label": "Motion sensor sensitivity", "description": "Sensitivity level of PIR sensor (1=minimum, 5=maximum)", "isFromConfig": true }, "value": 5 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 5, "propertyName": "Motion Sensor Triggered Command", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 1, "format": 1, "allowManualEntry": false, "states": { "1": "Send Basic Set CC", "2": "Send Sensor Binary Report CC" }, "label": "Motion Sensor Triggered Command", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 8, "propertyName": "Timeout after wake up", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 8, "max": 255, "default": 30, "format": 1, "allowManualEntry": true, "label": "Timeout after wake up", "description": "Set the timeout of awake after the Wake Up CC is sent out...", "isFromConfig": true }, "value": 15 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 39, "propertyName": "Low Battery Report", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 10, "max": 50, "default": 20, "format": 0, "allowManualEntry": true, "label": "Low Battery Report", "description": "Report Low Battery if below this value", "isFromConfig": true }, "value": 20 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 40, "propertyName": "Selective Reporting", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Selective Reporting", "description": "Select to report on thresholds", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 42, "propertyName": "Humidity Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 10, "format": 0, "allowManualEntry": true, "label": "Humidity Threshold", "description": "Humidity percent change threshold", "isFromConfig": true }, "value": 10 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 43, "propertyName": "Luminance Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 1000, "default": 100, "format": 0, "allowManualEntry": true, "label": "Luminance Threshold", "description": "Luminance change threshold", "isFromConfig": true }, "value": 100 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 44, "propertyName": "Battery Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 10, "format": 0, "allowManualEntry": true, "label": "Battery Threshold", "description": "Battery level threshold", "isFromConfig": true }, "value": 10 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 45, "propertyName": "Ultraviolet Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 2, "format": 0, "allowManualEntry": true, "label": "Ultraviolet Threshold", "description": "Ultraviolet change threshold", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 46, "propertyName": "Send Alarm Report if low temperature", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Send Alarm Report if low temperature", "description": "Send an alarm report if temperature is less than -15 °C", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 48, "propertyName": "Send a report if the measurement is out of limits", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": true, "label": "Send a report if the measurement is out of limits", "description": "Send report when measurement is at upper/lower limit", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 51, "propertyName": "Upper limit value of humidity sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 60, "format": 0, "allowManualEntry": true, "label": "Upper limit value of humidity sensor", "description": "Upper limit value of humidity sensor", "isFromConfig": true }, "value": 60 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 52, "propertyName": "Lower limit value of humidity sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 100, "default": 50, "format": 0, "allowManualEntry": true, "label": "Lower limit value of humidity sensor", "description": "Lower limit value of humidity sensor", "isFromConfig": true }, "value": 50 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 53, "propertyName": "Upper limit value of Lighting sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 30000, "default": 1000, "format": 0, "allowManualEntry": true, "label": "Upper limit value of Lighting sensor", "description": "Upper limit value of Lighting sensor", "isFromConfig": true }, "value": 1000 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 54, "propertyName": "Lower limit value of Lighting sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 30000, "default": 100, "format": 0, "allowManualEntry": true, "label": "Lower limit value of Lighting sensor", "description": "Lower limit value of Lighting sensor", "isFromConfig": true }, "value": 100 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 55, "propertyName": "Upper limit value of ultraviolet sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 11, "default": 8, "format": 0, "allowManualEntry": true, "label": "Upper limit value of ultraviolet sensor", "description": "Upper limit value of ultraviolet sensor", "isFromConfig": true }, "value": 8 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 56, "propertyName": "Lower limit value of ultraviolet sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 11, "default": 4, "format": 0, "allowManualEntry": true, "label": "Lower limit value of ultraviolet sensor", "description": "Lower limit value of ultraviolet sensor", "isFromConfig": true }, "value": 4 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 57, "propertyName": "Recover limit value of temperature sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 0, "max": 65535, "default": 0, "format": 1, "allowManualEntry": true, "label": "Recover limit value of temperature sensor", "description": "Recover limit value of temperature sensor", "isFromConfig": true }, "value": 5122 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 58, "propertyName": "Recover limit value of humidity sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 50, "default": 5, "format": 0, "allowManualEntry": true, "label": "Recover limit value of humidity sensor", "description": "Recover limit value of humidity sensor", "isFromConfig": true }, "value": 5 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 59, "propertyName": "Recover limit value of Lighting sensor.", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 255, "default": 10, "format": 1, "allowManualEntry": true, "label": "Recover limit value of Lighting sensor.", "description": "Recover limit value of Lighting sensor.", "isFromConfig": true }, "value": 10 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 60, "propertyName": "Recover limit value of Ultraviolet sensor", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 5, "default": 2, "format": 0, "allowManualEntry": true, "label": "Recover limit value of Ultraviolet sensor", "description": "Recover limit value of Ultraviolet sensor", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 61, "propertyName": "Out-of-limit state of the Sensors", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 1, "min": 0, "max": 255, "default": 0, "format": 1, "allowManualEntry": true, "label": "Out-of-limit state of the Sensors", "description": "Out-of-limit state of the Sensors", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 64, "propertyName": "Default unit of the automatic temperature report", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": true, "label": "Default unit of the automatic temperature report", "description": "Default unit of the automatic temperature report", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 81, "propertyName": "LED function", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 2, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Enable LED blinking", "1": "Disable PIR LED", "2": "Disable ALL" }, "label": "LED function", "description": "Disable/Enable LED function", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 111, "propertyName": "Group 1 Report Interval", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 5, "max": 2678400, "default": 3600, "format": 0, "allowManualEntry": true, "label": "Group 1 Report Interval", "description": "How often to update Group 1", "isFromConfig": true }, "value": 3600 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 112, "propertyName": "Group 2 Report Interval", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 5, "max": 2678400, "default": 3600, "format": 0, "allowManualEntry": true, "label": "Group 2 Report Interval", "description": "Group 2 Report Interval", "isFromConfig": true }, "value": 3600 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 113, "propertyName": "Group 3 Report Interval", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 5, "max": 2678400, "default": 3600, "format": 0, "allowManualEntry": true, "label": "Group 3 Report Interval", "description": "Group 3 Report Interval", "isFromConfig": true }, "value": 3600 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 202, "propertyName": "Humidity Sensor Calibration", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": -50, "max": 50, "default": 0, "format": 0, "allowManualEntry": true, "label": "Humidity Sensor Calibration", "description": "Humidity Sensor Calibration", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 203, "propertyName": "Luminance Sensor Calibration", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": -1000, "max": 1000, "default": 0, "format": 0, "allowManualEntry": true, "label": "Luminance Sensor Calibration", "description": "Luminance Sensor Calibration", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 204, "propertyName": "Ultraviolet Sensor Calibration", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": -10, "max": 10, "default": 0, "format": 0, "allowManualEntry": true, "label": "Ultraviolet Sensor Calibration", "description": "Ultraviolet Sensor Calibration", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 252, "propertyName": "Disable/Enable Configuration Lock", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Disable/Enable Configuration Lock", "description": "Disable/Enable Configuration Lock (0=Disable, 1=Enable)", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 101, "propertyKey": 1, "propertyName": "Group 1: Send battery reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 1: Send battery reports", "description": "Include battery information in periodic reports to Group 1", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 101, "propertyKey": 16, "propertyName": "Group 1: Send ultraviolet reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 1: Send ultraviolet reports", "description": "Include ultraviolet information in periodic reports to Group 1", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 101, "propertyKey": 32, "propertyName": "Group 1: Send temperature reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 1: Send temperature reports", "description": "Include temperature information in periodic reports to Group 1", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 101, "propertyKey": 64, "propertyName": "Group 1: Send humidity reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 1: Send humidity reports", "description": "Include humidity information in periodic reports to Group 1", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 101, "propertyKey": 128, "propertyName": "Group 1: Send luminance reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 1: Send luminance reports", "description": "Include luminance information in periodic reports to Group 1", "isFromConfig": true }, "value": 1 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyKey": 1, "propertyName": "Group 2: Send battery reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyKey": 16, "propertyName": "Group 2: Send ultraviolet reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 2: Send ultraviolet reports", "description": "Include ultraviolet information in periodic reports to Group 2", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyKey": 32, "propertyName": "Group 2: Send temperature reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 2: Send temperature reports", "description": "Include temperature information in periodic reports to Group 2", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyKey": 64, "propertyName": "Group 2: Send humidity reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 2: Send humidity reports", "description": "Include humidity information in periodic reports to Group 2", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyKey": 128, "propertyName": "Group 2: Send luminance reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 2: Send luminance reports", "description": "Include luminance information in periodic reports to Group 2", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 103, "propertyKey": 1, "propertyName": "Group 3: Send battery reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 3: Send battery reports", "description": "Include battery information in periodic reports to Group 3", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 103, "propertyKey": 16, "propertyName": "Group 3: Send ultraviolet reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 3: Send ultraviolet reports", "description": "Include ultraviolet information in periodic reports to Group 3", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 103, "propertyKey": 32, "propertyName": "Group 3: Send temperature reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 3: Send temperature reports", "description": "Include temperature information in periodic reports to Group 3", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 103, "propertyKey": 64, "propertyName": "Group 3: Send humidity reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 3: Send humidity reports", "description": "Include humidity information in periodic reports to Group 3", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 103, "propertyKey": 128, "propertyName": "Group 3: Send luminance reports", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": true, "label": "Group 3: Send luminance reports", "description": "Include luminance information in periodic reports to Group 3", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 9, "propertyKey": 1, "propertyName": "Sleep State", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 2, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Asleep", "1": "Awake" }, "label": "Sleep State", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 9, "propertyKey": 256, "propertyName": "Power Mode", "metadata": { "type": "number", "readable": true, "writeable": false, "valueSize": 2, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "USB", "1": "Battery" }, "label": "Power Mode", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 41, "propertyKey": 15, "propertyName": "Temperature Threshold (Unit)", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 3, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": false, "states": { "1": "Celsius", "2": "Fahrenheit" }, "label": "Temperature Threshold (Unit)", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 41, "propertyKey": 16776960, "propertyName": "Temperature Threshold", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 3, "min": 0, "max": 100, "default": 20, "format": 0, "allowManualEntry": true, "label": "Temperature Threshold", "description": "Threshold change in temperature to induce an automatic report.", "isFromConfig": true }, "value": 5122 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 49, "propertyKey": 65280, "propertyName": "Upper temperature limit (Unit)", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 4, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": false, "states": { "1": "Celsius", "2": "Fahrenheit" }, "label": "Upper temperature limit (Unit)", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 49, "propertyKey": 4294901760, "propertyName": "Upper temperature limit", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": -400, "max": 2120, "default": 280, "format": 0, "allowManualEntry": true, "label": "Upper temperature limit", "isFromConfig": true }, "value": 824 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 50, "propertyKey": 65280, "propertyName": "Lower temperature limit (Unit)", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 4, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": false, "states": { "1": "Celsius", "2": "Fahrenheit" }, "label": "Lower temperature limit (Unit)", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 50, "propertyKey": 4294901760, "propertyName": "Lower temperature limit", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 4, "min": -400, "max": 2120, "default": 0, "format": 0, "allowManualEntry": true, "label": "Lower temperature limit", "isFromConfig": true }, "value": 320 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 201, "propertyKey": 255, "propertyName": "Temperature Calibration (Unit)", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": false, "states": { "1": "Celsius", "2": "Fahrenheit" }, "label": "Temperature Calibration (Unit)", "isFromConfig": true }, "value": 2 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 201, "propertyKey": 65280, "propertyName": "Temperature Calibration", "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 2, "min": -127, "max": 127, "default": 0, "format": 0, "allowManualEntry": true, "label": "Temperature Calibration", "isFromConfig": true }, "value": 0 }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 100, "propertyName": "Set parameters 101-103 to default.", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": true, "label": "Set parameters 101-103 to default.", "description": "Reset 101-103 to defaults", "isFromConfig": true } }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 110, "propertyName": "Set parameters 111-113 to default.", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": true, "label": "Set parameters 111-113 to default.", "description": "Set parameters 111-113 to default.", "isFromConfig": true } }, { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 255, "propertyName": "Reset to default factory settings", "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 4, "min": 0, "max": 1431655765, "default": 0, "format": 0, "allowManualEntry": false, "states": { "1": "Resets all configuration parameters to defaults", "1431655765": "Reset to default factory settings and be excluded" }, "label": "Reset to default factory settings", "isFromConfig": true } }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Home Security", "propertyKey": "Cover status", "propertyName": "Home Security", "propertyKeyName": "Cover status", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Cover status", "states": { "0": "idle", "3": "Tampering, product cover removed" }, "ccSpecific": { "notificationType": 7 } }, "value": 0 }, { "commandClassName": "Notification", "commandClass": 113, "endpoint": 0, "property": "Home Security", "propertyKey": "Motion sensor status", "propertyName": "Home Security", "propertyKeyName": "Motion sensor status", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Motion sensor status", "states": { "0": "idle", "8": "Motion detection" }, "ccSpecific": { "notificationType": 7 } }, "value": 8 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "manufacturerId", "propertyName": "manufacturerId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 134 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productType", "propertyName": "productType", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 258 }, { "commandClassName": "Manufacturer Specific", "commandClass": 114, "endpoint": 0, "property": "productId", "propertyName": "productId", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 100 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "level", "propertyName": "level", "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "commandClassName": "Battery", "commandClass": 128, "endpoint": 0, "property": "isLow", "propertyName": "isLow", "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "commandClassName": "Wake Up", "commandClass": 132, "endpoint": 0, "property": "wakeUpInterval", "propertyName": "wakeUpInterval", "metadata": { "type": "number", "readable": false, "writeable": true, "min": 240, "max": 3600, "label": "Wake Up interval", "steps": 60, "default": 3600 }, "value": 3600 }, { "commandClassName": "Wake Up", "commandClass": 132, "endpoint": 0, "property": "controllerNodeId", "propertyName": "controllerNodeId", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Node ID of the controller" }, "value": 1 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "libraryType", "propertyName": "libraryType", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Libary type" }, "value": 3 }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "protocolVersion", "propertyName": "protocolVersion", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "4.54" }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "firmwareVersions", "propertyName": "firmwareVersions", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["1.12"] }, { "commandClassName": "Version", "commandClass": 134, "endpoint": 0, "property": "hardwareVersion", "propertyName": "hardwareVersion", "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } } ] } zwave-js-server-python-0.63.0/test/fixtures/partial_and_full_parameter_state.json000066400000000000000000000521211500374325600304620ustar00rootroot00000000000000{ "nodeId": 32, "index": 0, "installerIcon": 1793, "userIcon": 1793, "status": 4, "ready": true, "isListening": true, "isRouting": true, "isSecure": false, "manufacturerId": 798, "productId": 1, "productType": 2, "firmwareVersion": "1.9", "zwavePlusVersion": 1, "deviceConfig": { "filename": "/usr/src/app/node_modules/@zwave-js/config/config/devices/0x031e/lzw30-sn.json", "manufacturer": "Inovelli", "manufacturerId": 798, "label": "LZW30-SN", "description": "Red Series On/Off Switch", "devices": [{ "productType": 2, "productId": 1 }], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} } }, "label": "LZW30-SN", "neighbors": [ 1, 10, 11, 14, 15, 16, 19, 20, 22, 26, 27, 28, 29, 31, 33, 36, 38, 39, 41, 42, 6, 8, 9 ], "interviewAttempts": 0, "interviewStage": "Neighbors", "endpoints": [{ "nodeId": 32, "index": 0, "installerIcon": 1793, "userIcon": 1793, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 16, "label": "Binary Switch" }, "specific": { "key": 1, "label": "Binary Power Switch" }, "mandatorySupportedCCs": [ 32, 37, 39 ], "mandatoryControlledCCs": [] } }], "values": [{ "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Current value" }, "value": false }, { "endpoint": 0, "commandClass": 37, "commandClassName": "Binary Switch", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Target value" }, "value": true }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 65537, "propertyName": "value", "propertyKeyName": "Electric_kWh_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh]", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 }, "unit": "kWh" }, "value": 7.384 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 65537, "propertyName": "previousValue", "propertyKeyName": "65537", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. value)", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 }, "unit": "kWh" }, "value": 7.202 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 65537, "propertyName": "deltaTime", "propertyKeyName": "65537", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [kWh] (prev. time delta)", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 0 }, "unit": "s" }, "value": 3600 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "value", "propertyKey": 66049, "propertyName": "value", "propertyKeyName": "Electric_W_Consumed", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W]", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 }, "unit": "W" }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "deltaTime", "propertyKey": 66049, "propertyName": "deltaTime", "propertyKeyName": "66049", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. time delta)", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 }, "unit": "s" }, "value": 0 }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "previousValue", "propertyKey": 66049, "propertyName": "previousValue", "propertyKeyName": "66049", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Electric Consumed [W] (prev. value)", "ccSpecific": { "meterType": 1, "rateType": 1, "scale": 2 }, "unit": "W" } }, { "endpoint": 0, "commandClass": 50, "commandClassName": "Meter", "property": "reset", "propertyName": "reset", "ccVersion": 3, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Reset accumulated values" } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "slowRefresh", "propertyName": "slowRefresh", "ccVersion": 3, "metadata": { "type": "boolean", "readable": true, "writeable": true, "description": "When this is true, KeyHeldDown notifications are sent every 55s. When this is false, the notifications are sent every 200ms.", "label": "Send held down notifications at a slow rate" } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "001", "propertyName": "scene", "propertyKeyName": "001", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Scene 001", "min": 0, "max": 255, "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x", "5": "KeyPressed4x", "6": "KeyPressed5x" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "002", "propertyName": "scene", "propertyKeyName": "002", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Scene 002", "min": 0, "max": 255, "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x", "5": "KeyPressed4x", "6": "KeyPressed5x" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "003", "propertyName": "scene", "propertyKeyName": "003", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Scene 003", "min": 0, "max": 255, "states": { "0": "KeyPressed" } } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 1, "propertyName": "Power On State", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Power On State", "default": 0, "min": 0, "max": 2, "states": { "0": "Prior State", "1": "On", "2": "Off" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 2, "propertyName": "Invert Switch", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Invert Switch", "default": 0, "min": 0, "max": 1, "states": { "0": "Disabled", "1": "Enabled" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "Auto Off Timer", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Auto Off Timer", "default": 0, "min": 0, "max": 32767, "unit": "seconds", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Association Behavior", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Association Behavior", "default": 15, "min": 0, "max": 15, "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 15 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 5, "propertyName": "LED Indicator Color", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Uses a scaled hue value (realHue / 360 * 255).", "label": "LED Indicator Color", "default": 170, "min": 0, "max": 255, "states": { "0": "Red", "21": "Orange", "42": "Yellow", "85": "Green", "127": "Cyan", "170": "Blue", "212": "Violet", "234": "Pink" }, "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 234 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 6, "propertyName": "LED Indicator Brightness", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Indicator Brightness", "default": 5, "min": 0, "max": 10, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 7, "propertyName": "LED Indicator Brightness When Off", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Indicator Brightness When Off", "default": 1, "min": 0, "max": 10, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 9, "propertyName": "LED Strip Timeout", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Strip Timeout", "default": 0, "min": 0, "max": 10, "states": { "0": "Stay Off", "1": "One Second", "2": "Two Seconds", "3": "Three Seconds", "4": "Four Seconds", "5": "Five Seconds", "6": "Six Seconds", "7": "Seven Seconds", "8": "Eight Seconds", "9": "Nine Seconds", "10": "Ten Seconds" }, "unit": "seconds", "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 3 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 10, "propertyName": "Active Power Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Active Power Reports", "default": 10, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 11, "propertyName": "Periodic Power & Energy Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Periodic Power & Energy Reports", "default": 3600, "min": 0, "max": 32767, "unit": "seconds", "valueSize": 2, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 3600 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 12, "propertyName": "Energy Reports", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Energy Reports", "default": 10, "min": 0, "max": 100, "unit": "%", "valueSize": 1, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 255, "propertyName": "LED Effect Color", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Uses a scaled hue value (realHue / 360 * 255).", "label": "LED Effect Color", "default": 0, "min": 0, "max": 255, "states": { "0": "Red", "21": "Orange", "42": "Yellow", "85": "Green", "127": "Cyan", "170": "Blue", "212": "Violet", "234": "Pink" }, "valueSize": 4, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 70 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 65280, "propertyName": "LED Effect Brightness", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Effect Brightness", "default": 3, "min": 0, "max": 10, "states": { "0": "Off", "1": "10%", "2": "20%", "3": "30%", "4": "40%", "5": "50%", "6": "60%", "7": "70%", "8": "80%", "9": "90%", "10": "100%" }, "valueSize": 4, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 10 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 16711680, "propertyName": "LED Effect Duration", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "1 to 60 = seconds, 61 to 120 = minutes (minus 60), 121 - 254 = hours (minus 120), 255 = indefinitely", "label": "LED Effect Duration", "default": 255, "min": 0, "max": 255, "valueSize": 4, "format": 0, "allowManualEntry": true, "isFromConfig": true }, "value": 15 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyKey": 2130706432, "propertyName": "LED Effect Type", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Effect Type", "default": 0, "min": 0, "max": 4, "states": { "0": "Off", "1": "Solid", "2": "Fast Blink", "3": "Slow Blink", "4": "Pulse" }, "valueSize": 4, "format": 0, "allowManualEntry": false, "isFromConfig": true }, "value": 2 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyName": "param008", "ccVersion": 1, "metadata": { "type": "any", "readable": true, "writeable": true }, "value": 34540102 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535 }, "value": 798 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535 }, "value": 2 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535 }, "value": 1 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "local", "propertyName": "local", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Local protection state", "states": { "8": "unknown (0x08)", "9": "unknown (0x09)", "10": "unknown (0x0a)" } }, "value": 0 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "rf", "propertyName": "rf", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "RF protection state", "states": { "8": "unknown (0x08)", "9": "unknown (0x09)", "10": "unknown (0x0a)" } }, "value": 0 }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "exclusiveControlNodeId", "propertyName": "exclusiveControlNodeId", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true } }, { "endpoint": 0, "commandClass": 117, "commandClassName": "Protection", "property": "timeout", "propertyName": "timeout", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": true } }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "6.4" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": [ "1.9" ] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } } ], "isFrequentListening": false, "maxDataRate": 40000, "supportedDataRates": [ 40000 ], "protocolVersion": 3, "zwavePlusNodeType": 0, "zwavePlusRoleType": 5, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 16, "label": "Binary Switch" }, "specific": { "key": 1, "label": "Binary Power Switch" }, "mandatorySupportedCCs": [ 32, 37, 39 ], "mandatoryControlledCCs": [] }, "commandClasses": [{ "id": 37, "name": "Binary Switch", "version": 1, "isSecure": false }, { "id": 50, "name": "Meter", "version": 3, "isSecure": false }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": false }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": false }, { "id": 91, "name": "Central Scene", "version": 3, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": false }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": false }, { "id": 117, "name": "Protection", "version": 2, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 2, "isSecure": false }, { "id": 152, "name": "Security", "version": 1, "isSecure": true } ] } zwave-js-server-python-0.63.0/test/fixtures/ring_keypad_state.json000066400000000000000000000521631500374325600254240ustar00rootroot00000000000000{ "nodeId": 10, "index": 0, "installerIcon": 8193, "userIcon": 8193, "status": 4, "ready": true, "isListening": false, "isRouting": true, "isSecure": true, "manufacturerId": 838, "productId": 513, "productType": 257, "firmwareVersion": "2.14", "zwavePlusVersion": 1, "deviceConfig": { "filename": "C:\\Users\\hessl\\Documents\\Dev\\zwave-js-server\\node_modules\\@zwave-js\\config\\config\\devices\\0x0346\\alarm_keypad_gen1.json", "manufacturer": "Ring", "manufacturerId": 838, "label": "4AK1S7-0EN0 / 4AK1E9-0EU0", "description": "Alarm Keypad (1st generation)", "devices": [ { "productType": 257, "productId": 513 }, { "productType": 257, "productId": 514 } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} }, "compat": { "valueIdRegex": {}, "disableStrictEntryControlDataValidation": true }, "metadata": { "manual": "https://support.ring.com/hc/en-us/article_attachments/360051851012/Keypad_Zwave_UK.pdf" } }, "label": "4AK1S7-0EN0 / 4AK1E9-0EU0", "neighbors": [1, 7, 16], "interviewAttempts": 1, "interviewStage": "Neighbors", "endpoints": [ { "nodeId": 10, "index": 0, "installerIcon": 8193, "userIcon": 8193 } ], "values": [ { "endpoint": 0, "commandClass": 111, "commandClassName": "Entry Control", "property": "keyCacheSize", "propertyName": "keyCacheSize", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Number of character that must be stored before sending", "label": "Key cache size", "min": 4, "max": 10 }, "value": 8 }, { "endpoint": 0, "commandClass": 111, "commandClassName": "Entry Control", "property": "keyCacheTimeout", "propertyName": "keyCacheTimeout", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "How long the key cache must wait for additional characters", "label": "Key cache timeout", "min": 0, "max": 30, "unit": "seconds" }, "value": 5 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535 }, "value": 838 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535 }, "value": 257 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535 }, "value": 513 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "6.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["2.14"] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "level", "propertyName": "level", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Battery level", "min": 0, "max": 100, "unit": "%" }, "value": 41 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "isLow", "propertyName": "isLow", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 1, "propertyName": "Battery Report Interval", "ccVersion": 1, "metadata": { "type": "number", "default": 70, "readable": true, "writeable": true, "description": "Default heartbeat check in time", "label": "Battery Report Interval", "min": 70, "max": 1440, "states": {}, "unit": "minutes" }, "value": 70 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 2, "propertyName": "Awake Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 1, "readable": true, "writeable": true, "description": "How long the device waits for a command before going back to sleep", "label": "Awake Timeout", "min": 1, "max": 5, "states": {}, "unit": "seconds" }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "Co-Proc Status", "ccVersion": 1, "metadata": { "type": "number", "default": 1, "readable": true, "writeable": false, "description": "Check to see if the co-proc is operational", "label": "Co-Proc Status", "min": 0, "max": 1, "states": { "0": "Dead", "1": "Alive" } }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Proximity Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 5, "readable": true, "writeable": true, "description": "Timeout when proximity is detected and no input is received", "label": "Proximity Timeout", "min": 0, "max": 30, "states": {}, "unit": "seconds" }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 5, "propertyName": "Button Press Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 5, "readable": true, "writeable": true, "description": ": Timeout when a button is pressed, but a sequence is not completed and buttons are no longer being pressed", "label": "Button Press Timeout", "min": 0, "max": 30, "states": {}, "unit": "seconds" }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 6, "propertyName": "Status Change Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 15, "readable": true, "writeable": true, "label": "Status Change Timeout", "min": 10, "max": 60, "states": {}, "unit": "seconds" }, "value": 15 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 7, "propertyName": "Enable / Disable Extended Battery Life Mode", "ccVersion": 1, "metadata": { "type": "number", "default": 0, "readable": true, "writeable": true, "label": "Enable / Disable Extended Battery Life Mode", "min": 0, "max": 1, "states": { "0": "Enable", "1": "Disable" } }, "value": 0 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 8, "propertyName": "Key Backlight Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 3, "readable": true, "writeable": true, "description": "Timeout for keypad LED backlight to stay on between key presses", "label": "Key Backlight Timeout", "min": 1, "max": 15, "states": {}, "unit": "seconds" }, "value": 3 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 9, "propertyName": "Key Backlight Brightness", "ccVersion": 1, "metadata": { "type": "number", "default": 100, "readable": true, "writeable": true, "description": "Adjusts the brightness of the keypad backlight", "label": "Key Backlight Brightness", "min": 0, "max": 100, "states": {}, "unit": "%" }, "value": 100 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 10, "propertyName": "Key Tone Volume", "ccVersion": 1, "metadata": { "type": "number", "default": 8, "readable": true, "writeable": true, "label": "Key Tone Volume", "min": 0, "max": 10, "states": {} }, "value": 8 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 11, "propertyName": "Ambient Light Sensor Level", "ccVersion": 1, "metadata": { "type": "number", "default": 5, "readable": true, "writeable": true, "description": "Light threshold where keypad will stop backlighting if higher than choosen value", "label": "Ambient Light Sensor Level", "min": 0, "max": 100, "states": {} }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 12, "propertyName": "Siren Volume", "ccVersion": 1, "metadata": { "type": "number", "default": 6, "readable": true, "writeable": true, "label": "Siren Volume", "min": 0, "max": 10, "states": {} }, "value": 6 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 13, "propertyName": "Enable / Disable Proximity mode", "ccVersion": 1, "metadata": { "type": "number", "default": 1, "readable": true, "writeable": true, "label": "Enable / Disable Proximity mode", "min": 0, "max": 1, "states": { "0": "Disable", "1": "Enable" } }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 14, "propertyName": "Proximity Distance", "ccVersion": 1, "metadata": { "type": "number", "default": 100, "readable": true, "writeable": true, "label": "Proximity Distance", "min": 0, "max": 100, "states": {}, "unit": "centimeters" }, "value": 100 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 15, "propertyName": "Extended Battery Life LED Brightness Adjustment", "ccVersion": 1, "metadata": { "type": "number", "default": 50, "readable": true, "writeable": true, "label": "Extended Battery Life LED Brightness Adjustment", "min": 0, "max": 100, "states": {}, "unit": "%" }, "value": 50 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 16, "propertyName": "Reduced Battery Life LED Brightness Adjustment", "ccVersion": 1, "metadata": { "type": "number", "default": 65, "readable": true, "writeable": true, "label": "Reduced Battery Life LED Brightness Adjustment", "min": 0, "max": 100, "states": {}, "unit": "%" }, "value": 65 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 17, "propertyName": "Fast Blink Rate", "ccVersion": 1, "metadata": { "type": "number", "default": 5, "readable": true, "writeable": true, "label": "Fast Blink Rate", "min": 0, "max": 100, "states": {}, "unit": "0.1 seconds" }, "value": 5 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 18, "propertyName": "Slow Blink Rate", "ccVersion": 1, "metadata": { "type": "number", "default": 2, "readable": true, "writeable": true, "label": "Slow Blink Rate", "min": 0, "max": 100, "states": {}, "unit": "0.5 seconds" }, "value": 2 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 19, "propertyName": "Supervision Report Timeout", "ccVersion": 1, "metadata": { "type": "number", "default": 1500, "readable": true, "writeable": true, "label": "Supervision Report Timeout", "min": 500, "max": 5000, "states": {}, "unit": "milliseconds" }, "value": 1500 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 20, "propertyName": "Number of Re-transmissions Attempts", "ccVersion": 1, "metadata": { "type": "number", "default": 1, "readable": true, "writeable": true, "label": "Number of Re-transmissions Attempts", "min": 0, "max": 5, "states": {} }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 21, "propertyName": "Wait Period Between Re-transmissions Attempts", "ccVersion": 1, "metadata": { "type": "number", "default": 5, "readable": true, "writeable": true, "label": "Wait Period Between Re-transmissions Attempts", "min": 1, "max": 60, "states": {}, "unit": "seconds" }, "value": 5 }, { "endpoint": 0, "commandClass": 135, "commandClassName": "Indicator", "property": "value", "propertyName": "value", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Indicator value", "ccSpecific": { "indicatorId": 0 }, "min": 0, "max": 255 }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Home Security", "propertyKey": "Motion sensor status", "propertyName": "Home Security", "propertyKeyName": "Motion sensor status", "ccVersion": 8, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Motion sensor status", "ccSpecific": { "notificationType": 7 }, "min": 0, "max": 255, "states": { "0": "idle", "8": "Motion detection" } }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Power status", "propertyName": "Power Management", "propertyKeyName": "Power status", "ccVersion": 8, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Power status", "ccSpecific": { "notificationType": 8 }, "min": 0, "max": 255, "states": { "0": "idle", "1": "Power has been applied" } }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Battery load status", "propertyName": "Power Management", "propertyKeyName": "Battery load status", "ccVersion": 8, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Battery load status", "ccSpecific": { "notificationType": 8 }, "min": 0, "max": 255, "states": { "0": "idle", "12": "Battery is charging" } }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "System", "propertyKey": "Software status", "propertyName": "System", "propertyKeyName": "Software status", "ccVersion": 8, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Software status", "ccSpecific": { "notificationType": 9 }, "min": 0, "max": 255, "states": { "0": "idle", "4": "System software failure (with failure code)" } }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Mains status", "propertyName": "Power Management", "propertyKeyName": "Mains status", "ccVersion": 8, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Mains status", "ccSpecific": { "notificationType": 8 }, "min": 0, "max": 255, "states": { "2": "AC mains disconnected", "3": "AC mains re-connected" } } } ], "isFrequentListening": "1000ms", "maxDataRate": 100000, "supportedDataRates": [40000, 100000], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 7, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 11, "label": "Secure Keypad" }, "mandatorySupportedCCs": [90, 111, 114, 152, 134], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": true }, { "id": 111, "name": "Entry Control", "version": 1, "isSecure": true }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": true }, { "id": 152, "name": "Security", "version": 1, "isSecure": true }, { "id": 134, "name": "Version", "version": 2, "isSecure": true }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": true }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": true }, { "id": 128, "name": "Battery", "version": 1, "isSecure": true }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": true }, { "id": 135, "name": "Indicator", "version": 1, "isSecure": true }, { "id": 113, "name": "Notification", "version": 8, "isSecure": true }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": true }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": true } ] } zwave-js-server-python-0.63.0/test/fixtures/switch_enbrighten_zw3010_state.json000066400000000000000000000742631500374325600276670ustar00rootroot00000000000000{ "nodeId": 2, "index": 0, "installerIcon": 1540, "userIcon": 1536, "status": 4, "ready": true, "isListening": true, "isRouting": true, "isSecure": true, "manufacturerId": 99, "productId": 12853, "productType": 18756, "firmwareVersion": "5.54", "zwavePlusVersion": 1, "deviceConfig": { "filename": "/data/db/devices/0x0063/46203_zw3010.json", "isEmbedded": true, "manufacturer": "GE/Enbrighten", "manufacturerId": 99, "label": "46203 / ZW3010", "description": "In-Wall Paddle Dimmer, QFSW, 500S", "devices": [ { "productType": 18756, "productId": 12853 } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "preferred": false, "associations": {}, "paramInformation": { "_map": {} }, "compat": { "treatBasicSetAsEvent": true }, "metadata": { "inclusion": "1. Follow the instructions for your Z-Wave certified controller to add a device to the Z-Wave network.\n2. Once the controller is ready to add your device, press and release the top or bottom of the wireless smart dimmer (rocker) to add it in the network.\nIf prompted by the controller to enter the S2 security code, refer to the QR code/security number on the back of the box, or the QR code label on the product", "exclusion": "1. Follow the instructions for your Z-Wave certified controller to remove a device from the Z-Wave network.\n2. Once the controller is ready to remove your device, press and release the top or bottom of the wireless smart dimmer (rocker) to remove it from the network", "reset": "Quickly press ON (top) button 3 times, then, immediately press the OFF (bottom) button 3 times. The LED will flash 5 times when completed successfully.\nNote: This should only be used in the event your network\u2019s primary controller is missing or otherwise inoperable", "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=product_documents/4024/46203%20QSG%20v3%20(3).pdf" } }, "label": "46203 / ZW3010", "interviewAttempts": 0, "endpoints": [ { "nodeId": 2, "index": 0, "installerIcon": 1540, "userIcon": 1536, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 17, "label": "Multilevel Switch" }, "specific": { "key": 1, "label": "Multilevel Power Switch" }, "mandatorySupportedCCs": [ 32, 38, 39 ], "mandatoryControlledCCs": [] }, "commandClasses": [ { "id": 32, "name": "Basic", "version": 1, "isSecure": false }, { "id": 38, "name": "Multilevel Switch", "version": 4, "isSecure": true }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 85, "name": "Transport Service", "version": 2, "isSecure": false }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 159, "name": "Security 2", "version": 1, "isSecure": true }, { "id": 133, "name": "Association", "version": 2, "isSecure": true }, { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": true }, { "id": 134, "name": "Version", "version": 3, "isSecure": true }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": true }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": true }, { "id": 115, "name": "Powerlevel", "version": 1, "isSecure": true }, { "id": 91, "name": "Central Scene", "version": 3, "isSecure": true }, { "id": 112, "name": "Configuration", "version": 4, "isSecure": true }, { "id": 122, "name": "Firmware Update Meta Data", "version": 4, "isSecure": true } ] } ], "values": [ { "endpoint": 0, "commandClass": 32, "commandClassName": "Basic", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Current value", "min": 0, "max": 99, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 32, "commandClassName": "Basic", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Target value", "min": 0, "max": 255, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 32, "commandClassName": "Basic", "property": "duration", "propertyName": "duration", "ccVersion": 1, "metadata": { "type": "duration", "readable": true, "writeable": false, "label": "Remaining duration", "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 32, "commandClassName": "Basic", "property": "restorePrevious", "propertyName": "restorePrevious", "ccVersion": 1, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Restore previous value", "states": { "true": "Restore" }, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 32, "commandClassName": "Basic", "property": "event", "propertyName": "event", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Event value", "min": 0, "max": 255, "stateful": false, "secret": false } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "currentValue", "propertyName": "currentValue", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Current value", "min": 0, "max": 99, "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "targetValue", "propertyName": "targetValue", "ccVersion": 0, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Target value", "valueChangeOptions": [ "transitionDuration" ], "min": 0, "max": 99, "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "duration", "propertyName": "duration", "ccVersion": 0, "metadata": { "type": "duration", "readable": true, "writeable": false, "label": "Remaining duration", "stateful": true, "secret": false }, "value": { "value": 0, "unit": "seconds" } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "Up", "propertyName": "Up", "ccVersion": 0, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Perform a level change (Up)", "ccSpecific": { "switchType": 2 }, "valueChangeOptions": [ "transitionDuration" ], "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 38, "commandClassName": "Multilevel Switch", "property": "Down", "propertyName": "Down", "ccVersion": 0, "metadata": { "type": "boolean", "readable": false, "writeable": true, "label": "Perform a level change (Down)", "ccSpecific": { "switchType": 2 }, "valueChangeOptions": [ "transitionDuration" ], "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "001", "propertyName": "scene", "propertyKeyName": "001", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Scene 001", "min": 0, "max": 255, "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x" }, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "002", "propertyName": "scene", "propertyKeyName": "002", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Scene 002", "min": 0, "max": 255, "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown", "3": "KeyPressed2x", "4": "KeyPressed3x" }, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "slowRefresh", "propertyName": "slowRefresh", "ccVersion": 3, "metadata": { "type": "boolean", "readable": true, "writeable": true, "description": "When this is true, KeyHeldDown notifications are sent every 55s. When this is false, the notifications are sent every 200ms.", "label": "Send held down notifications at a slow rate", "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "LED Indicator", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "LED Indicator", "default": 0, "min": 0, "max": 3, "states": { "0": "On when load is off", "1": "On when load is on", "2": "Always off", "3": "Always on" }, "valueSize": 1, "format": 0, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Inverted Orientation", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Inverted Orientation", "default": 0, "min": 0, "max": 1, "states": { "0": "Disable", "1": "Enable" }, "valueSize": 1, "format": 1, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 6, "propertyName": "Dim Rate", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Dim Rate", "default": 0, "min": 0, "max": 1, "states": { "0": "Dim Quickly", "1": "Dim Slowly" }, "valueSize": 1, "format": 1, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 16, "propertyName": "Switch Mode", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Switch Mode", "default": 0, "min": 0, "max": 1, "states": { "0": "Disable", "1": "Enable" }, "valueSize": 1, "format": 1, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 19, "propertyName": "Alternate Exclusion", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "description": "Press two times ON and two times OFF, LED will flash 5 times if successful", "label": "Alternate Exclusion", "default": 0, "min": 0, "max": 1, "states": { "0": "Disable", "1": "Enable" }, "valueSize": 1, "format": 1, "allowManualEntry": false, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 30, "propertyName": "Minimum Dimmer Threshold", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Minimum Dimmer Threshold", "default": 1, "min": 1, "max": 99, "valueSize": 1, "format": 1, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 31, "propertyName": "Maximum Dimmer Threshold", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Maximum Dimmer Threshold", "default": 99, "min": 1, "max": 99, "valueSize": 1, "format": 1, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 32, "propertyName": "Default Brightness Level", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Default Brightness Level", "default": 0, "min": 0, "max": 99, "valueSize": 1, "format": 1, "allowManualEntry": true, "isFromConfig": true } }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 99 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 18756 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 12853 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "sdkVersion", "propertyName": "sdkVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "SDK version", "stateful": true, "secret": false }, "value": "6.81.3" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkAPIVersion", "propertyName": "applicationFrameworkAPIVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API version", "stateful": true, "secret": false }, "value": "4.1.2" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkBuildNumber", "propertyName": "applicationFrameworkBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API build number", "stateful": true, "secret": false }, "value": 52445 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceVersion", "propertyName": "hostInterfaceVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API version", "stateful": true, "secret": false }, "value": "unused" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceBuildNumber", "propertyName": "hostInterfaceBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API build number", "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolVersion", "propertyName": "zWaveProtocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version", "stateful": true, "secret": false }, "value": "6.4.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolBuildNumber", "propertyName": "zWaveProtocolBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol build number", "stateful": true, "secret": false }, "value": 91 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationVersion", "propertyName": "applicationVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application version", "stateful": true, "secret": false }, "value": "4.1.2" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationBuildNumber", "propertyName": "applicationBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application build number", "stateful": true, "secret": false }, "value": 52445 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Library type", "states": { "0": "Unknown", "1": "Static Controller", "2": "Controller", "3": "Enhanced Slave", "4": "Slave", "5": "Installer", "6": "Routing Slave", "7": "Bridge Controller", "8": "Device under Test", "9": "N/A", "10": "AV Remote", "11": "AV Device" }, "stateful": true, "secret": false }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version", "stateful": true, "secret": false }, "value": "6.4" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 3, "metadata": { "type": "string[]", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions", "stateful": true, "secret": false }, "value": [ "5.54" ] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version", "stateful": true, "secret": false }, "value": 255 } ], "isFrequentListening": false, "maxDataRate": 100000, "supportedDataRates": [ 40000, 100000 ], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 5, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 17, "label": "Multilevel Switch" }, "specific": { "key": 1, "label": "Multilevel Power Switch" }, "mandatorySupportedCCs": [ 32, 38, 39 ], "mandatoryControlledCCs": [] }, "interviewStage": "Complete", "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0x0063:0x4944:0x3235:5.54", "statistics": { "commandsTX": 6, "commandsRX": 4, "commandsDroppedRX": 1, "commandsDroppedTX": 0, "timeoutResponse": 1, "rtt": 190.2, "rssi": -79, "lwr": { "protocolDataRate": 3, "repeaters": [ 72 ], "rssi": -78, "repeaterRSSI": [ -83 ] } }, "highestSecurityClass": 1, "isControllerNode": false, "keepAwake": false }zwave-js-server-python-0.63.0/test/fixtures/timed_lock_state.json000066400000000000000000000445541500374325600252470ustar00rootroot00000000000000{ "nodeId": 7, "index": 0, "installerIcon": 1792, "userIcon": 1792, "status": 4, "ready": true, "isListening": true, "isRouting": true, "isSecure": true, "manufacturerId": 65535, "productId": 1, "productType": 170, "firmwareVersion": "0.0", "zwavePlusVersion": 2, "interviewAttempts": 1, "isFrequentListening": false, "maxDataRate": 100000, "supportedDataRates": [ 40000, 100000 ], "protocolVersion": 3, "supportsBeaming": true, "supportsSecurity": false, "nodeType": 1, "zwavePlusNodeType": 0, "zwavePlusRoleType": 5, "deviceClass": { "basic": { "key": 4, "label": "Routing End Node" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 1, "label": "Door Lock" } }, "interviewStage": "Complete", "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0xffff:0x00aa:0x0001:0.0", "statistics": { "commandsTX": 49, "commandsRX": 48, "commandsDroppedRX": 2, "commandsDroppedTX": 0, "timeoutResponse": 0, "rtt": 29.3, "lastSeen": "2024-09-04T11:55:07.601Z", "rssi": -68, "lwr": { "protocolDataRate": 3, "repeaters": [], "rssi": -69, "repeaterRSSI": [] } }, "highestSecurityClass": 2, "isControllerNode": false, "keepAwake": false, "lastSeen": "2024-09-04T11:54:44.326Z", "protocol": 0, "values": [ { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "targetMode", "propertyName": "targetMode", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Target lock mode", "min": 0, "max": 255, "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "255": "Secured" }, "stateful": true, "secret": false }, "value": 255 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "operationType", "propertyName": "operationType", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Lock operation type", "min": 0, "max": 255, "states": { "1": "Constant", "2": "Timed" }, "stateful": true, "secret": false }, "value": 1 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "latchStatus", "propertyName": "latchStatus", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Current status of the latch", "stateful": true, "secret": false }, "value": "open" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "boltStatus", "propertyName": "boltStatus", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Current status of the bolt", "stateful": true, "secret": false }, "value": "unlocked" }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoorConfiguration", "propertyName": "outsideHandlesCanOpenDoorConfiguration", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which outside handles can open the door (configuration)", "stateful": true, "secret": false }, "value": [ true, true, true, true ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoorConfiguration", "propertyName": "insideHandlesCanOpenDoorConfiguration", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": true, "label": "Which inside handles can open the door (configuration)", "stateful": true, "secret": false }, "value": [ true, true, true, true ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "autoRelockTime", "propertyName": "autoRelockTime", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration in seconds until lock returns to secure state", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "holdAndReleaseTime", "propertyName": "holdAndReleaseTime", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration in seconds the latch stays retracted", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "twistAssist", "propertyName": "twistAssist", "ccVersion": 4, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Twist Assist enabled", "stateful": true, "secret": false }, "value": true }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "blockToBlock", "propertyName": "blockToBlock", "ccVersion": 4, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Block-to-block functionality enabled", "stateful": true, "secret": false }, "value": true }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "currentMode", "propertyName": "currentMode", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Current lock mode", "min": 0, "max": 255, "states": { "0": "Unsecured", "1": "UnsecuredWithTimeout", "16": "InsideUnsecured", "17": "InsideUnsecuredWithTimeout", "32": "OutsideUnsecured", "33": "OutsideUnsecuredWithTimeout", "254": "Unknown", "255": "Secured" }, "stateful": true, "secret": false }, "value": 255 }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "duration", "propertyName": "duration", "ccVersion": 4, "metadata": { "type": "duration", "readable": true, "writeable": false, "label": "Remaining duration until target lock mode", "stateful": true, "secret": false }, "value": { "value": 0, "unit": "seconds" } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "outsideHandlesCanOpenDoor", "propertyName": "outsideHandlesCanOpenDoor", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which outside handles can open the door (actual status)", "stateful": true, "secret": false }, "value": [ true, true, true, true ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "insideHandlesCanOpenDoor", "propertyName": "insideHandlesCanOpenDoor", "ccVersion": 4, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Which inside handles can open the door (actual status)", "stateful": true, "secret": false }, "value": [ true, true, true, true ] }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeoutConfiguration", "propertyName": "lockTimeoutConfiguration", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": true, "label": "Duration of timed mode in seconds", "min": 0, "max": 65535, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "lockTimeout", "propertyName": "lockTimeout", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Seconds until lock mode times out", "min": 0, "max": 65535, "stateful": true, "secret": false } }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Manufacturer ID", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 65535 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product type", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 170 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Product ID", "min": 0, "max": 65535, "stateful": true, "secret": false }, "value": 1 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Library type", "states": { "0": "Unknown", "1": "Static Controller", "2": "Controller", "3": "Enhanced Slave", "4": "Slave", "5": "Installer", "6": "Routing Slave", "7": "Bridge Controller", "8": "Device under Test", "9": "N/A", "10": "AV Remote", "11": "AV Device" }, "stateful": true, "secret": false }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version", "stateful": true, "secret": false }, "value": "0.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 3, "metadata": { "type": "string[]", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions", "stateful": true, "secret": false }, "value": [ "0.0" ] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 3, "metadata": { "type": "number", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version", "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "sdkVersion", "propertyName": "sdkVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "SDK version", "stateful": true, "secret": false }, "value": "7.0.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkAPIVersion", "propertyName": "applicationFrameworkAPIVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API version", "stateful": true, "secret": false }, "value": "unused" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationFrameworkBuildNumber", "propertyName": "applicationFrameworkBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave application framework API build number", "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceVersion", "propertyName": "hostInterfaceVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API version", "stateful": true, "secret": false }, "value": "unused" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hostInterfaceBuildNumber", "propertyName": "hostInterfaceBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Serial API build number", "stateful": true, "secret": false }, "value": 0 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolVersion", "propertyName": "zWaveProtocolVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol version", "stateful": true, "secret": false }, "value": "7.0.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "zWaveProtocolBuildNumber", "propertyName": "zWaveProtocolBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Z-Wave protocol build number", "stateful": true, "secret": false }, "value": 255 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationVersion", "propertyName": "applicationVersion", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application version", "stateful": true, "secret": false }, "value": "1.0.0" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "applicationBuildNumber", "propertyName": "applicationBuildNumber", "ccVersion": 3, "metadata": { "type": "string", "readable": true, "writeable": false, "label": "Application build number", "stateful": true, "secret": false }, "value": 255 } ], "endpoints": [ { "nodeId": 7, "index": 0, "installerIcon": 1792, "userIcon": 1792, "deviceClass": { "basic": { "key": 4, "label": "Routing End Node" }, "generic": { "key": 64, "label": "Entry Control" }, "specific": { "key": 1, "label": "Door Lock" } }, "commandClasses": [ { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 159, "name": "Security 2", "version": 1, "isSecure": true }, { "id": 152, "name": "Security", "version": 1, "isSecure": true }, { "id": 108, "name": "Supervision", "version": 1, "isSecure": false }, { "id": 85, "name": "Transport Service", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 3, "isSecure": true }, { "id": 133, "name": "Association", "version": 2, "isSecure": true }, { "id": 89, "name": "Association Group Information", "version": 3, "isSecure": true }, { "id": 98, "name": "Door Lock", "version": 4, "isSecure": true }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": true } ] } ] } zwave-js-server-python-0.63.0/test/fixtures/unparseable_json_string_value_state.json000066400000000000000000000032101500374325600312310ustar00rootroot00000000000000{ "nodeId": 20, "index": 0, "status": 4, "ready": true, "deviceClass": { "basic": { "key": 1, "label": "Static Controller" }, "generic": { "key": 2, "label": "Entry Control" }, "specific": { "key": 3, "label": "Secure Keypad Door Lock" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": false, "isFrequentListening": true, "isRouting": true, "maxBaudRate": 40000, "isSecure": true, "version": 4, "isBeaming": true, "manufacturerId": 59, "productId": 20548, "productType": 25409, "firmwareVersion": "113.22", "deviceConfig": { "manufacturerId": 59, "manufacturer": "Allegion", "label": "BE469", "description": "Touchscreen Deadbolt", "devices": [ { "productType": "0x6341", "productId": "0x5044" } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "associations": {}, "paramInformation": { "_map": {} } }, "label": "BE469", "neighbors": [1, 2, 3, 4, 13], "interviewAttempts": 1, "endpoints": [ { "nodeId": 20, "index": 0 } ], "commandClasses": [], "values": [ { "commandClassName": "User Code", "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 4, "propertyName": "userCode", "propertyKeyName": "4", "metadata": { "type": "buffer", "readable": true, "writeable": true, "minLength": 4, "maxLength": 10, "label": "User Code (4)" }, "value": "{ \"type\": \"Unparseable\", \"data\": [55, 48, 51, 48, 10, 13] }" } ] } zwave-js-server-python-0.63.0/test/fixtures/wallmote_central_scene_state.json000066400000000000000000000414321500374325600276360ustar00rootroot00000000000000{ "nodeId": 35, "index": 0, "installerIcon": 7172, "userIcon": 7172, "status": 1, "ready": true, "deviceClass": { "basic": { "key": 4, "label": "Routing Slave" }, "generic": { "key": 24, "label": "Wall Controller" }, "specific": { "key": 1, "label": "Basic Wall Controller" }, "mandatorySupportedCCs": [], "mandatoryControlledCCs": [] }, "isListening": false, "isFrequentListening": false, "isRouting": true, "maxBaudRate": 40000, "isSecure": false, "version": 4, "isBeaming": true, "manufacturerId": 134, "productId": 130, "productType": 258, "firmwareVersion": "2.3", "zwavePlusVersion": 1, "nodeType": 0, "roleType": 4, "name": "mbr_wallmote_quad", "deviceConfig": { "filename": "/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0086/zw130.json", "manufacturerId": 134, "manufacturer": "AEON Labs", "label": "ZW130", "description": "WallMote Quad", "devices": [ { "productType": 2, "productId": 130 }, { "productType": 258, "productId": 130 }, { "productType": 514, "productId": 130 } ], "firmwareVersion": { "min": "0.0", "max": "255.255" }, "paramInformation": { "_map": {} }, "metadata": { "inclusion": "To add the ZP3111 to the Z-Wave network (inclusion), place the Z-Wave primary controller into inclusion mode. Press the Program Switch of ZP3111 for sending the NIF. After sending NIF, Z-Wave will send the auto inclusion, otherwise, ZP3111 will go to sleep after 20 seconds.", "exclusion": "To remove the ZP3111 from the Z-Wave network (exclusion), place the Z-Wave primary controller into \u201cexclusion\u201d mode, and following its instruction to delete the ZP3111 to the controller. Press the Program Switch of ZP3111 once to be excluded.", "reset": "Remove cover to trigged tamper switch, LED flash once & send out Alarm Report. Press Program Switch 10 times within 10 seconds, ZP3111 will send the \u201cDevice Reset Locally Notification\u201d command and reset to the factory default. (Remark: This is to be used only in the case of primary controller being inoperable or otherwise unavailable.)", "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf", "comments": { "level": "info", "text": "test" } }, "isEmbedded": true }, "label": "ZW130", "neighbors": [1, 14, 15, 16, 22, 30, 31, 5, 6, 7, 8], "endpointCountIsDynamic": false, "endpointsHaveIdenticalCapabilities": true, "individualEndpointCount": 4, "aggregatedEndpointCount": 0, "interviewAttempts": 1, "interviewStage": "NodeInfo", "commandClasses": [ { "id": 89, "name": "Association Group Information", "version": 1, "isSecure": false }, { "id": 90, "name": "Device Reset Locally", "version": 1, "isSecure": false }, { "id": 91, "name": "Central Scene", "version": 2, "isSecure": false }, { "id": 94, "name": "Z-Wave Plus Info", "version": 2, "isSecure": false }, { "id": 96, "name": "Multi Channel", "version": 4, "isSecure": false }, { "id": 112, "name": "Configuration", "version": 1, "isSecure": false }, { "id": 113, "name": "Notification", "version": 4, "isSecure": false }, { "id": 114, "name": "Manufacturer Specific", "version": 2, "isSecure": false }, { "id": 122, "name": "Firmware Update Meta Data", "version": 2, "isSecure": false }, { "id": 128, "name": "Battery", "version": 1, "isSecure": false }, { "id": 132, "name": "Wake Up", "version": 1, "isSecure": false }, { "id": 133, "name": "Association", "version": 2, "isSecure": false }, { "id": 134, "name": "Version", "version": 2, "isSecure": false }, { "id": 142, "name": "Multi Channel Association", "version": 3, "isSecure": false } ], "endpoints": [ { "nodeId": 35, "index": 0, "installerIcon": 7172, "userIcon": 7172 }, { "nodeId": 35, "index": 1, "installerIcon": 7169, "userIcon": 7169 }, { "nodeId": 35, "index": 2, "installerIcon": 7169, "userIcon": 7169 }, { "nodeId": 35, "index": 3, "installerIcon": 7169, "userIcon": 7169 }, { "nodeId": 35, "index": 4, "installerIcon": 7169, "userIcon": 7169 } ], "values": [ { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "slowRefresh", "propertyName": "slowRefresh", "ccVersion": 2, "metadata": { "type": "boolean", "readable": true, "writeable": true, "label": "Send held down notifications at a slow rate", "description": "When this is true, KeyHeldDown notifications are sent every 55s. When this is false, the notifications are sent every 200ms." } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "004", "propertyName": "scene", "propertyKeyName": "004", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 004", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "001", "propertyName": "scene", "propertyKeyName": "001", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 001", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "002", "propertyName": "scene", "propertyKeyName": "002", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 002", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown" } } }, { "endpoint": 0, "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "003", "propertyName": "scene", "propertyKeyName": "003", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Scene 003", "states": { "0": "KeyPressed", "1": "KeyReleased", "2": "KeyHeldDown" } } }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 1, "propertyName": "Touch sound", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Touch sound", "description": "Enable/disable the touch sound.", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 2, "propertyName": "Touch vibration", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Touch vibration", "description": "Enable/disable the touch vibration.", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 3, "propertyName": "Button slide", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": false, "states": { "0": "Disable", "1": "Enable" }, "label": "Button slide", "description": "Enable/disable the function of button slide.", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 4, "propertyName": "Notification report", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 3, "default": 1, "format": 0, "allowManualEntry": false, "states": { "1": "Central scene", "3": "Central scene and config" }, "label": "Notification report", "description": "Which notification to be sent to the associated devices.", "isFromConfig": true }, "value": 1 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 39, "propertyName": "Low battery value", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": true, "valueSize": 1, "min": 0, "max": 50, "default": 5, "format": 0, "allowManualEntry": true, "label": "Low battery value", "description": "Set the low battery value", "isFromConfig": true }, "value": 20 }, { "endpoint": 0, "commandClass": 112, "commandClassName": "Configuration", "property": 255, "propertyName": "Reset the WallMote Quad", "ccVersion": 1, "metadata": { "type": "number", "readable": false, "writeable": true, "valueSize": 4, "min": 0, "max": 1431655765, "default": 0, "format": 0, "allowManualEntry": false, "states": { "0": "Reset to factory default", "1431655765": "Reset and remove" }, "label": "Reset the WallMote Quad", "description": "Reset the WallMote Quad to factory default.", "isFromConfig": true } }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Battery load status", "propertyName": "Power Management", "propertyKeyName": "Battery load status", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Battery load status", "states": { "0": "idle", "12": "Battery is charging" }, "ccSpecific": { "notificationType": 8 } }, "value": 0 }, { "endpoint": 0, "commandClass": 113, "commandClassName": "Notification", "property": "Power Management", "propertyKey": "Battery level status", "propertyName": "Power Management", "propertyKeyName": "Battery level status", "ccVersion": 4, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 255, "label": "Battery level status", "states": { "0": "idle", "13": "Battery is fully charged", "14": "Charge battery soon", "15": "Charge battery now" }, "ccSpecific": { "notificationType": 8 } }, "value": 0 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "manufacturerId", "propertyName": "manufacturerId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Manufacturer ID" }, "value": 134 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productType", "propertyName": "productType", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product type" }, "value": 258 }, { "endpoint": 0, "commandClass": 114, "commandClassName": "Manufacturer Specific", "property": "productId", "propertyName": "productId", "ccVersion": 2, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 65535, "label": "Product ID" }, "value": 130 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "level", "propertyName": "level", "ccVersion": 1, "metadata": { "type": "number", "readable": true, "writeable": false, "min": 0, "max": 100, "unit": "%", "label": "Battery level" }, "value": 100 }, { "endpoint": 0, "commandClass": 128, "commandClassName": "Battery", "property": "isLow", "propertyName": "isLow", "ccVersion": 1, "metadata": { "type": "boolean", "readable": true, "writeable": false, "label": "Low battery level" }, "value": false }, { "endpoint": 0, "commandClass": 132, "commandClassName": "Wake Up", "property": "wakeUpInterval", "propertyName": "wakeUpInterval", "ccVersion": 1, "metadata": { "type": "number", "readable": false, "writeable": true, "min": 0, "max": 864000, "label": "Wake Up interval", "steps": 240, "default": 0 }, "value": 0 }, { "endpoint": 0, "commandClass": 132, "commandClassName": "Wake Up", "property": "controllerNodeId", "propertyName": "controllerNodeId", "ccVersion": 1, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Node ID of the controller" }, "value": 1 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "libraryType", "propertyName": "libraryType", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Library type" }, "value": 3 }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "protocolVersion", "propertyName": "protocolVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave protocol version" }, "value": "4.62" }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "firmwareVersions", "propertyName": "firmwareVersions", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip firmware versions" }, "value": ["2.3"] }, { "endpoint": 0, "commandClass": 134, "commandClassName": "Version", "property": "hardwareVersion", "propertyName": "hardwareVersion", "ccVersion": 2, "metadata": { "type": "any", "readable": true, "writeable": false, "label": "Z-Wave chip hardware version" } } ] } zwave-js-server-python-0.63.0/test/model/000077500000000000000000000000001500374325600202555ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/model/__init__.py000066400000000000000000000000261500374325600223640ustar00rootroot00000000000000"""Test the model.""" zwave-js-server-python-0.63.0/test/model/test_config_manager.py000066400000000000000000000042041500374325600246250ustar00rootroot00000000000000"""Test the config manager.""" from zwave_js_server.client import Client from zwave_js_server.model.config_manager import ConfigManager from zwave_js_server.model.device_config import DeviceConfigDataType from ..common import MockCommandProtocol async def test_lookup_device( client: Client, mock_command: MockCommandProtocol, device_config: DeviceConfigDataType, ) -> None: """Test the lookup_device command.""" # Test successful lookup mock_command( { "command": "config_manager.lookup_device", "manufacturerId": 0x1234, "productType": 0x5678, "productId": 0x9ABC, }, {"config": device_config}, ) config_manager = ConfigManager(client) result = await config_manager.lookup_device(0x1234, 0x5678, 0x9ABC) assert result is not None assert result.manufacturer == "Test Manufacturer" assert result.manufacturer_id == "0x1234" assert result.label == "Test Device" assert result.description == "Test Device Description" assert len(result.devices) == 1 assert result.devices[0].product_type == "0x5678" assert result.devices[0].product_id == "0x9ABC" assert result.firmware_version.min == "1.0" assert result.firmware_version.max == "2.0" # Test lookup with firmware version mock_command( { "command": "config_manager.lookup_device", "manufacturerId": 0x1234, "productType": 0x5678, "productId": 0x9ABC, "firmwareVersion": "1.5", }, {"config": device_config}, ) result = await config_manager.lookup_device(0x1234, 0x5678, 0x9ABC, "1.5") assert result is not None assert result.manufacturer == "Test Manufacturer" assert result.to_dict() == device_config # Test device not found mock_command( { "command": "config_manager.lookup_device", "manufacturerId": 0x4321, "productType": 0x8765, "productId": 0xCBA9, }, {"config": None}, ) result = await config_manager.lookup_device(0x4321, 0x8765, 0xCBA9) assert result is None zwave-js-server-python-0.63.0/test/model/test_controller.py000066400000000000000000002204221500374325600240530ustar00rootroot00000000000000"""Test the controller model.""" from copy import deepcopy import json from unittest.mock import patch import pytest from zwave_js_server.const import ( AssociationCheckResult, ControllerStatus, ExclusionStrategy, InclusionState, InclusionStrategy, NodeType, ProtocolDataRate, Protocols, ProvisioningEntryStatus, QRCodeVersion, RFRegion, SecurityClass, ZwaveFeature, ) from zwave_js_server.event import Event from zwave_js_server.exceptions import RepeaterRssiErrorReceived, RssiErrorReceived from zwave_js_server.model import ( association as association_pkg, controller as controller_pkg, ) from zwave_js_server.model.controller import Controller from zwave_js_server.model.controller.firmware import ControllerFirmwareUpdateStatus from zwave_js_server.model.controller.rebuild_routes import ( RebuildRoutesOptions, RebuildRoutesStatus, ) from zwave_js_server.model.controller.statistics import ControllerStatistics from zwave_js_server.model.node import Node from zwave_js_server.model.node.firmware import NodeFirmwareUpdateInfo from .. import load_fixture FIRMWARE_UPDATE_INFO = { "version": "1.0.0", "changelog": "changelog", "channel": "stable", "files": [{"target": 0, "url": "http://example.com", "integrity": "test"}], "downgrade": True, "normalizedVersion": "1.0.0", "device": { "manufacturerId": 1, "productType": 2, "productId": 3, "firmwareVersion": "0.4.4", "rfRegion": 1, }, } def test_from_state(): """Test from_state method.""" state = json.loads(load_fixture("basic_dump.txt").split("\n")[0])["result"]["state"] ctrl = controller_pkg.Controller(None, state) assert ctrl.sdk_version == "Z-Wave 3.95" assert ctrl.controller_type == 1 assert ctrl.home_id == 3601639587 assert ctrl.own_node_id == 1 assert isinstance(ctrl.own_node, Node) assert ctrl.is_primary assert ctrl.is_using_home_id_from_other_network is False assert ctrl.is_SIS_present is True assert ctrl.was_real_primary is True assert ctrl.is_suc is True assert ctrl.node_type == NodeType.CONTROLLER assert ctrl.firmware_version == "1.0" assert ctrl.manufacturer_id == 134 assert ctrl.product_type == 257 assert ctrl.product_id == 90 assert ctrl.supported_function_types == [ 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 28, 32, 33, 34, 35, 36, 39, 41, 42, 43, 44, 45, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 80, 81, 83, 84, 85, 86, 87, 94, 96, 97, 98, 99, 102, 103, 128, 144, 146, 147, 152, 180, 182, 183, 184, 185, 186, 189, 190, 191, 210, 211, 212, 238, 239, ] assert ctrl.suc_node_id == 1 assert ctrl.supports_timers is False assert ctrl.is_rebuilding_routes is False assert ctrl.inclusion_state == InclusionState.IDLE stats = ctrl.statistics assert ( stats.can == stats.messages_dropped_rx == stats.messages_dropped_tx == stats.messages_rx == stats.messages_tx == stats.nak == stats.timeout_ack == stats.timeout_callback == stats.timeout_response == 0 ) assert ctrl.rf_region is None assert ctrl.rebuild_routes_progress is None def test_controller_mods(client): """Test modifications to controller method.""" state = json.loads(load_fixture("basic_dump.txt").split("\n")[0])["result"]["state"] state["controller"].pop("ownNodeId") state["controller"]["rfRegion"] = 0 state["controller"]["status"] = 0 state["controller"]["rebuildRoutesProgress"] = {1: "pending"} state["controller"]["supportsLongRange"] = True ctrl = controller_pkg.Controller(client, state) assert ctrl.own_node_id is None assert ctrl.own_node is None assert ctrl.rf_region == RFRegion.EUROPE assert ctrl.status == ControllerStatus.READY assert ctrl.rebuild_routes_progress == {ctrl.nodes[1]: RebuildRoutesStatus.PENDING} assert ctrl.supports_long_range is True def test_controller_status(): """Test controller status functionality.""" state = json.loads(load_fixture("basic_dump.txt").split("\n")[0])["result"]["state"] state["controller"]["status"] = 0 ctrl = controller_pkg.Controller(None, state) assert ctrl.status == ControllerStatus.READY event = Event( "status changed", {"source": "controller", "event": "status changed", "status": 1}, ) ctrl.receive_event(event) assert ctrl.status == ControllerStatus.UNRESPONSIVE async def test_begin_inclusion(controller, uuid4, mock_command): """Test begin inclusion.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion(InclusionStrategy.SECURITY_S0) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": {"strategy": InclusionStrategy.SECURITY_S0}, "messageId": uuid4, } async def test_begin_inclusion_default(controller, uuid4, mock_command): """Test begin inclusion.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion(InclusionStrategy.DEFAULT) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.DEFAULT, }, "messageId": uuid4, } async def test_begin_inclusion_default_force_security(controller, uuid4, mock_command): """Test begin inclusion with force_security provided.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion( InclusionStrategy.DEFAULT, force_security=False ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.DEFAULT, "forceSecurity": False, }, "messageId": uuid4, } async def test_begin_inclusion_s2_no_input(controller, uuid4, mock_command): """Test begin inclusion S2 Mode.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion(InclusionStrategy.SECURITY_S2) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": {"strategy": InclusionStrategy.SECURITY_S2}, "messageId": uuid4, } async def test_begin_inclusion_s2_qr_code_string(controller, uuid4, mock_command): """Test begin inclusion S2 Mode with a QR code string.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning="90testtesttesttesttesttesttesttesttesttesttesttesttest", ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": "90testtesttesttesttesttesttesttesttesttesttesttesttest", }, "messageId": uuid4, } # Test invalid QR code length fails with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning="test", ) async def test_begin_inclusion_s2_provisioning_entry(controller, uuid4, mock_command): """Test begin inclusion S2 Mode with a provisioning entry.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) assert await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": { "dsk": "test", "securityClasses": [0], "requestedSecurityClasses": [0], "status": 0, "test": "test", }, }, "messageId": uuid4, } async def test_begin_inclusion_s2_qr_info(controller, uuid4, mock_command): """Test begin inclusion S2 Mode with QR info.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.INACTIVE, version=QRCodeVersion.S2, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=None, ) assert await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": { "version": 0, "securityClasses": [0], "requestedSecurityClasses": [0], "status": 1, "dsk": "test1", "genericDeviceClass": 1, "specificDeviceClass": 2, "installerIconType": 3, "manufacturerId": 4, "productType": 5, "productId": 6, "applicationVersion": "test2", "maxInclusionRequestInterval": 7, "uuid": "test3", }, }, "messageId": uuid4, } async def test_begin_inclusion_s2_dsk(controller, uuid4, mock_command): """Test begin inclusion S2 Mode with DSK string.""" ack_commands = mock_command( {"command": "controller.begin_inclusion"}, {"success": True}, ) assert await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, dsk="test" ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_inclusion", "options": { "strategy": InclusionStrategy.SECURITY_S2, "dsk": "test", }, "messageId": uuid4, } async def test_begin_inclusion_errors(controller, uuid4, mock_command): """Test begin inclusion error scenarios.""" provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) # Test that Security S0 Inclusion Strategy doesn't support providing a provisioning # entry with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S0, provisioning=provisioning_entry ) # Test that Security S0 Inclusion Strategy doesn't support providing a DSK string with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S0, dsk="test" ) # Test that Security S2 Inclusion Strategy doesn't support providing # `force_security` with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, force_security=True ) # Test that Smart Start QR code can't be used async_begin_inclusion provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], version=QRCodeVersion.SMART_START, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=[Protocols.ZWAVE], ) with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry ) provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) # Test that provisioning entry and dsk string can't be provided together with pytest.raises(ValueError): await controller.async_begin_inclusion( InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry, dsk="test" ) async def test_provision_smart_start_node_qr_code_string( controller, uuid4, mock_command ): """Test provision smart start node with a QR code string.""" ack_commands = mock_command( {"command": "controller.provision_smart_start_node"}, {"success": True}, ) await controller.async_provision_smart_start_node("test") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.provision_smart_start_node", "entry": "test", "messageId": uuid4, } async def test_provision_smart_start_node_provisioning_entry( controller, uuid4, mock_command ): """Test provision smart start node with a provisioning entry.""" ack_commands = mock_command( {"command": "controller.provision_smart_start_node"}, {"success": True}, ) provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) await controller.async_provision_smart_start_node(provisioning_entry) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.provision_smart_start_node", "entry": { "dsk": "test", "securityClasses": [0], "requestedSecurityClasses": [0], "status": 0, "test": "test", }, "messageId": uuid4, } async def test_provision_smart_start_node_qr_info(controller, uuid4, mock_command): """Test provision smart start with QR info.""" ack_commands = mock_command( {"command": "controller.provision_smart_start_node"}, {"success": True}, ) provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.INACTIVE, version=QRCodeVersion.SMART_START, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=[Protocols.ZWAVE], ) await controller.async_provision_smart_start_node(provisioning_entry) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.provision_smart_start_node", "entry": { "version": 1, "securityClasses": [0], "requestedSecurityClasses": [0], "status": 1, "dsk": "test1", "genericDeviceClass": 1, "specificDeviceClass": 2, "installerIconType": 3, "manufacturerId": 4, "productType": 5, "productId": 6, "applicationVersion": "test2", "maxInclusionRequestInterval": 7, "uuid": "test3", "supportedProtocols": [0], }, "messageId": uuid4, } ack_commands.clear() # Test that when supported protocols aren't included, it should be None # instead of an empty list. provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.INACTIVE, version=QRCodeVersion.SMART_START, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=None, ) await controller.async_provision_smart_start_node(provisioning_entry) qr_entry = { "version": 1, "securityClasses": [0], "requestedSecurityClasses": [0], "status": 1, "dsk": "test1", "genericDeviceClass": 1, "specificDeviceClass": 2, "installerIconType": 3, "manufacturerId": 4, "productType": 5, "productId": 6, "applicationVersion": "test2", "maxInclusionRequestInterval": 7, "uuid": "test3", } assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.provision_smart_start_node", "entry": qr_entry, "messageId": uuid4, } assert ( qr_entry == controller_pkg.QRProvisioningInformation.from_dict(qr_entry).to_dict() ) assert controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.INACTIVE, version=QRCodeVersion.SMART_START, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=[Protocols.ZWAVE], additional_properties={"test": "foo"}, ) == controller_pkg.QRProvisioningInformation.from_dict( { "version": 1, "securityClasses": [0], "requestedSecurityClasses": [0], "status": 1, "dsk": "test1", "genericDeviceClass": 1, "specificDeviceClass": 2, "installerIconType": 3, "manufacturerId": 4, "productType": 5, "productId": 6, "applicationVersion": "test2", "maxInclusionRequestInterval": 7, "uuid": "test3", "supportedProtocols": [0], "test": "foo", } ) # Test that S2 QR Code can't be used with `async_provision_smart_start_node` provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], version=QRCodeVersion.S2, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=[Protocols.ZWAVE], ) with pytest.raises(ValueError): await controller.async_provision_smart_start_node(provisioning_entry) async def test_unprovision_smart_start_node(controller, uuid4, mock_command): """Test unprovision smart start node.""" ack_commands = mock_command( {"command": "controller.unprovision_smart_start_node"}, {"success": True}, ) await controller.async_unprovision_smart_start_node("test") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.unprovision_smart_start_node", "dskOrNodeId": "test", "messageId": uuid4, } async def test_get_provisioning_entry(controller, uuid4, mock_command): """Test get_provisioning_entry.""" ack_commands = mock_command( {"command": "controller.get_provisioning_entry"}, { "entry": { "dsk": "test", "securityClasses": [0], "requestedSecurityClasses": [0], "test": "test", "status": 0, } }, ) provisioning_entry = await controller.async_get_provisioning_entry("test") assert provisioning_entry == controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.ACTIVE, additional_properties={"test": "test"}, ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_provisioning_entry", "dskOrNodeId": "test", "messageId": uuid4, } async def test_get_provisioning_entry_undefined(controller, uuid4, mock_command): """Test get_provisioning_entry when entry is undefined.""" ack_commands = mock_command( {"command": "controller.get_provisioning_entry"}, {}, ) assert await controller.async_get_provisioning_entry("test") is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_provisioning_entry", "dskOrNodeId": "test", "messageId": uuid4, } async def test_get_provisioning_entries(controller, uuid4, mock_command): """Test get_provisioning_entries.""" ack_commands = mock_command( {"command": "controller.get_provisioning_entries"}, { "entries": [ { "dsk": "test", "securityClasses": [0], "requestedSecurityClasses": [0], "test": "test", "status": 0, } ] }, ) provisioning_entry = await controller.async_get_provisioning_entries() assert provisioning_entry == [ controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.ACTIVE, requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) ] assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_provisioning_entries", "messageId": uuid4, } async def test_stop_inclusion(controller, uuid4, mock_command): """Test stop inclusion.""" ack_commands = mock_command( {"command": "controller.stop_inclusion"}, {"success": True}, ) assert await controller.async_stop_inclusion() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.stop_inclusion", "messageId": uuid4, } async def test_cancel_secure_bootstrap_s2(controller, uuid4, mock_command): """Test cancel secure bootstrap S2.""" ack_commands = mock_command( {"command": "controller.cancel_secure_bootstrap_s2"}, {}, ) assert await controller.async_cancel_secure_bootstrap_s2() is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.cancel_secure_bootstrap_s2", "messageId": uuid4, } async def test_begin_exclusion(controller, uuid4, mock_command): """Test begin exclusion.""" ack_commands = mock_command( {"command": "controller.begin_exclusion"}, {"success": True}, ) assert await controller.async_begin_exclusion() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_exclusion", "messageId": uuid4, } async def test_begin_exclusion_unprovision(controller, uuid4, mock_command): """Test begin exclusion with unprovision set.""" ack_commands = mock_command( {"command": "controller.begin_exclusion"}, {"success": True}, ) assert await controller.async_begin_exclusion(ExclusionStrategy.EXCLUDE_ONLY) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_exclusion", "options": {"strategy": ExclusionStrategy.EXCLUDE_ONLY}, "messageId": uuid4, } async def test_stop_exclusion(controller, uuid4, mock_command): """Test stop exclusion.""" ack_commands = mock_command( {"command": "controller.stop_exclusion"}, {"success": True}, ) assert await controller.async_stop_exclusion() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.stop_exclusion", "messageId": uuid4, } async def test_hash(controller): """Test node hash.""" assert hash(controller) == hash(controller.home_id) async def test_remove_failed_node(controller, multisensor_6, uuid4, mock_command): """Test remove failed node.""" ack_commands = mock_command( {"command": "controller.remove_failed_node"}, {}, ) assert await controller.async_remove_failed_node(multisensor_6) is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.remove_failed_node", "messageId": uuid4, "nodeId": multisensor_6.node_id, } async def test_replace_failed_node(controller, multisensor_6, uuid4, mock_command): """Test replace_failed_node.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S0 ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": {"strategy": InclusionStrategy.SECURITY_S0}, "messageId": uuid4, } async def test_replace_failed_node_default( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.DEFAULT ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": { "strategy": InclusionStrategy.DEFAULT, }, "messageId": uuid4, } async def test_replace_failed_node_default_force_security( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node with force_security provided.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.DEFAULT, force_security=False ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": { "strategy": InclusionStrategy.DEFAULT, "forceSecurity": False, }, "messageId": uuid4, } async def test_replace_failed_node_s2_no_input( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node S2 Mode.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2 ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": {"strategy": InclusionStrategy.SECURITY_S2}, "messageId": uuid4, } async def test_replace_failed_node_s2_qr_code_string( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node S2 Mode with a QR code string.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2, provisioning="90testtesttesttesttesttesttesttesttesttesttesttesttest", ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": "90testtesttesttesttesttesttesttesttesttesttesttesttest", }, "messageId": uuid4, } # Test invalid QR code length fails with pytest.raises(ValueError): await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2, provisioning="test", ) async def test_replace_failed_node_s2_provisioning_entry( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node S2 Mode with a provisioning entry.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": { "dsk": "test", "securityClasses": [0], "requestedSecurityClasses": [0], "status": 0, "test": "test", }, }, "messageId": uuid4, } async def test_replace_failed_node_s2_qr_info( controller, multisensor_6, uuid4, mock_command ): """Test replace_failed_node S2 Mode with QR info.""" ack_commands = mock_command( {"command": "controller.replace_failed_node"}, {"success": True}, ) provisioning_entry = controller_pkg.QRProvisioningInformation( dsk="test1", security_classes=[SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], status=ProvisioningEntryStatus.INACTIVE, version=QRCodeVersion.S2, generic_device_class=1, specific_device_class=2, installer_icon_type=3, manufacturer_id=4, product_type=5, product_id=6, application_version="test2", max_inclusion_request_interval=7, uuid="test3", supported_protocols=None, ) assert await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2, provisioning=provisioning_entry ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.replace_failed_node", "nodeId": multisensor_6.node_id, "options": { "strategy": InclusionStrategy.SECURITY_S2, "provisioning": { "version": 0, "securityClasses": [0], "requestedSecurityClasses": [0], "status": 1, "dsk": "test1", "genericDeviceClass": 1, "specificDeviceClass": 2, "installerIconType": 3, "manufacturerId": 4, "productType": 5, "productId": 6, "applicationVersion": "test2", "maxInclusionRequestInterval": 7, "uuid": "test3", }, }, "messageId": uuid4, } async def test_replace_failed_node_errors(controller, multisensor_6): """Test replace_failed_node error scenarios.""" provisioning_entry = controller_pkg.ProvisioningEntry( "test", [SecurityClass.S2_UNAUTHENTICATED], requested_security_classes=[SecurityClass.S2_UNAUTHENTICATED], additional_properties={"test": "test"}, ) # Test that Security S0 Inclusion strategy can't be combined with a provisioning # entry with pytest.raises(ValueError): await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S0, provisioning=provisioning_entry, ) # Test that Security S2 inclusion strategy can't use force_security with pytest.raises(ValueError): await controller.async_replace_failed_node( multisensor_6, InclusionStrategy.SECURITY_S2, force_security=True ) async def test_rebuild_node_routes(controller, multisensor_6, uuid4, mock_command): """Test rebuild node routes.""" ack_commands = mock_command( {"command": "controller.rebuild_node_routes"}, {"success": True}, ) assert await controller.async_rebuild_node_routes(multisensor_6) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.rebuild_node_routes", "messageId": uuid4, "nodeId": multisensor_6.node_id, } async def test_begin_rebuilding_routes(controller, uuid4, mock_command): """Test begin rebuilding routes.""" ack_commands = mock_command( {"command": "controller.begin_rebuilding_routes"}, {"success": True}, ) assert await controller.async_begin_rebuilding_routes() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.begin_rebuilding_routes", "messageId": uuid4, } options_include_sleeping = RebuildRoutesOptions(True) assert await controller.async_begin_rebuilding_routes(options_include_sleeping) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "controller.begin_rebuilding_routes", "options": {"includeSleeping": True}, "messageId": uuid4, } assert await controller.async_begin_rebuilding_routes(RebuildRoutesOptions()) assert len(ack_commands) == 3 assert ack_commands[2] == { "command": "controller.begin_rebuilding_routes", "options": {}, "messageId": uuid4, } assert ( RebuildRoutesOptions.from_dict({"includeSleeping": True}) == options_include_sleeping ) async def test_stop_rebuilding_routes(client, multisensor_6, uuid4, mock_command): """Test stop rebuilding routes.""" controller = client.driver.controller ack_commands = mock_command( {"command": "controller.stop_rebuilding_routes"}, {"success": True}, ) event = Event( "rebuild routes progress", { "source": "controller", "event": "rebuild routes progress", "progress": {"52": "pending"}, }, ) controller.receive_event(event) assert controller.rebuild_routes_progress == { multisensor_6: RebuildRoutesStatus.PENDING } assert await controller.async_stop_rebuilding_routes() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.stop_rebuilding_routes", "messageId": uuid4, } # Verify that controller.rebuild_routes_progress is cleared assert controller.rebuild_routes_progress is None async def test_is_failed_node(controller, multisensor_6, uuid4, mock_command): """Test is failed node.""" ack_commands = mock_command( {"command": "controller.is_failed_node"}, {"failed": False}, ) assert await controller.async_is_failed_node(multisensor_6) is False assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.is_failed_node", "messageId": uuid4, "nodeId": multisensor_6.node_id, } async def test_get_association_groups(controller, uuid4, mock_command): """Test get association groups.""" issued_commands = {2: [37, 43, 43], 5: [50, 114]} ack_commands = mock_command( {"command": "controller.get_association_groups"}, { "groups": { "1": { "maxNodes": 10, "isLifeline": True, "multiChannel": True, "label": "Association Group 1", }, "2": { "maxNodes": 30, "isLifeline": False, "multiChannel": False, "label": "Association Group 2", "profile": 2, "issuedCommands": issued_commands, }, } }, ) assoc_addr = association_pkg.AssociationAddress(controller, node_id=52) result = await controller.async_get_association_groups(assoc_addr) assert result[1].max_nodes == 10 assert result[1].is_lifeline is True assert result[1].multi_channel is True assert result[1].label == "Association Group 1" assert result[1].profile is None assert result[1].issued_commands == {} assert result[2].max_nodes == 30 assert result[2].is_lifeline is False assert result[2].multi_channel is False assert result[2].label == "Association Group 2" assert result[2].profile == 2 for attr, value in issued_commands.items(): assert result[2].issued_commands[attr] == value assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_association_groups", "messageId": uuid4, "nodeId": assoc_addr.node_id, } async def test_get_associations(controller, uuid4, mock_command): """Test get associations.""" ack_commands = mock_command( {"command": "controller.get_associations"}, { "associations": { "1": [ {"nodeId": 10}, ], "2": [ {"nodeId": 11}, {"nodeId": 20}, ], "3": [ {"nodeId": 30, "endpoint": 0}, {"nodeId": 40, "endpoint": 1}, ], } }, ) assoc_addr = association_pkg.AssociationAddress(controller, node_id=52) result = await controller.async_get_associations(assoc_addr) assert result[1][0].node_id == 10 assert result[1][0].endpoint is None assert result[2][0].node_id == 11 assert result[2][0].endpoint is None assert result[2][1].node_id == 20 assert result[2][1].endpoint is None assert result[3][0].node_id == 30 assert result[3][0].endpoint == 0 assert result[3][1].node_id == 40 assert result[3][1].endpoint == 1 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_associations", "messageId": uuid4, "nodeId": assoc_addr.node_id, } async def test_assoc_addr_model(client, multisensor_6, uuid4, mock_command): """Test association address model.""" cls_ = association_pkg.AssociationAddress controller = client.driver.controller assert cls_(controller, node_id=52).node == multisensor_6 assert cls_(controller, node_id=255).node is None async def test_check_association(controller, uuid4, mock_command): """Test is association allowed.""" ack_commands = mock_command( {"command": "controller.check_association"}, {"result": 1}, ) assoc_addr = association_pkg.AssociationAddress(controller, node_id=52) group = 0 assoc = association_pkg.AssociationAddress(controller, node_id=5, endpoint=0) result = await controller.async_check_association(assoc_addr, group, assoc) assert result is AssociationCheckResult.OK assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.check_association", "messageId": uuid4, "nodeId": assoc_addr.node_id, "group": group, "association": {"nodeId": 5, "endpoint": 0}, } async def test_add_associations(controller, uuid4, mock_command): """Test add associations.""" ack_commands = mock_command( {"command": "controller.add_associations"}, {}, ) assoc_addr = association_pkg.AssociationAddress(controller, node_id=52) group = 0 associations = [ association_pkg.AssociationAddress(controller, node_id=5, endpoint=0), association_pkg.AssociationAddress(controller, node_id=10), ] await controller.async_add_associations(assoc_addr, group, associations) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.add_associations", "messageId": uuid4, "nodeId": assoc_addr.node_id, "group": group, "associations": [ {"nodeId": associations[0].node_id, "endpoint": associations[0].endpoint}, {"nodeId": associations[1].node_id}, ], } assoc_addr = association_pkg.AssociationAddress( controller, node_id=52, endpoint=111 ) group = 1 associations = [ association_pkg.AssociationAddress(controller, node_id=11), association_pkg.AssociationAddress(controller, node_id=6, endpoint=1), ] await controller.async_add_associations(assoc_addr, group, associations, True) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "controller.add_associations", "messageId": uuid4, "nodeId": assoc_addr.node_id, "endpoint": assoc_addr.endpoint, "group": group, "associations": [ {"nodeId": associations[0].node_id}, {"nodeId": associations[1].node_id, "endpoint": associations[1].endpoint}, ], } async def test_remove_associations(controller, uuid4, mock_command): """Test remove associations.""" ack_commands = mock_command( {"command": "controller.remove_associations"}, {}, ) assoc_addr = association_pkg.AssociationAddress(controller, node_id=52) group = 0 associations = [ association_pkg.AssociationAddress(controller, node_id=5, endpoint=0), association_pkg.AssociationAddress(controller, node_id=10), ] await controller.async_remove_associations(assoc_addr, group, associations) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.remove_associations", "messageId": uuid4, "nodeId": assoc_addr.node_id, "group": group, "associations": [ {"nodeId": associations[0].node_id, "endpoint": associations[0].endpoint}, {"nodeId": associations[1].node_id}, ], } assoc_addr = association_pkg.AssociationAddress( controller, node_id=53, endpoint=112 ) group = 1 associations = [ association_pkg.AssociationAddress(controller, node_id=11), association_pkg.AssociationAddress(controller, node_id=6, endpoint=1), ] await controller.async_remove_associations(assoc_addr, group, associations, True) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "controller.remove_associations", "messageId": uuid4, "nodeId": assoc_addr.node_id, "endpoint": assoc_addr.endpoint, "group": group, "associations": [ {"nodeId": associations[0].node_id}, {"nodeId": associations[1].node_id, "endpoint": associations[1].endpoint}, ], } async def test_remove_node_from_all_associations( controller, multisensor_6, uuid4, mock_command ): """Test remove associations.""" ack_commands = mock_command( {"command": "controller.remove_node_from_all_associations"}, {}, ) await controller.async_remove_node_from_all_associations(multisensor_6) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.remove_node_from_all_associations", "messageId": uuid4, "nodeId": multisensor_6.node_id, } await controller.async_remove_node_from_all_associations(multisensor_6, True) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "controller.remove_node_from_all_associations", "messageId": uuid4, "nodeId": multisensor_6.node_id, } async def test_get_node_neighbors(controller, multisensor_6, uuid4, mock_command): """Test get node neighbors.""" ack_commands = mock_command( {"command": "controller.get_node_neighbors"}, {"neighbors": [1, 2]} ) assert await controller.async_get_node_neighbors(multisensor_6) == [1, 2] assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_node_neighbors", "messageId": uuid4, "nodeId": multisensor_6.node_id, } async def test_rebuild_routes_active(client, multisensor_6): """Test that is_rebuilding_routes changes on events.""" controller = client.driver.controller assert controller.is_rebuilding_routes is False assert controller.rebuild_routes_progress is None event = Event( "rebuild routes progress", { "source": "controller", "event": "rebuild routes progress", "progress": {"52": "pending"}, }, ) controller.receive_event(event) assert controller.rebuild_routes_progress == { multisensor_6: RebuildRoutesStatus.PENDING } assert controller.last_rebuild_routes_result is None assert controller.is_rebuilding_routes event = Event( "rebuild routes done", { "source": "controller", "event": "rebuild routes done", "result": {"52": "failed"}, }, ) controller.receive_event(event) assert controller.rebuild_routes_progress is None assert controller.last_rebuild_routes_result == { multisensor_6: RebuildRoutesStatus.FAILED } assert controller.is_rebuilding_routes is False async def test_statistics_updated(controller): """Test that statistics get updated on events.""" assert controller.statistics.nak == 0 statistics_data = { "messagesTX": 1, "messagesRX": 1, "messagesDroppedRX": 1, "NAK": 1, "CAN": 1, "timeoutACK": 1, "timeoutResponse": 1, "timeoutCallback": 1, "messagesDroppedTX": 1, } assert controller.data.get("statistics") != statistics_data event = Event( "statistics updated", { "source": "controller", "event": "statistics updated", "statistics": statistics_data, }, ) controller.receive_event(event) # Event should be modified with the ControllerStatistics object assert "statistics_updated" in event.data event_stats = event.data["statistics_updated"] assert isinstance(event_stats, ControllerStatistics) assert controller.statistics.nak == event_stats.nak == 1 assert event_stats.background_rssi is None assert controller.statistics == event_stats assert controller.data["statistics"] == statistics_data statistics_data = { "messagesTX": 1, "messagesRX": 1, "messagesDroppedRX": 1, "NAK": 1, "CAN": 1, "timeoutACK": 1, "timeoutResponse": 1, "timeoutCallback": 1, "messagesDroppedTX": 1, "backgroundRSSI": { "timestamp": 1234567890, "channel0": { "average": -91, "current": -92, }, "channel1": { "average": -93, "current": -94, }, }, } event = Event( "statistics updated", { "source": "controller", "event": "statistics updated", "statistics": statistics_data, }, ) controller.receive_event(event) event_stats = event.data["statistics_updated"] assert isinstance(event_stats, ControllerStatistics) assert event_stats.background_rssi assert event_stats.background_rssi.timestamp == 1234567890 assert event_stats.background_rssi.channel_0.average == -91 assert event_stats.background_rssi.channel_0.current == -92 assert event_stats.background_rssi.channel_1.average == -93 assert event_stats.background_rssi.channel_1.current == -94 assert event_stats.background_rssi.channel_2 is None statistics_data = { "messagesTX": 1, "messagesRX": 1, "messagesDroppedRX": 1, "NAK": 1, "CAN": 1, "timeoutACK": 1, "timeoutResponse": 1, "timeoutCallback": 1, "messagesDroppedTX": 1, "backgroundRSSI": { "timestamp": 1234567890, "channel0": { "average": -81, "current": -82, }, "channel1": { "average": -83, "current": -84, }, "channel2": { "average": -85, "current": -86, }, }, } event = Event( "statistics updated", { "source": "controller", "event": "statistics updated", "statistics": statistics_data, }, ) controller.receive_event(event) event_stats = event.data["statistics_updated"] assert isinstance(event_stats, ControllerStatistics) assert event_stats.background_rssi assert event_stats.background_rssi.timestamp == 1234567890 assert event_stats.background_rssi.channel_0.average == -81 assert event_stats.background_rssi.channel_0.current == -82 assert event_stats.background_rssi.channel_1.average == -83 assert event_stats.background_rssi.channel_1.current == -84 assert event_stats.background_rssi.channel_2.average == -85 assert event_stats.background_rssi.channel_2.current == -86 async def test_grant_security_classes(controller, uuid4, mock_command) -> None: """Test controller.grant_security_classes command and event.""" ack_commands = mock_command({"command": "controller.grant_security_classes"}, {}) inclusion_grant = controller_pkg.InclusionGrant( [SecurityClass.S2_AUTHENTICATED], True ) inclusion_grant_dict = { "securityClasses": [SecurityClass.S2_AUTHENTICATED.value], "clientSideAuth": True, } await controller.async_grant_security_classes(inclusion_grant) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.grant_security_classes", "messageId": uuid4, "inclusionGrant": inclusion_grant_dict, } # Test grant security classes event event = Event( "grant security classes", { "source": "controller", "event": "grant security classes", "requested": inclusion_grant_dict, }, ) controller.receive_event(event) assert event.data["requested_grant"] == inclusion_grant async def test_validate_dsk_and_enter_pin(controller, uuid4, mock_command) -> None: """Test controller.validate_dsk_and_enter_pin command.""" ack_commands = mock_command( {"command": "controller.validate_dsk_and_enter_pin"}, {} ) await controller.async_validate_dsk_and_enter_pin("test") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.validate_dsk_and_enter_pin", "messageId": uuid4, "pin": "test", } async def test_supports_feature(controller, uuid4, mock_command): """Test supports feature.""" ack_commands = mock_command( {"command": "controller.supports_feature"}, {"supported": True}, ) assert await controller.async_supports_feature(ZwaveFeature.SMART_START) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.supports_feature", "feature": ZwaveFeature.SMART_START.value, "messageId": uuid4, } async def test_get_state(controller, controller_state, uuid4, mock_command): """Test get state.""" new_state = deepcopy(controller_state) new_state["inclusionState"] = 1 ack_commands = mock_command( {"command": "controller.get_state"}, {"state": new_state}, ) assert controller.inclusion_state == InclusionState.IDLE assert await controller.async_get_state() == new_state # Verify state hasn't changed assert controller.inclusion_state == InclusionState.IDLE assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_state", "messageId": uuid4, } async def test_backup_nvm_raw(controller, uuid4, mock_command): """Test backup NVM raw.""" ack_commands = mock_command( {"command": "controller.backup_nvm_raw"}, {"nvmData": "AAAAAAAAAAAAAA=="}, ) assert await controller.async_backup_nvm_raw() == bytes(10) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.backup_nvm_raw", "messageId": uuid4, } async def test_restore_nvm(controller, uuid4, mock_command): """Test restore NVM.""" ack_commands = mock_command( {"command": "controller.restore_nvm"}, {}, ) await controller.async_restore_nvm(bytes(10)) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.restore_nvm", "nvmData": "AAAAAAAAAAAAAA==", "messageId": uuid4, } async def test_backup_nvm_raw_base64(controller, uuid4, mock_command): """Test backup NVM raw with base64 return.""" ack_commands = mock_command( {"command": "controller.backup_nvm_raw"}, {"nvmData": "AAAAAAAAAAAAAA=="}, ) assert await controller.async_backup_nvm_raw_base64() == "AAAAAAAAAAAAAA==" assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.backup_nvm_raw", "messageId": uuid4, } async def test_restore_nvm_base64(controller, uuid4, mock_command): """Test restore NVM with base64 input.""" ack_commands = mock_command( {"command": "controller.restore_nvm"}, {}, ) await controller.async_restore_nvm_base64("AAAAAAAAAAAAAA==") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.restore_nvm", "nvmData": "AAAAAAAAAAAAAA==", "messageId": uuid4, } async def test_set_power_level(controller, uuid4, mock_command): """Test set powerlevel.""" ack_commands = mock_command( {"command": "controller.set_powerlevel"}, {"success": True}, ) assert await controller.async_set_power_level(1, 2) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.set_powerlevel", "powerlevel": 1, "measured0dBm": 2, "messageId": uuid4, } async def test_get_power_level(controller, uuid4, mock_command): """Test get powerlevel.""" ack_commands = mock_command( {"command": "controller.get_powerlevel"}, {"powerlevel": 1, "measured0dBm": 2}, ) assert await controller.async_get_power_level() == { "power_level": 1, "measured_0_dbm": 2, } assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_powerlevel", "messageId": uuid4, } async def test_set_rf_region(controller, uuid4, mock_command): """Test set RF region.""" ack_commands = mock_command( {"command": "controller.set_rf_region"}, {"success": True}, ) assert await controller.async_set_rf_region(RFRegion.USA) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.set_rf_region", "region": RFRegion.USA.value, "messageId": uuid4, } async def test_get_rf_region(controller, uuid4, mock_command): """Test get RF region.""" ack_commands = mock_command( {"command": "controller.get_rf_region"}, {"region": 1}, ) assert await controller.async_get_rf_region() == RFRegion.USA assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_rf_region", "messageId": uuid4, } async def test_get_known_lifeline_routes( multisensor_6, ring_keypad, wallmote_central_scene, uuid4, mock_command ): """Test get known lifeline routes.""" ack_commands = mock_command( {"command": "controller.get_known_lifeline_routes"}, { "routes": { f"{multisensor_6.node_id}": { "lwr": { "protocolDataRate": 1, "repeaters": [f"{multisensor_6.node_id}"], "repeaterRSSI": [1], "routeFailedBetween": [ f"{ring_keypad.node_id}", f"{wallmote_central_scene.node_id}", ], }, "nlwr": { "protocolDataRate": 2, "repeaters": [], "rssi": 1, "repeaterRSSI": [127], }, } } }, ) routes = ( await multisensor_6.client.driver.controller.async_get_known_lifeline_routes() ) assert len(routes) == 1 assert multisensor_6 in routes lifeline_routes = routes[multisensor_6] assert lifeline_routes.lwr assert lifeline_routes.lwr.protocol_data_rate == ProtocolDataRate.ZWAVE_9K6 assert lifeline_routes.lwr.repeaters == [multisensor_6] assert not lifeline_routes.lwr.rssi assert lifeline_routes.lwr.repeater_rssi == [1] assert lifeline_routes.lwr.route_failed_between == ( ring_keypad, wallmote_central_scene, ) assert lifeline_routes.nlwr assert lifeline_routes.nlwr.protocol_data_rate == ProtocolDataRate.ZWAVE_40K assert lifeline_routes.nlwr.repeaters == [] assert lifeline_routes.nlwr.rssi == 1 with pytest.raises(RepeaterRssiErrorReceived): assert lifeline_routes.nlwr.repeater_rssi assert not lifeline_routes.nlwr.route_failed_between assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_known_lifeline_routes", "messageId": uuid4, } async def test_get_known_lifeline_routes_bad_protocol_data_rates( multisensor_6, uuid4, mock_command ): """Test get known lifeline routes with bad protocol data rates.""" ack_commands = mock_command( {"command": "controller.get_known_lifeline_routes"}, { "routes": { f"{multisensor_6.node_id}": { "lwr": { "protocolDataRate": 0, "repeaters": [], "repeaterRSSI": [], "routeFailedBetween": [], }, "nlwr": { "protocolDataRate": 0, "repeaters": [], "rssi": 1, "repeaterRSSI": [], }, } } }, ) routes = ( await multisensor_6.client.driver.controller.async_get_known_lifeline_routes() ) assert len(routes) == 1 assert multisensor_6 in routes lifeline_routes = routes[multisensor_6] assert not lifeline_routes.lwr assert not lifeline_routes.nlwr assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_known_lifeline_routes", "messageId": uuid4, } async def test_is_any_ota_firmware_update_in_progress( multisensor_6, uuid4, mock_command ): """Test get any firmware update progress.""" ack_commands = mock_command( {"command": "controller.is_any_ota_firmware_update_in_progress"}, {"progress": False}, ) controller = multisensor_6.client.driver.controller assert not await controller.async_is_any_ota_firmware_update_in_progress() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.is_any_ota_firmware_update_in_progress", "messageId": uuid4, } async def test_get_available_firmware_updates(multisensor_6, uuid4, mock_command): """Test get available firmware updates.""" ack_commands = mock_command( {"command": "controller.get_available_firmware_updates"}, {"updates": [FIRMWARE_UPDATE_INFO]}, ) controller = multisensor_6.client.driver.controller updates = await controller.async_get_available_firmware_updates( multisensor_6, "test" ) assert len(updates) == 1 update = updates[0] assert update.version == "1.0.0" assert update.changelog == "changelog" assert update.channel == "stable" assert len(update.files) == 1 file = update.files[0] assert file.target == 0 assert file.url == "http://example.com" assert file.integrity == "test" assert update.downgrade assert update.normalized_version == "1.0.0" assert update.device.manufacturer_id == 1 assert update.device.product_type == 2 assert update.device.product_id == 3 assert update.device.firmware_version == "0.4.4" assert update.device.rf_region == RFRegion.USA assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_available_firmware_updates", "nodeId": multisensor_6.node_id, "apiKey": "test", "includePrereleases": True, "messageId": uuid4, } async def test_begin_ota_firmware_update(multisensor_6, uuid4, mock_command): """Test get available firmware updates.""" ack_commands = mock_command( {"command": "controller.firmware_update_ota"}, {"result": {"status": 255, "success": True, "reInterview": False}}, ) result = await multisensor_6.client.driver.controller.async_firmware_update_ota( multisensor_6, NodeFirmwareUpdateInfo.from_dict(FIRMWARE_UPDATE_INFO) ) assert result.status == 255 assert result.success assert not result.reinterview assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.firmware_update_ota", "nodeId": multisensor_6.node_id, "updateInfo": FIRMWARE_UPDATE_INFO, "messageId": uuid4, } async def test_get_known_lifeline_routes_rssi_error( multisensor_6, ring_keypad, wallmote_central_scene, uuid4, mock_command ): """Test get known lifeline routes has an RSSI error.""" ack_commands = mock_command( {"command": "controller.get_known_lifeline_routes"}, { "routes": { f"{multisensor_6.node_id}": { "lwr": { "protocolDataRate": 1, "repeaters": [f"{multisensor_6.node_id}"], "repeaterRSSI": [1], "routeFailedBetween": [ f"{ring_keypad.node_id}", f"{wallmote_central_scene.node_id}", ], }, "nlwr": { "protocolDataRate": 2, "repeaters": [], "rssi": 127, "repeaterRSSI": [127], }, } } }, ) routes = ( await multisensor_6.client.driver.controller.async_get_known_lifeline_routes() ) assert len(routes) == 1 assert multisensor_6 in routes lifeline_routes = routes[multisensor_6] with pytest.raises(RssiErrorReceived): assert lifeline_routes.nlwr.rssi assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.get_known_lifeline_routes", "messageId": uuid4, } async def test_is_firmware_update_in_progress(controller, uuid4, mock_command): """Test is_firmware_update_in_progress command.""" ack_commands = mock_command( {"command": "controller.is_firmware_update_in_progress"}, {"progress": True}, ) assert await controller.async_is_firmware_update_in_progress() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "controller.is_firmware_update_in_progress", "messageId": uuid4, } async def test_nvm_events(controller): """Test NVM progress events.""" event = Event( "nvm backup progress", { "source": "controller", "event": "nvm backup progress", "bytesRead": 1, "total": 2, }, ) controller.receive_event(event) assert event.data["nvm_backup_progress"] == controller_pkg.NVMProgress(1, 2) event = Event( "nvm convert progress", { "source": "controller", "event": "nvm convert progress", "bytesRead": 3, "total": 4, }, ) controller.receive_event(event) assert event.data["nvm_convert_progress"] == controller_pkg.NVMProgress(3, 4) event = Event( "nvm restore progress", { "source": "controller", "event": "nvm restore progress", "bytesWritten": 5, "total": 6, }, ) controller.receive_event(event) assert event.data["nvm_restore_progress"] == controller_pkg.NVMProgress(5, 6) async def test_node_found(controller): """Test node found event.""" found_node = { "id": 1, "deviceClass": { "basic": {"key": 2, "label": "1"}, "generic": {"key": 3, "label": "2"}, "specific": {"key": 4, "label": "3"}, }, "supportedCCs": [112], "controlledCCs": [112], } event = Event( "node found", { "source": "controller", "event": "node found", "node": found_node, }, ) controller.receive_event(event) assert event.data["node"] == found_node async def test_node_added(controller, multisensor_6_state): """Test node added event.""" event = Event( "node added", { "source": "controller", "event": "node added", "node": multisensor_6_state, "result": "", }, ) controller.receive_event(event) assert event.data["node"].node_id == 52 async def test_node_removed(client, multisensor_6, multisensor_6_state): """Test node removed event.""" assert 52 in client.driver.controller.nodes assert client.driver.controller.nodes[52] == multisensor_6 event = Event( "node removed", { "source": "controller", "event": "node removed", "node": multisensor_6_state, "reason": 0, }, ) client.driver.controller.receive_event(event) assert event.data["node"].node_id == 52 assert event.data["node"].client is None assert 52 not in client.driver.controller.nodes async def test_inclusion_aborted(controller): """Test inclusion aborted event.""" event_data = { "source": "controller", "event": "inclusion aborted", } event = Event("inclusion aborted", event_data.copy()) with patch( "zwave_js_server.model.controller.Controller.handle_inclusion_aborted" ) as mock: controller.receive_event(event) assert mock.called # Ensure that the handler doesn't modify the event assert {k: v for k, v in event.data.items() if k != "controller"} == event_data async def test_firmware_events(controller): """Test firmware events.""" assert controller.firmware_update_progress is None event = Event( type="firmware update progress", data={ "source": "controller", "event": "firmware update progress", "progress": { "sentFragments": 1, "totalFragments": 10, "progress": 10.0, }, }, ) controller.receive_event(event) progress = event.data["firmware_update_progress"] assert progress.sent_fragments == 1 assert progress.total_fragments == 10 assert progress.progress == 10.0 assert controller.firmware_update_progress assert controller.firmware_update_progress.sent_fragments == 1 assert controller.firmware_update_progress.total_fragments == 10 assert controller.firmware_update_progress.progress == 10.0 event = Event( type="firmware update finished", data={ "source": "controller", "event": "firmware update finished", "result": {"status": 255, "success": True}, }, ) controller.receive_event(event) result = event.data["firmware_update_finished"] assert result.status == ControllerFirmwareUpdateStatus.OK assert result.success assert controller.firmware_update_progress is None async def test_unknown_event(controller): """Test that an unknown event type causes an exception.""" with pytest.raises(KeyError): assert controller.receive_event( Event("unknown_event", {"source": "controller"}) ) async def test_additional_events(controller: Controller) -> None: """Test that remaining events pass pydantic validation.""" event = Event( "exclusion failed", {"source": "controller", "event": "exclusion failed"} ) controller.receive_event(event) event = Event( "exclusion started", {"source": "controller", "event": "exclusion started"} ) controller.receive_event(event) event = Event( "exclusion stopped", {"source": "controller", "event": "exclusion stopped"} ) controller.receive_event(event) event = Event( "inclusion failed", {"source": "controller", "event": "inclusion failed"} ) controller.receive_event(event) event = Event( "inclusion started", {"source": "controller", "event": "inclusion started", "strategy": 0}, ) controller.receive_event(event) event = Event( "inclusion state changed", {"source": "controller", "event": "inclusion state changed", "state": 1}, ) controller.receive_event(event) event = Event( "inclusion stopped", {"source": "controller", "event": "inclusion stopped"} ) controller.receive_event(event) event = Event( "validate dsk and enter pin", {"source": "controller", "event": "validate dsk and enter pin", "dsk": "1234"}, ) controller.receive_event(event) async def test_identify(client, multisensor_6): """Test identify event.""" event = Event( "identify", {"source": "controller", "event": "identify", "nodeId": multisensor_6.node_id}, ) client.driver.controller.receive_event(event) assert event.data["node"] == multisensor_6 async def test_inclusion_state_changed(controller): """Test that inclusion state is updated after receiving inclusion state changed event.""" assert controller.inclusion_state == InclusionState.IDLE event = Event( "inclusion state changed", { "source": "controller", "event": "inclusion state changed", "state": InclusionState.INCLUDING.value, }, ) controller.receive_event(event) assert controller.inclusion_state == InclusionState.INCLUDING zwave-js-server-python-0.63.0/test/model/test_driver.py000066400000000000000000000306041500374325600231640ustar00rootroot00000000000000"""Test the driver model.""" import json import pytest from zwave_js_server.const import LogLevel from zwave_js_server.event import Event from zwave_js_server.model import ( driver as driver_pkg, log_config as log_config_pkg, log_message as log_message_pkg, ) from .. import load_fixture def test_from_state(client, log_config): """Test from_state method.""" ws_msgs = load_fixture("basic_dump.txt").strip().split("\n") driver = driver_pkg.Driver( client, json.loads(ws_msgs[0])["result"]["state"], log_config ) assert driver == driver_pkg.Driver( client, json.loads(ws_msgs[0])["result"]["state"], log_config ) assert driver != driver.controller.home_id assert hash(driver) == hash(driver.controller.home_id) for msg in ws_msgs[1:]: msg = json.loads(msg) assert msg["type"] == "event" event = Event(type=msg["event"]["event"], data=msg["event"]) driver.receive_event(event) assert len(driver.controller.nodes) == 8 async def test_update_log_config(driver, uuid4, mock_command): """Test update log config.""" # Update log level ack_commands = mock_command( {"command": "driver.update_log_config", "config": {"level": "error"}}, {"success": True}, ) assert ( await driver.async_update_log_config( log_config_pkg.LogConfig(level=LogLevel.ERROR) ) is None ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.update_log_config", "config": {"level": "error"}, "messageId": uuid4, } # Update all parameters ack_commands = mock_command( { "command": "driver.update_log_config", "config": { "enabled": True, "level": "error", "logToFile": True, "filename": "/test.txt", "forceConsole": True, }, }, {"success": True}, ) assert ( await driver.async_update_log_config( log_config_pkg.LogConfig( enabled=True, level=LogLevel.ERROR, log_to_file=True, filename="/test.txt", force_console=True, ) ) is None ) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "driver.update_log_config", "config": { "enabled": True, "level": "error", "logToFile": True, "filename": "/test.txt", "forceConsole": True, }, "messageId": uuid4, } async def test_get_log_config(driver, uuid4, mock_command): """Test set value.""" ack_commands = mock_command( {"command": "driver.get_log_config"}, { "success": True, "config": { "enabled": True, "level": "error", "logToFile": False, "filename": "/test.txt", "forceConsole": False, }, }, ) log_config = await driver.async_get_log_config() assert len(ack_commands) == 1 assert ack_commands[0] == {"command": "driver.get_log_config", "messageId": uuid4} assert log_config.enabled assert log_config.level == LogLevel.ERROR assert log_config.log_to_file is False assert log_config.filename == "/test.txt" assert log_config.force_console is False async def test_listening_logs(client, driver, uuid4, mock_command): """Test listening to logs helpers.""" # Test that start listening to logs command is sent ack_commands = mock_command( {"command": "start_listening_logs"}, {"success": True}, ) await client.async_start_listening_logs() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "start_listening_logs", "messageId": uuid4, } # Test that stop listening to logs command is sent ack_commands = mock_command( {"command": "stop_listening_logs"}, {"success": True}, ) await client.async_stop_listening_logs() assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "stop_listening_logs", "messageId": uuid4, } # Test receiving a log message event event = Event( type="logging", data={ "source": "driver", "event": "logging", "formattedMessage": [ "2021-04-18T18:03:34.051Z CNTRLR [Node 005] [~] \n", "test", ], "level": "debug", "primaryTags": "[Node 005] [~] [Notification]", "secondaryTags": "[Endpoint 0]", "message": "Home Security[Motion sensor status]\n: 8 => 0", "direction": " ", "label": "CNTRLR", "timestamp": "2021-04-18T18:03:34.051Z", "multiline": True, "secondaryTagPadding": -1, "context": { "source": "controller", "type": "node", "nodeId": 5, "header": "Notification", "direction": "none", "change": "notification", "endpoint": 0, }, }, ) driver.receive_event(event) assert "log_message" in event.data assert isinstance(event.data["log_message"], log_message_pkg.LogMessage) log_message = event.data["log_message"] assert log_message.message == ["Home Security[Motion sensor status]", ": 8 => 0"] assert log_message.formatted_message == [ "2021-04-18T18:03:34.051Z CNTRLR [Node 005] [~] ", "test", ] assert log_message.direction == " " assert log_message.primary_tags == "[Node 005] [~] [Notification]" assert log_message.secondary_tags == "[Endpoint 0]" assert log_message.level == "debug" assert log_message.label == "CNTRLR" assert log_message.multiline assert log_message.secondary_tag_padding == -1 assert log_message.timestamp == "2021-04-18T18:03:34.051Z" context = log_message.context assert context.change == "notification" assert context.direction == "none" assert context.endpoint == 0 assert context.header == "Notification" assert context.node_id == 5 assert context.source == "controller" assert context.type == "node" assert context.internal is None assert context.property_ is None assert context.property_key is None assert context.command_class is None async def test_statistics(driver, uuid4, mock_command): """Test statistics commands.""" # Test that enable_statistics command is sent ack_commands = mock_command( { "command": "driver.enable_statistics", "applicationName": "test_name", "applicationVersion": "test_version", }, {"success": True}, ) await driver.async_enable_statistics("test_name", "test_version") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.enable_statistics", "applicationName": "test_name", "applicationVersion": "test_version", "messageId": uuid4, } # Test that disable_statistics command is sent ack_commands = mock_command( {"command": "driver.disable_statistics"}, {"success": True}, ) await driver.async_disable_statistics() assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "driver.disable_statistics", "messageId": uuid4, } # Test that is statistics_enabled command is sent ack_commands = mock_command( {"command": "driver.is_statistics_enabled"}, {"success": True, "statisticsEnabled": True}, ) assert await driver.async_is_statistics_enabled() assert len(ack_commands) == 3 assert ack_commands[2] == { "command": "driver.is_statistics_enabled", "messageId": uuid4, } async def test_log_config_updated(driver): """Test the log_config_updated event.""" # Modify current log config in an update and assert that it changed assert driver.log_config.level != LogLevel.SILLY log_config = driver.log_config.to_dict() log_config["level"] = "silly" event = Event( "log config updated", data={"source": "driver", "event": "log config updated", "config": log_config}, ) driver.receive_event(event) assert driver.log_config.level == LogLevel.SILLY async def test_check_for_config_updates(driver, uuid4, mock_command): """Test driver.check_for_config_updates command.""" ack_commands = mock_command( {"command": "driver.check_for_config_updates"}, {"updateAvailable": False, "installedVersion": "1.0.0"}, ) check_config_updates = await driver.async_check_for_config_updates() assert check_config_updates.installed_version == "1.0.0" assert check_config_updates.update_available is False assert check_config_updates.new_version is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.check_for_config_updates", "messageId": uuid4, } async def test_install_config_update(driver, uuid4, mock_command): """Test driver.install_config_update command.""" ack_commands = mock_command( {"command": "driver.install_config_update"}, {"success": False}, ) assert not await driver.async_install_config_update() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.install_config_update", "messageId": uuid4, } async def test_set_preferred_scales(driver, uuid4, mock_command): """Test driver.set_preferred_scales command.""" ack_commands = mock_command({"command": "driver.set_preferred_scales"}, {}) assert not await driver.async_set_preferred_scales({1: 1}) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.set_preferred_scales", "scales": {1: 1}, "messageId": uuid4, } async def test_hard_reset(driver, uuid4, mock_command): """Test driver hard reset command.""" ack_commands = mock_command({"command": "driver.hard_reset"}, {}) assert not await driver.async_hard_reset() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.hard_reset", "messageId": uuid4, } async def test_try_soft_reset(driver, uuid4, mock_command): """Test driver try soft reset command.""" ack_commands = mock_command({"command": "driver.try_soft_reset"}, {}) assert not await driver.async_try_soft_reset() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.try_soft_reset", "messageId": uuid4, } async def test_soft_reset(driver, uuid4, mock_command): """Test driver soft reset command.""" ack_commands = mock_command({"command": "driver.soft_reset"}, {}) assert not await driver.async_soft_reset() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.soft_reset", "messageId": uuid4, } async def test_shutdown(driver, uuid4, mock_command): """Test driver shutdown command.""" ack_commands = mock_command({"command": "driver.shutdown"}, {"success": True}) assert await driver.async_shutdown() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "driver.shutdown", "messageId": uuid4, } async def test_unknown_event(driver): """Test that an unknown event type causes an exception.""" with pytest.raises(KeyError): assert driver.receive_event(Event("unknown_event", {"source": "driver"})) async def test_all_nodes_ready_event(driver): """Test that the all nodes ready event is succesfully validated by pydantic.""" event = Event("all nodes ready", {"source": "driver", "event": "all nodes ready"}) driver.receive_event(event) async def test_driver_ready_event(driver): """Test that the driver ready event is succesfully validated by pydantic.""" event_type = "driver ready" event_data = {"source": "driver", "event": event_type} event = Event(event_type, event_data) def callback(data: dict) -> None: assert data == event_data driver.on(event_type, callback) driver.receive_event(event) def test_config_manager(driver): """Test the driver has the config manager property.""" assert driver.config_manager is not None assert driver.config_manager._client is driver.client zwave-js-server-python-0.63.0/test/model/test_node.py000066400000000000000000002572621500374325600226310ustar00rootroot00000000000000"""Test the node model.""" import asyncio from copy import deepcopy from datetime import UTC, datetime import json from typing import Any from unittest.mock import AsyncMock, patch import pytest from zwave_js_server.const import ( INTERVIEW_FAILED, CommandClass, CommandStatus, NodeStatus, PowerLevel, ProtocolDataRate, ProtocolVersion, Protocols, RFRegion, SecurityClass, SupervisionStatus, Weekday, ) from zwave_js_server.const.command_class.entry_control import ( EntryControlDataType, EntryControlEventType, ) from zwave_js_server.const.command_class.multilevel_switch import ( MultilevelSwitchCommand, ) from zwave_js_server.const.command_class.power_level import PowerLevelTestStatus from zwave_js_server.event import Event from zwave_js_server.exceptions import ( FailedCommand, NotFoundError, RssiErrorReceived, UnwriteableValue, ) from zwave_js_server.model import endpoint as endpoint_pkg, node as node_pkg from zwave_js_server.model.node import Node from zwave_js_server.model.node.firmware import ( NodeFirmwareUpdateInfo, NodeFirmwareUpdateStatus, ) from zwave_js_server.model.node.health_check import ( LifelineHealthCheckResultDataType, RouteHealthCheckResultDataType, ) from zwave_js_server.model.node.statistics import NodeStatistics from zwave_js_server.model.value import ( ConfigurationValue, ConfigurationValueFormat, SetConfigParameterResult, get_value_id_str, ) from .. import load_fixture # pylint: disable=unused-argument FIRMWARE_UPDATE_INFO = { "version": "1.0.0", "changelog": "changelog", "channel": "stable", "files": [{"target": 0, "url": "http://example.com", "integrity": "test"}], "downgrade": True, "normalizedVersion": "1.0.0", "device": { "manufacturerId": 1, "productType": 2, "productId": 3, "firmwareVersion": "0.4.4", "rfRegion": 1, }, } def test_firmware(): """Test NodeFirmwareUpdateInfo.""" firmware_update_info = NodeFirmwareUpdateInfo.from_dict(FIRMWARE_UPDATE_INFO) assert firmware_update_info.version == "1.0.0" assert firmware_update_info.changelog == "changelog" assert firmware_update_info.channel == "stable" assert len(firmware_update_info.files) == 1 assert firmware_update_info.files[0].target == 0 assert firmware_update_info.files[0].url == "http://example.com" assert firmware_update_info.files[0].integrity == "test" assert firmware_update_info.downgrade assert firmware_update_info.normalized_version == "1.0.0" assert firmware_update_info.device.manufacturer_id == 1 assert firmware_update_info.device.product_type == 2 assert firmware_update_info.device.product_id == 3 assert firmware_update_info.device.firmware_version == "0.4.4" assert firmware_update_info.device.rf_region == RFRegion.USA assert firmware_update_info.to_dict() == FIRMWARE_UPDATE_INFO def test_from_state(client): """Test from_state method.""" state = json.loads(load_fixture("basic_dump.txt").split("\n")[0])["result"]["state"] node = node_pkg.Node(client, state["nodes"][0]) assert node.node_id == 1 assert node.index == 0 assert node.status == 4 assert node.ready is True assert node.device_class.basic.key == 2 assert node.device_class.generic.label == "Static Controller" assert node.is_listening is True assert node.is_frequent_listening is False assert node.is_routing is False assert node.max_data_rate == 100000 assert node.supported_data_rates == [40000, 100000] assert node.is_secure is False assert node.protocol is None assert node.protocol_version == ProtocolVersion.VERSION_4_5X_OR_6_0X assert node.supports_beaming is True assert node.supports_security is False assert node.zwave_plus_node_type is None assert node.zwave_plus_role_type is None assert node.manufacturer_id == 134 assert node.product_id == 90 assert node.product_type == 257 assert node.label == "ZW090" assert node.interview_attempts == 0 assert node.installer_icon is None assert node.user_icon is None assert node.firmware_version is None assert node.name is None assert node.zwave_plus_version is None assert node.location is None assert node.endpoint_count_is_dynamic is None assert node.endpoints_have_identical_capabilities is None assert node.individual_endpoint_count is None assert node.aggregated_endpoint_count is None assert node.interview_stage == "Neighbors" assert not node.is_controller_node assert not node.keep_awake assert len(node.command_classes) == 0 assert len(node.endpoints) == 1 assert node.endpoints[0].index == 0 assert node.endpoints[0].installer_icon is None assert node.endpoints[0].user_icon is None assert node.endpoints[0].command_classes == [] assert node.endpoints[0].endpoint_label is None device_class = node.endpoints[0].device_class assert device_class.basic.key == 2 assert device_class.generic.key == 2 assert device_class.specific.key == 1 stats = node.statistics assert ( stats.commands_dropped_rx == stats.commands_dropped_tx == stats.commands_rx == stats.commands_tx == stats.timeout_response == 0 ) assert node == node_pkg.Node(client, state["nodes"][0]) assert node != node.node_id assert hash(node) == hash((client.driver, node.node_id)) assert node.endpoints[0] == endpoint_pkg.Endpoint( client, node, state["nodes"][0]["endpoints"][0], {} ) assert node.endpoints[0] != node.endpoints[0].index assert hash(node.endpoints[0]) == hash((client.driver, node.node_id, 0)) assert node.last_seen is None event = Event( "statistics updated", { "source": "node", "event": "statistics updated", "nodeId": node.node_id, "statistics": { "commandsTX": 1, "commandsRX": 2, "commandsDroppedTX": 3, "commandsDroppedRX": 4, "timeoutResponse": 5, "rssi": 7, "lastSeen": "2023-07-18T15:42:34.701Z", }, }, ) node.receive_event(event) assert node.last_seen == datetime(2023, 7, 18, 15, 42, 34, 701000, UTC) async def test_last_seen(lock_schlage_be469): """Test last seen property.""" assert lock_schlage_be469.last_seen == datetime( 2023, 7, 18, 15, 42, 34, 701000, UTC ) assert ( lock_schlage_be469.last_seen == lock_schlage_be469.statistics.last_seen == datetime.fromisoformat(lock_schlage_be469.statistics.data.get("lastSeen")) ) async def test_highest_security_value(lock_schlage_be469, ring_keypad): """Test the highest_security_class property.""" assert lock_schlage_be469.highest_security_class == SecurityClass.S0_LEGACY assert ring_keypad.highest_security_class is None async def test_command_classes(endpoints_with_command_classes: Node) -> None: """Test command_classes property on endpoint.""" node = endpoints_with_command_classes assert len(node.endpoints[0].command_classes) == 17 command_class_info = node.endpoints[0].command_classes[0] assert command_class_info.id == 38 assert command_class_info.command_class == CommandClass.SWITCH_MULTILEVEL assert command_class_info.name == "Multilevel Switch" assert command_class_info.version == 2 assert command_class_info.is_secure is False assert command_class_info.to_dict() == command_class_info.data async def test_device_config( wallmote_central_scene, climate_radio_thermostat_ct100_plus ): """Test a device config.""" node: node_pkg.Node = wallmote_central_scene device_config = node.device_config assert device_config.is_embedded assert device_config.filename == ( "/usr/src/app/node_modules/@zwave-js/config/config/devices/0x0086/zw130.json" ) assert device_config.manufacturer == "AEON Labs" assert device_config.manufacturer_id == 134 assert device_config.label == "ZW130" assert device_config.description == "WallMote Quad" assert len(device_config.devices) == 3 assert device_config.devices[0].product_id == 130 assert device_config.devices[0].product_type == 2 assert device_config.firmware_version.min == "0.0" assert device_config.firmware_version.max == "255.255" assert device_config.metadata.inclusion == ( "To add the ZP3111 to the Z-Wave network (inclusion), place the Z-Wave " "primary controller into inclusion mode. Press the Program Switch of ZP3111 " "for sending the NIF. After sending NIF, Z-Wave will send the auto inclusion, " "otherwise, ZP3111 will go to sleep after 20 seconds." ) assert device_config.metadata.exclusion == ( "To remove the ZP3111 from the Z-Wave network (exclusion), place the Z-Wave " "primary controller into \u201cexclusion\u201d mode, and following its " "instruction to delete the ZP3111 to the controller. Press the Program Switch " "of ZP3111 once to be excluded." ) assert device_config.metadata.reset == ( "Remove cover to trigged tamper switch, LED flash once & send out Alarm " "Report. Press Program Switch 10 times within 10 seconds, ZP3111 will send " "the \u201cDevice Reset Locally Notification\u201d command and reset to the " "factory default. (Remark: This is to be used only in the case of primary " "controller being inoperable or otherwise unavailable.)" ) assert device_config.metadata.manual == ( "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=" "MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf" ) assert device_config.metadata.wakeup is None assert device_config.metadata.comments == [{"level": "info", "text": "test"}] assert device_config.associations == {} assert device_config.param_information == {"_map": {}} assert device_config.supports_zwave_plus is None assert climate_radio_thermostat_ct100_plus.device_config.metadata.comments == [] async def test_protocol(client, wallmote_central_scene_state): """Test protocol of a node.""" node_state = deepcopy(wallmote_central_scene_state) node_state["protocol"] = 0 node = node_pkg.Node(client, node_state) assert node.protocol is Protocols.ZWAVE async def test_endpoint_no_device_class(climate_radio_thermostat_ct100_plus): """Test endpoint without a device class.""" assert climate_radio_thermostat_ct100_plus.endpoints[0].device_class is None async def test_unknown_values(cover_qubino_shutter): """Test that values that are unknown return as None.""" node = cover_qubino_shutter assert ( "5-38-0-currentValue" in node.values and node.values["5-38-0-currentValue"].value is None ) assert ( "5-37-0-currentValue" in node.values and node.values["5-37-0-currentValue"].value is None ) async def test_device_database_url(cover_qubino_shutter): """Test that the device database URL is available.""" assert ( cover_qubino_shutter.device_database_url == "https://devices.zwave-js.io/?jumpTo=0x0159:0x0003:0x0053:0.0" ) async def test_values_without_property_key_name(multisensor_6): """Test that values with property key and without property key name can be found.""" node = multisensor_6 assert "52-112-0-101-1" in node.values assert "52-112-0-101-16" in node.values async def test_hash(climate_radio_thermostat_ct100_plus): """Test node hash.""" node = climate_radio_thermostat_ct100_plus assert hash(node) == hash((node.client.driver, node.node_id)) async def test_command_class_values(climate_radio_thermostat_ct100_plus): """Test node methods to get command class values.""" node = climate_radio_thermostat_ct100_plus assert node.node_id == 13 switch_values = node.get_command_class_values(CommandClass.SENSOR_MULTILEVEL) assert len(switch_values) == 2 with pytest.raises(UnwriteableValue): await node.async_set_value("13-112-0-2", 1) async def test_set_value(multisensor_6, uuid4, mock_command): """Test set value.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"success": True}, ) value_id = "52-32-0-targetValue" assert await node.async_set_value(value_id, 42) is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": {"commandClass": 32, "endpoint": 0, "property": "targetValue"}, "value": 42, "messageId": uuid4, } # Set value with options assert await node.async_set_value(value_id, 42, {"transitionDuration": 1}) is None assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": {"commandClass": 32, "endpoint": 0, "property": "targetValue"}, "value": 42, "options": {"transitionDuration": 1}, "messageId": uuid4, } # Set value with illegal option with pytest.raises(NotFoundError): await node.async_set_value(value_id, 42, {"fake_option": 1}) # Use invalid value with pytest.raises(NotFoundError): await node.async_set_value(f"{value_id}_fake_value", 42) async def test_set_value_node_status_change(driver, multisensor_6_state): """Test set value when node status changes.""" async def async_send_command( message: dict[str, Any], require_schema: int | None = None ) -> dict: """Send a mock command that never returns.""" block_event = asyncio.Event() await block_event.wait() with patch("zwave_js_server.client.Client", autospec=True) as client_class: client = client_class.return_value client.driver = driver client.async_send_command = AsyncMock(side_effect=async_send_command) node = node_pkg.Node(client, multisensor_6_state) # wake up node event = Event(type="wake up") node.handle_wake_up(event) task = asyncio.create_task(node.async_send_command("mock_cmd")) task_2 = asyncio.create_task(node.endpoints[0].async_send_command("mock_cmd")) await asyncio.sleep(0.01) # we are waiting for the response assert not task.done() assert not task_2.done() # node goes to sleep event = Event(type="sleep") node.handle_sleep(event) await asyncio.sleep(0.01) # we are no longer waiting for the response assert task.done() assert task.result() is None assert task_2.done() assert task_2.result() is None async def test_poll_value(multisensor_6, uuid4, mock_command): """Test poll value.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.poll_value", "nodeId": node.node_id}, {"result": "something"}, ) value_id = "52-32-0-currentValue" assert await node.async_poll_value(value_id) is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.poll_value", "nodeId": node.node_id, "valueId": {"commandClass": 32, "endpoint": 0, "property": "currentValue"}, "messageId": uuid4, } async def test_ping(multisensor_6, uuid4, mock_command): """Test ping.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.ping", "nodeId": node.node_id}, {"responded": True}, ) assert await node.async_ping() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.ping", "nodeId": node.node_id, "messageId": uuid4, } async def test_refresh_info(multisensor_6, uuid4, mock_command): """Test refresh info.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.refresh_info", "nodeId": node.node_id}, {}, ) assert await node.async_refresh_info() is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.refresh_info", "nodeId": node.node_id, "messageId": uuid4, } async def test_value_added_event(multisensor_6): """Test Node value removed event.""" node = multisensor_6 assert "52-112-0-2" in node.values event = Event( type="value removed", data={ "source": "node", "event": "value removed", "nodeId": 52, "args": { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 2, "propertyName": "Stay Awake in Battery Mode", "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": False, "states": {"0": "Disable", "1": "Enable"}, "label": "Stay Awake in Battery Mode", "description": "Stay awake for 10 minutes at power on", "isFromConfig": True, }, "value": 0, }, }, ) node.handle_value_removed(event) assert "52-112-0-2" not in node.values async def test_get_defined_value_ids(multisensor_6, uuid4, mock_command): """Test get defined value ids.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_defined_value_ids", "nodeId": node.node_id}, { "valueIds": [ { "commandClassName": "Wake Up", "commandClass": 132, "endpoint": 0, "property": "wakeUpInterval", "propertyName": "wakeUpInterval", }, { "commandClassName": "Wake Up", "commandClass": 132, "endpoint": 0, "property": "controllerNodeId", "propertyName": "controllerNodeId", }, ] }, ) result = await node.async_get_defined_value_ids() assert len(result) == 2 assert result[0].command_class_name == "Wake Up" assert result[0].command_class == 132 assert result[0].endpoint == 0 assert result[0].property_ == "wakeUpInterval" assert result[0].property_name == "wakeUpInterval" assert result[1].command_class_name == "Wake Up" assert result[1].command_class == 132 assert result[1].endpoint == 0 assert result[1].property_ == "controllerNodeId" assert result[1].property_name == "controllerNodeId" assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_defined_value_ids", "nodeId": node.node_id, "messageId": uuid4, } async def test_get_value_metadata(multisensor_6, uuid4, mock_command): """Test get value metadata.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_value_metadata", "nodeId": node.node_id}, { "type": "any", "readable": True, "writeable": False, "label": "Node ID of the controller", "description": "Description of the value metadata", }, ) result = await node.async_get_value_metadata("52-32-0-targetValue") assert result.type == "any" assert result.readable is True assert result.writeable is False assert result.label == "Node ID of the controller" assert result.description == "Description of the value metadata" assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_value_metadata", "nodeId": node.node_id, "valueId": {"commandClass": 32, "endpoint": 0, "property": "targetValue"}, "messageId": uuid4, } ack_commands.clear() async def test_abort_firmware_update(multisensor_6, uuid4, mock_command): """Test abort firmware update.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.abort_firmware_update", "nodeId": node.node_id}, {}, ) assert await node.async_abort_firmware_update() is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.abort_firmware_update", "nodeId": node.node_id, "messageId": uuid4, } def test_node_inclusion(multisensor_6_state): """Emulate a node being added.""" # when a node node is added, it has minimal info first node = node_pkg.Node( None, {"nodeId": 52, "status": 1, "ready": False, "values": [], "endpoints": []} ) assert node.node_id == 52 assert node.status == 1 assert not node.ready assert len(node.values) == 0 assert node.device_config.manufacturer is None # the ready event contains a full (and complete) dump of the node, including values event = Event( "ready", { "event": "ready", "source": "node", "nodeId": node.node_id, "nodeState": multisensor_6_state, "result": [], }, ) node.receive_event(event) assert node.device_config.manufacturer == "AEON Labs" assert len(node.values) > 0 new_state = deepcopy(multisensor_6_state) new_state["values"].append( { "commandClassName": "Binary Sensor", "commandClass": 48, "endpoint": 0, "property": "test", "propertyName": "test", "metadata": { "type": "boolean", "readable": True, "writeable": False, "label": "Any", "ccSpecific": {"sensorType": 255}, }, "value": False, } ) new_state["endpoints"].append( {"nodeId": 52, "index": 1, "installerIcon": 3079, "userIcon": 3079} ) event = Event( "ready", { "event": "ready", "source": "node", "nodeId": node.node_id, "nodeState": new_state, "result": [], }, ) node.receive_event(event) assert "52-48-0-test" in node.values assert 1 in node.endpoints new_state = deepcopy(new_state) new_state["endpoints"].pop(1) event = Event( "ready", { "event": "ready", "source": "node", "nodeId": node.node_id, "nodeState": multisensor_6_state, "result": [], }, ) node.receive_event(event) assert 1 not in node.endpoints def test_node_ready_event(switch_enbrighten_zw3010_state): """Emulate a node ready event.""" # when a node node is added, it has minimal info first node = node_pkg.Node( None, {"nodeId": 2, "status": 1, "ready": False, "values": [], "endpoints": []} ) assert node.node_id == 2 assert node.status == 1 assert not node.ready assert len(node.values) == 0 assert node.device_config.manufacturer is None # the ready event contains a full (and complete) dump of the node, including values event = Event( "ready", { "event": "ready", "source": "node", "nodeId": node.node_id, "nodeState": switch_enbrighten_zw3010_state, "result": [], }, ) # This will fail if the schema is invalid node.receive_event(event) assert len(node.values) > 0 async def test_node_status_events(multisensor_6): """Test Node status events.""" node = multisensor_6 assert node.status == NodeStatus.ASLEEP # mock node wake up event event = Event(type="wake up") node.handle_wake_up(event) assert node.status == NodeStatus.AWAKE # mock node dead event event = Event(type="dead") node.handle_dead(event) assert node.status == NodeStatus.DEAD # mock node alive event event = Event(type="alive") node.handle_alive(event) assert node.status == NodeStatus.ALIVE # mock node sleep event event = Event(type="sleep") node.handle_sleep(event) assert node.status == NodeStatus.ASLEEP async def test_value_added_events(multisensor_6): """Test Node value added events for new value.""" node = multisensor_6 value_id = "52-112-0-6" # Validate that the value doesn't exist in the node state data assert value_id not in node.values event = Event( type="value added", data={ "source": "node", "event": "value added", "nodeId": 52, "args": { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 6, "propertyName": "Stay Awake in Battery Mode", "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 1, "min": 0, "max": 1, "default": 0, "format": 0, "allowManualEntry": False, "states": {"0": "Disable", "1": "Enable"}, "label": "Stay Awake in Battery Mode", "description": "Stay awake for 10 minutes at power on", "isFromConfig": True, }, "value": 0, }, }, ) node.handle_value_added(event) assert isinstance(event.data["value"], ConfigurationValue) assert isinstance(node.values[value_id], ConfigurationValue) # ensure that the value was added to the node's state data assert value_id in node.values async def test_value_updated_events(multisensor_6): """Test Node value updated events.""" node = multisensor_6 value_id = "52-112-0-2" # ensure that the value is in the node's state data assert value_id in node.values # assert the old value of the ZwaveValue assert (value_data := node.values[value_id].data) is not None assert value_data["value"] == node.values[value_id].value == 0 event = Event( type="value updated", data={ "source": "node", "event": "value updated", "nodeId": 52, "args": { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 2, "propertyName": "Stay Awake in Battery Mode", "value": -1, "newValue": 1, "prevValue": 0, }, }, ) node.handle_value_updated(event) assert isinstance(event.data["value"], ConfigurationValue) assert isinstance(node.values[value_id], ConfigurationValue) # ensure that the value is in to the node's state data assert value_id in node.values # ensure that the node's state data was updated and that old keys were removed assert (value_data := node.values[value_id].data) is not None assert value_data["metadata"] assert value_data["value"] == 1 assert "newValue" not in value_data assert "prevValue" not in value_data # ensure that the value's state data was updated and that old keys were removed val = node.values[value_id] assert val.data["value"] == 1 assert val.value == 1 assert "newValue" not in val.data assert "prevValue" not in val.data async def test_value_removed_events(multisensor_6): """Test Node value removed events.""" node = multisensor_6 value_id = "52-112-0-2" event = Event( type="value removed", data={ "source": "node", "event": "value removed", "nodeId": 52, "args": { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 2, "propertyName": "Stay Awake in Battery Mode", "prevValue": 0, }, }, ) node.handle_value_removed(event) assert isinstance(event.data["value"], ConfigurationValue) # ensure that the value was removed from the nodes value's dict assert node.values.get(value_id) is None # ensure that the value was removed from the node's state data assert value_id not in node.values async def test_value_notification(wallmote_central_scene: node_pkg.Node): """Test value notification events.""" node = wallmote_central_scene # Validate that metadata gets added to notification when it's not included event = Event( type="value notification", data={ "source": "node", "event": "value notification", "nodeId": 35, "args": { "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "002", "propertyName": "scene", "propertyKeyName": "002", "ccVersion": 2, "value": 1, }, }, ) node.handle_value_notification(event) assert event.data["value_notification"].metadata.states assert event.data["value_notification"].endpoint is not None assert event.data["value_notification"].value == 1 # Let's make sure that the Value was not updated by the value notification event assert node.values["35-91-0-scene-002"].value is None # Validate that a value notification event for an unknown value gets returned as is event = Event( type="value notification", data={ "source": "node", "event": "value notification", "nodeId": 35, "args": { "commandClass": 91, "commandClassName": "Central Scene", "property": "scene", "propertyKey": "005", "propertyName": "scene", "propertyKeyName": "005", "ccVersion": 2, "value": 2, }, }, ) node.handle_value_notification(event) assert event.data["value_notification"].command_class == 91 assert event.data["value_notification"].command_class_name == "Central Scene" assert event.data["value_notification"].property_ == "scene" assert event.data["value_notification"].property_name == "scene" assert event.data["value_notification"].property_key == "005" assert event.data["value_notification"].property_key_name == "005" assert event.data["value_notification"].value == 2 async def test_metadata_updated(climate_radio_thermostat_ct100_plus: node_pkg.Node): """Test metadata updated events.""" node = climate_radio_thermostat_ct100_plus value = node.values["13-135-1-value"] assert not value.metadata.states # Validate that states becomes available on a value that doesn't have a state when # a metadata updated event with states is received event = Event( type="value notification", data={ "source": "node", "event": "metadata updated", "nodeId": 13, "args": { "commandClassName": "Indicator", "commandClass": 135, "endpoint": 1, "property": "value", "propertyName": "value", "metadata": { "type": "number", "readable": True, "writeable": True, "min": 0, "max": 255, "label": "Indicator value", "ccSpecific": {"indicatorId": 0}, "states": { "0": "Idle", "1": "Heating", "2": "Cooling", "3": "Fan Only", "4": "Pending Heat", "5": "Pending Cool", "6": "Vent/Economizer", "7": "Aux Heating", "8": "2nd Stage Heating", "9": "2nd Stage Cooling", "10": "2nd Stage Aux Heat", "11": "3rd Stage Aux Heat", }, }, "value": 0, }, }, ) node.handle_metadata_updated(event) assert value.metadata.states async def test_notification(lock_schlage_be469: node_pkg.Node): """Test notification CC notification events.""" node = lock_schlage_be469 # Validate that Entry Control CC notification event is received as expected event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "ccId": 111, "endpointIndex": 0, "args": { "eventType": 0, "eventTypeLabel": "a", "dataType": 0, "dataTypeLabel": "b", "eventData": "test", }, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.ENTRY_CONTROL assert event.data["notification"].node_id == 23 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].event_type == EntryControlEventType.CACHING assert event.data["notification"].event_type_label == "a" assert event.data["notification"].data_type == EntryControlDataType.NONE assert event.data["notification"].data_type_label == "b" assert event.data["notification"].event_data == "test" # Validate that Notification CC notification event is received as expected event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "endpointIndex": 0, "ccId": 113, "args": { "type": 6, "event": 5, "label": "Access Control", "eventLabel": "Keypad lock operation", "parameters": {"userId": 1}, }, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.NOTIFICATION assert event.data["notification"].node_id == 23 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].type_ == 6 assert event.data["notification"].event == 5 assert event.data["notification"].label == "Access Control" assert event.data["notification"].event_label == "Keypad lock operation" assert event.data["notification"].parameters == {"userId": 1} # Validate that Power Level CC notification event is received as expected event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "endpointIndex": 0, "ccId": CommandClass.POWERLEVEL.value, "args": {"testNodeId": 1, "status": 0, "acknowledgedFrames": 2}, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.POWERLEVEL assert event.data["notification"].node_id == 23 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].test_node_id == 1 assert event.data["notification"].status == PowerLevelTestStatus.FAILED assert event.data["notification"].acknowledged_frames == 2 # Validate that Multilevel Switch CC notification event is received as expected event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "endpointIndex": 0, "ccId": CommandClass.SWITCH_MULTILEVEL.value, "args": {"direction": "up", "eventType": 4, "eventTypeLabel": "c"}, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.SWITCH_MULTILEVEL assert event.data["notification"].node_id == 23 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].direction == "up" assert ( event.data["notification"].event_type == MultilevelSwitchCommand.START_LEVEL_CHANGE ) assert event.data["notification"].event_type_label == "c" # Validate that Multilevel Switch CC notification event without a direction is valid event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "endpointIndex": 0, "ccId": CommandClass.SWITCH_MULTILEVEL.value, "args": {"eventType": 4, "eventTypeLabel": "c"}, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.SWITCH_MULTILEVEL assert event.data["notification"].node_id == 23 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].direction is None assert ( event.data["notification"].event_type == MultilevelSwitchCommand.START_LEVEL_CHANGE ) assert event.data["notification"].event_type_label == "c" async def test_notification_unknown(lock_schlage_be469: node_pkg.Node, caplog): """Test unrecognized command class notification events.""" # Validate that an unrecognized CC notification event raises Exception node = lock_schlage_be469 event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 23, "ccId": 0, }, ) node.handle_notification(event) assert "notification" not in event.data async def test_entry_control_notification(ring_keypad): """Test entry control CC notification events.""" node = ring_keypad # Validate that Entry Control CC notification event is received as expected event = Event( type="notification", data={ "source": "node", "event": "notification", "nodeId": 10, "endpointIndex": 0, "ccId": 111, "args": { "eventType": 5, "eventTypeLabel": "foo", "dataType": 2, "dataTypeLabel": "bar", "eventData": "cat", }, }, ) node.handle_notification(event) assert event.data["notification"].command_class == CommandClass.ENTRY_CONTROL assert event.data["notification"].node_id == 10 assert event.data["notification"].endpoint_idx == 0 assert event.data["notification"].event_type == EntryControlEventType.ARM_AWAY assert event.data["notification"].event_type_label == "foo" assert event.data["notification"].data_type == EntryControlDataType.ASCII assert event.data["notification"].data_type_label == "bar" assert event.data["notification"].event_data == "cat" async def test_interview_events(multisensor_6): """Test Node interview events.""" node = multisensor_6 assert node.interview_stage is None assert node.ready assert not node.in_interview event = Event( type="interview started", data={ "source": "node", "event": "interview started", "nodeId": 52, }, ) node.handle_interview_started(event) assert node.interview_stage is None assert not node.ready assert not node.in_interview assert node.awaiting_manual_interview event = Event( type="interview stage completed", data={ "source": "node", "event": "interview stage completed", "nodeId": 52, "stageName": "test", }, ) node.handle_interview_stage_completed(event) assert node.interview_stage == "test" assert not node.ready assert node.in_interview event = Event( type="interview failed", data={ "source": "node", "event": "interview failed", "nodeId": 52, }, ) node.handle_interview_failed(event) assert node.interview_stage == INTERVIEW_FAILED assert not node.ready assert not node.in_interview event = Event( type="interview completed", data={ "source": "node", "event": "interview completed", "nodeId": 52, }, ) node.handle_interview_completed(event) assert node.ready assert not node.in_interview async def test_refresh_values(multisensor_6, uuid4, mock_command): """Test refresh_values and refresh_cc_values commands.""" node: node_pkg.Node = multisensor_6 ack_commands = mock_command( {"command": "node.refresh_values", "nodeId": node.node_id}, {"success": True}, ) await node.async_refresh_values() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.refresh_values", "nodeId": node.node_id, "messageId": uuid4, } ack_commands = mock_command( { "command": "node.refresh_cc_values", "nodeId": node.node_id, "commandClass": 112, }, {"success": True}, ) await node.async_refresh_cc_values(CommandClass.CONFIGURATION) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "node.refresh_cc_values", "nodeId": node.node_id, "commandClass": 112, "messageId": uuid4, } async def test_firmware_events(wallmote_central_scene: node_pkg.Node): """Test firmware events.""" node = wallmote_central_scene assert node.firmware_update_progress is None event = Event( type="firmware update progress", data={ "source": "node", "event": "firmware update progress", "nodeId": 35, "progress": { "currentFile": 1, "totalFiles": 1, "sentFragments": 1, "totalFragments": 10, "progress": 10.0, }, }, ) node.handle_firmware_update_progress(event) progress = event.data["firmware_update_progress"] assert progress.current_file == 1 assert progress.total_files == 1 assert progress.sent_fragments == 1 assert progress.total_fragments == 10 assert progress.progress == 10.0 assert node.firmware_update_progress assert node.firmware_update_progress.current_file == 1 assert node.firmware_update_progress.total_files == 1 assert node.firmware_update_progress.sent_fragments == 1 assert node.firmware_update_progress.total_fragments == 10 assert node.firmware_update_progress.progress == 10.0 event = Event( type="firmware update finished", data={ "source": "node", "event": "firmware update finished", "nodeId": 35, "result": { "status": 255, "success": True, "waitTime": 10, "reInterview": False, }, }, ) node.handle_firmware_update_finished(event) result = event.data["firmware_update_finished"] assert result.status == NodeFirmwareUpdateStatus.OK_RESTART_PENDING assert result.success assert result.wait_time == 10 assert not result.reinterview assert node.firmware_update_progress is None async def test_value_added_value_exists(climate_radio_thermostat_ct100_plus): """Test value added event when value exists.""" node: node_pkg.Node = climate_radio_thermostat_ct100_plus value_id = f"{node.node_id}-128-1-isHigh" value = node.values.get(value_id) assert value event = Event( "value added", { "source": "node", "event": "value added", "nodeId": node.node_id, "args": { "commandClassName": "Battery", "commandClass": 128, "endpoint": 1, "property": "isHigh", "propertyName": "isHigh", "metadata": { "type": "boolean", "readable": True, "writeable": False, "label": "High battery level", }, "value": True, }, }, ) node.receive_event(event) assert value_id in node.values assert node.values[value_id] is value async def test_value_added_new_value(climate_radio_thermostat_ct100_plus): """Test value added event when new value is added.""" node: node_pkg.Node = climate_radio_thermostat_ct100_plus event = Event( "value added", { "source": "node", "event": "value added", "nodeId": node.node_id, "args": { "commandClassName": "Battery", "commandClass": 128, "endpoint": 1, "property": "isMedium", "propertyName": "isMedium", "metadata": { "type": "boolean", "readable": True, "writeable": False, "label": "Medium battery level", }, "value": True, }, }, ) node.receive_event(event) assert f"{node.node_id}-128-1-isMedium" in node.values async def test_invoke_cc_api(client, lock_schlage_be469, uuid4, mock_command): """Test endpoint.invoke_cc_api commands.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {"response": "ok"}, ) assert ( await node.async_invoke_cc_api(CommandClass.USER_CODE, "set", 1, 1, "1234") == "ok" ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "methodName": "set", "args": [1, 1, "1234"], "messageId": uuid4, } assert ( await node.async_invoke_cc_api( CommandClass.USER_CODE, "set", 2, 2, "1234", wait_for_result=True ) == "ok" ) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "methodName": "set", "args": [2, 2, "1234"], "messageId": uuid4, } with pytest.raises(NotFoundError): await node.async_invoke_cc_api(CommandClass.ANTITHEFT, "test", 1) async def test_supports_cc_api(multisensor_6, uuid4, mock_command): """Test endpoint.supports_cc_api commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.supports_cc_api", "nodeId": node.node_id, "endpoint": 0}, {"supported": True}, ) assert await node.async_supports_cc_api(CommandClass.USER_CODE) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.supports_cc_api", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_supports_cc_api(CommandClass.USER_CODE) async def test_supports_cc(multisensor_6, uuid4, mock_command): """Test endpoint.supports_cc_api commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.supports_cc", "nodeId": node.node_id, "endpoint": 0}, {"supported": True}, ) assert await node.async_supports_cc(CommandClass.USER_CODE) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.supports_cc", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_supports_cc(CommandClass.USER_CODE) async def test_controls_cc(multisensor_6, uuid4, mock_command): """Test endpoint.controls_cc commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.controls_cc", "nodeId": node.node_id, "endpoint": 0}, {"controlled": True}, ) assert await node.async_controls_cc(CommandClass.USER_CODE) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.controls_cc", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_controls_cc(CommandClass.USER_CODE) async def test_is_cc_secure(multisensor_6, uuid4, mock_command): """Test endpoint.is_cc_secure commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.is_cc_secure", "nodeId": node.node_id, "endpoint": 0}, {"secure": True}, ) assert await node.async_is_cc_secure(CommandClass.USER_CODE) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.is_cc_secure", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_is_cc_secure(CommandClass.USER_CODE) async def test_get_cc_version(multisensor_6, uuid4, mock_command): """Test endpoint.get_cc_version commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.get_cc_version", "nodeId": node.node_id, "endpoint": 0}, {"version": 1}, ) assert await node.async_get_cc_version(CommandClass.USER_CODE) == 1 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.get_cc_version", "nodeId": node.node_id, "endpoint": 0, "commandClass": 99, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_get_cc_version(CommandClass.USER_CODE) async def test_get_node_unsafe(multisensor_6, uuid4, mock_command): """Test endpoint.get_node_unsafe commands.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.get_node_unsafe", "nodeId": node.node_id, "endpoint": 0}, {"node": multisensor_6}, ) assert await node.async_get_node_unsafe() == multisensor_6 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.get_node_unsafe", "nodeId": node.node_id, "endpoint": 0, "messageId": uuid4, } # Test that command fails when client is disconnected with patch("zwave_js_server.client.asyncio.Event.wait", return_value=True): await node.client.disconnect() with pytest.raises(FailedCommand): await node.async_get_node_unsafe() async def test_statistics_updated( wallmote_central_scene: node_pkg.Node, multisensor_6, ring_keypad ): """Test that statistics get updated on events.""" node = wallmote_central_scene assert node.statistics.commands_rx == 0 event = Event( "statistics updated", { "source": "node", "event": "statistics updated", "nodeId": node.node_id, "statistics": { "commandsTX": 1, "commandsRX": 2, "commandsDroppedTX": 3, "commandsDroppedRX": 4, "timeoutResponse": 5, "rtt": 6, "rssi": 7, "lwr": { "protocolDataRate": 1, "repeaters": [f"{wallmote_central_scene.node_id}"], "repeaterRSSI": [1], "routeFailedBetween": [ f"{ring_keypad.node_id}", f"{multisensor_6.node_id}", ], }, "nlwr": { "protocolDataRate": 2, "repeaters": [], "repeaterRSSI": [127], "routeFailedBetween": [ f"{multisensor_6.node_id}", f"{ring_keypad.node_id}", ], }, }, }, ) node.receive_event(event) # Event should be modified with the NodeStatistics object assert "statistics_updated" in event.data event_stats: NodeStatistics = event.data["statistics_updated"] assert isinstance(event_stats, NodeStatistics) assert event_stats.commands_tx == 1 assert event_stats.commands_rx == 2 assert event_stats.commands_dropped_tx == 3 assert event_stats.commands_dropped_rx == 4 assert event_stats.timeout_response == 5 assert event_stats.rtt == 6 assert event_stats.rssi == 7 assert event_stats.lwr assert event_stats.lwr.protocol_data_rate == ProtocolDataRate.ZWAVE_9K6 assert event_stats.nlwr assert event_stats.nlwr.protocol_data_rate == ProtocolDataRate.ZWAVE_40K assert node.statistics == event_stats assert event_stats.lwr.as_dict() == { "protocol_data_rate": 1, "repeaters": [wallmote_central_scene], "repeater_rssi": [1], "rssi": None, "route_failed_between": ( ring_keypad, multisensor_6, ), } statistics_data = { "commandsTX": 1, "commandsRX": 2, "commandsDroppedTX": 3, "commandsDroppedRX": 4, "timeoutResponse": 5, } assert node.data.get("statistics") != statistics_data event = Event( "statistics updated", { "source": "node", "event": "statistics updated", "nodeId": node.node_id, "statistics": statistics_data, }, ) node.receive_event(event) # Event should be modified with the NodeStatistics object assert "statistics_updated" in event.data event_stats: NodeStatistics = event.data["statistics_updated"] assert isinstance(event_stats, NodeStatistics) assert event_stats.commands_tx == 1 assert event_stats.commands_rx == 2 assert event_stats.commands_dropped_tx == 3 assert event_stats.commands_dropped_rx == 4 assert event_stats.timeout_response == 5 assert not event_stats.rtt assert not event_stats.rssi assert not event_stats.lwr assert not event_stats.nlwr assert node.statistics == event_stats assert node.data["statistics"] == statistics_data # Test that invalid protocol data rate doesn't raise error event = Event( "statistics updated", { "source": "node", "event": "statistics updated", "nodeId": node.node_id, "statistics": { "commandsTX": 1, "commandsRX": 2, "commandsDroppedTX": 3, "commandsDroppedRX": 4, "timeoutResponse": 5, "rtt": 6, "rssi": 7, "lwr": { "protocolDataRate": 0, "repeaters": [], "repeaterRSSI": [], "routeFailedBetween": [], }, "nlwr": { "protocolDataRate": 0, "repeaters": [], "repeaterRSSI": [], "routeFailedBetween": [], }, }, }, ) node.receive_event(event) # Event should be modified with the NodeStatistics object assert "statistics_updated" in event.data event_stats: NodeStatistics = event.data["statistics_updated"] assert isinstance(event_stats, NodeStatistics) assert not event_stats.lwr assert not event_stats.nlwr async def test_statistics_updated_rssi_error( wallmote_central_scene: node_pkg.Node, multisensor_6, ring_keypad ): """Test that statistics get updated on events and rssi error is handled.""" node = wallmote_central_scene assert node.statistics.commands_rx == 0 event = Event( "statistics updated", { "source": "node", "event": "statistics updated", "nodeId": node.node_id, "statistics": { "commandsTX": 1, "commandsRX": 2, "commandsDroppedTX": 3, "commandsDroppedRX": 4, "timeoutResponse": 5, "rtt": 6, "rssi": 127, "lwr": { "protocolDataRate": 1, "repeaters": [f"{wallmote_central_scene.node_id}"], "repeaterRSSI": [1], "routeFailedBetween": [ f"{ring_keypad.node_id}", f"{multisensor_6.node_id}", ], }, "nlwr": { "protocolDataRate": 2, "repeaters": [], "repeaterRSSI": [127], "routeFailedBetween": [ f"{multisensor_6.node_id}", f"{ring_keypad.node_id}", ], }, }, }, ) node.receive_event(event) # Event should be modified with the NodeStatistics object assert "statistics_updated" in event.data event_stats: NodeStatistics = event.data["statistics_updated"] assert isinstance(event_stats, NodeStatistics) with pytest.raises(RssiErrorReceived): assert event_stats.rssi async def test_has_security_class(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.has_security_class command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.has_security_class", "nodeId": node.node_id}, {"hasSecurityClass": True}, ) assert await node.async_has_security_class(SecurityClass.S2_AUTHENTICATED) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.has_security_class", "nodeId": node.node_id, "securityClass": SecurityClass.S2_AUTHENTICATED.value, "messageId": uuid4, } async def test_has_security_class_undefined( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.has_security_class command response is undefined.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.has_security_class", "nodeId": node.node_id}, {}, ) assert await node.async_has_security_class(SecurityClass.S2_AUTHENTICATED) is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.has_security_class", "nodeId": node.node_id, "securityClass": SecurityClass.S2_AUTHENTICATED.value, "messageId": uuid4, } async def test_get_highest_security_class( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_highest_security_class command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_highest_security_class", "nodeId": node.node_id}, {"highestSecurityClass": SecurityClass.S2_AUTHENTICATED.value}, ) assert ( await node.async_get_highest_security_class() == SecurityClass.S2_AUTHENTICATED ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_highest_security_class", "nodeId": node.node_id, "messageId": uuid4, } async def test_get_highest_security_class_undefined( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_highest_security_class command response is undefined.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_highest_security_class", "nodeId": node.node_id}, {}, ) assert await node.async_get_highest_security_class() is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_highest_security_class", "nodeId": node.node_id, "messageId": uuid4, } async def test_test_power_level( multisensor_6: node_pkg.Node, wallmote_central_scene: node_pkg.Node, uuid4, mock_command, ): """Test node.test_powerlevel command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.test_powerlevel", "nodeId": node.node_id}, {"framesAcked": 1}, ) assert ( await node.async_test_power_level( wallmote_central_scene, PowerLevel.DBM_MINUS_1, 3 ) == 1 ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.test_powerlevel", "nodeId": node.node_id, "testNodeId": wallmote_central_scene.node_id, "powerlevel": PowerLevel.DBM_MINUS_1.value, "testFrameCount": 3, "messageId": uuid4, } async def test_test_power_level_progress_event( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test test power level progress event.""" event = Event( "test powerlevel progress", { "source": "node", "event": "test powerlevel progress", "nodeId": multisensor_6.node_id, "acknowledged": 1, "total": 2, }, ) multisensor_6.receive_event(event) assert event.data["test_power_level_progress"] assert event.data["test_power_level_progress"].acknowledged == 1 assert event.data["test_power_level_progress"].total == 2 async def test_check_lifeline_health(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.check_lifeline_health command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.check_lifeline_health", "nodeId": node.node_id}, { "summary": { "rating": 10, "results": [ LifelineHealthCheckResultDataType( latency=1, numNeighbors=2, failedPingsNode=3, rating=9, routeChanges=4, minPowerlevel=5, failedPingsController=6, snrMargin=7, ) ], } }, ) summary = await node.async_check_lifeline_health(1) assert summary.rating == 10 assert summary.results[0].latency == 1 assert summary.results[0].num_neighbors == 2 assert summary.results[0].failed_pings_node == 3 assert summary.results[0].rating == 9 assert summary.results[0].route_changes == 4 assert summary.results[0].min_power_level == PowerLevel.DBM_MINUS_5 assert summary.results[0].failed_pings_controller == 6 assert summary.results[0].snr_margin == 7 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.check_lifeline_health", "nodeId": node.node_id, "rounds": 1, "messageId": uuid4, } async def test_check_lifeline_health_progress_event( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test check lifeline health progress event.""" event = Event( "check lifeline health progress", { "source": "node", "event": "check lifeline health progress", "nodeId": multisensor_6.node_id, "rounds": 1, "totalRounds": 2, "lastRating": 10, "lastResult": LifelineHealthCheckResultDataType( latency=1, numNeighbors=2, failedPingsNode=3, rating=9, routeChanges=4, minPowerlevel=5, failedPingsController=6, snrMargin=7, ), }, ) multisensor_6.receive_event(event) assert event.data["check_lifeline_health_progress"] assert event.data["check_lifeline_health_progress"].rounds == 1 assert event.data["check_lifeline_health_progress"].total_rounds == 2 assert event.data["check_lifeline_health_progress"].last_rating == 10 assert event.data["check_lifeline_health_progress"].last_result.latency == 1 async def test_check_route_health( multisensor_6: node_pkg.Node, wallmote_central_scene: node_pkg.Node, uuid4, mock_command, ): """Test node.check_route_health command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.check_route_health", "nodeId": node.node_id}, { "summary": { "rating": 10, "results": [ RouteHealthCheckResultDataType( numNeighbors=1, rating=10, failedPingsToSource=2, failedPingsToTarget=3, minPowerlevelSource=4, minPowerlevelTarget=5, ) ], } }, ) summary = await node.async_check_route_health(wallmote_central_scene, 1) assert summary.rating == 10 assert summary.results[0].num_neighbors == 1 assert summary.results[0].rating == 10 assert summary.results[0].failed_pings_to_source == 2 assert summary.results[0].failed_pings_to_target == 3 assert summary.results[0].min_power_level_source == PowerLevel.DBM_MINUS_4 assert summary.results[0].min_power_level_target == PowerLevel.DBM_MINUS_5 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.check_route_health", "nodeId": node.node_id, "targetNodeId": wallmote_central_scene.node_id, "rounds": 1, "messageId": uuid4, } async def test_check_route_health_progress_event( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test check route health progress event.""" event = Event( "check route health progress", { "source": "node", "event": "check route health progress", "nodeId": multisensor_6.node_id, "rounds": 1, "totalRounds": 2, "lastRating": 10, "lastResult": RouteHealthCheckResultDataType( numNeighbors=1, rating=10, failedPingsToSource=2, failedPingsToTarget=3, minPowerlevelSource=4, minPowerlevelTarget=5, ), }, ) multisensor_6.receive_event(event) assert event.data["check_route_health_progress"] assert event.data["check_route_health_progress"].rounds == 1 assert event.data["check_route_health_progress"].total_rounds == 2 assert event.data["check_route_health_progress"].last_rating == 10 assert event.data["check_route_health_progress"].last_result.num_neighbors == 1 async def test_get_state( multisensor_6: node_pkg.Node, multisensor_6_state: node_pkg.NodeDataType, uuid4, mock_command, ): """Test node.get_state command.""" node = multisensor_6 value_id = get_value_id_str(node, 32, "currentValue", 0) # Verify original values assert node.endpoints[0].installer_icon == 3079 assert node.values[value_id].value == 255 new_state = deepcopy(multisensor_6_state) # Update endpoint 0 installer icon new_state["endpoints"][0]["installerIcon"] = 1 # Update value of {nodeId}-32-0-currentValue new_state["values"][0] = { "commandClassName": "Basic", "commandClass": 32, "endpoint": 0, "property": "currentValue", "propertyName": "currentValue", "metadata": { "type": "number", "readable": True, "writeable": False, "min": 0, "max": 99, "label": "Current value", }, "value": 0, } ack_commands = mock_command( {"command": "node.get_state", "nodeId": node.node_id}, {"state": new_state}, ) # Verify new values assert await node.async_get_state() == new_state # Verify original values are still the same assert node.endpoints[0].installer_icon != 1 assert node.values[value_id].value != 0 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_state", "nodeId": node.node_id, "messageId": uuid4, } async def test_set_name(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.set_name command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_name", "nodeId": node.node_id}, {}, ) assert node.name != "new_name" assert await node.async_set_name("new_name", False) is None assert node.name == "new_name" assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_name", "nodeId": node.node_id, "name": "new_name", "updateCC": False, "messageId": uuid4, } async def test_set_location(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.set_location command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_location", "nodeId": node.node_id}, {}, ) assert node.location != "new_location" assert await node.async_set_location("new_location", False) is None assert node.location == "new_location" assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_location", "nodeId": node.node_id, "location": "new_location", "updateCC": False, "messageId": uuid4, } async def test_set_keep_awake(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.set_keep_awake command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_keep_awake", "nodeId": node.node_id}, {}, ) assert node.keep_awake assert await node.async_set_keep_awake(False) is None assert node.keep_awake is False assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_keep_awake", "nodeId": node.node_id, "keepAwake": False, "messageId": uuid4, } async def test_get_firmware_update_capabilities( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_firmware_update_capabilities command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_firmware_update_capabilities", "nodeId": node.node_id}, { "capabilities": { "firmwareUpgradable": True, "firmwareTargets": [0], "continuesToFunction": True, "supportsActivation": True, } }, ) capabilities = await node.async_get_firmware_update_capabilities() assert capabilities.firmware_upgradable assert capabilities.firmware_targets == [0] assert capabilities.continues_to_function assert capabilities.supports_activation assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_firmware_update_capabilities", "nodeId": node.node_id, "messageId": uuid4, } assert capabilities.to_dict() == { "firmware_upgradable": True, "firmware_targets": [0], "continues_to_function": True, "supports_activation": True, } async def test_get_firmware_update_capabilities_false( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_firmware_update_capabilities cmd without firmware support.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_firmware_update_capabilities", "nodeId": node.node_id}, {"capabilities": {"firmwareUpgradable": False}}, ) capabilities = await node.async_get_firmware_update_capabilities() assert not capabilities.firmware_upgradable with pytest.raises(TypeError): assert capabilities.firmware_targets with pytest.raises(TypeError): assert capabilities.continues_to_function with pytest.raises(TypeError): assert capabilities.supports_activation assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_firmware_update_capabilities", "nodeId": node.node_id, "messageId": uuid4, } assert capabilities.to_dict() == {"firmware_upgradable": False} async def test_get_firmware_update_capabilities_string( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_firmware_update_capabilities cmd without firmware support.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_firmware_update_capabilities", "nodeId": node.node_id}, { "capabilities": { "firmwareUpgradable": True, "firmwareTargets": [0], "continuesToFunction": "unknown", "supportsActivation": "unknown", } }, ) capabilities = await node.async_get_firmware_update_capabilities() assert capabilities.firmware_upgradable assert capabilities.firmware_targets == [0] assert capabilities.continues_to_function is None assert capabilities.supports_activation is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_firmware_update_capabilities", "nodeId": node.node_id, "messageId": uuid4, } async def test_get_firmware_update_capabilities_cached( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.get_firmware_update_capabilities_cached command.""" node = multisensor_6 ack_commands = mock_command( { "command": "node.get_firmware_update_capabilities_cached", "nodeId": node.node_id, }, { "capabilities": { "firmwareUpgradable": True, "firmwareTargets": [0], "continuesToFunction": True, "supportsActivation": True, } }, ) capabilities = await node.async_get_firmware_update_capabilities_cached() assert capabilities.firmware_upgradable assert capabilities.firmware_targets == [0] assert capabilities.continues_to_function assert capabilities.supports_activation assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_firmware_update_capabilities_cached", "nodeId": node.node_id, "messageId": uuid4, } assert capabilities.to_dict() == { "firmware_upgradable": True, "firmware_targets": [0], "continues_to_function": True, "supports_activation": True, } async def test_is_firmware_update_in_progress( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.is_firmware_update_in_progress command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.is_firmware_update_in_progress", "nodeId": node.node_id}, {"progress": True}, ) assert await node.async_is_firmware_update_in_progress() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.is_firmware_update_in_progress", "nodeId": node.node_id, "messageId": uuid4, } async def test_interview(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.interview command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.interview", "nodeId": node.node_id}, {}, ) await node.async_interview() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.interview", "nodeId": node.node_id, "messageId": uuid4, } async def test_manually_idle_notification_value( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.manually_idle_notification_value command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.manually_idle_notification_value", "nodeId": node.node_id}, {}, ) await node.async_manually_idle_notification_value( f"{node.node_id}-113-0-Home Security-Cover status" ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.manually_idle_notification_value", "nodeId": node.node_id, "valueId": { "commandClass": 113, "endpoint": 0, "property": "Home Security", "propertyKey": "Cover status", }, "messageId": uuid4, } # Raise ValueError if the value is not for the right CommandClass with pytest.raises(ValueError): await node.async_manually_idle_notification_value(f"{node.node_id}-112-0-255") async def test_set_date_and_time_no_wait( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.set_date_and_time command without waiting.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_date_and_time", "nodeId": node.node_id}, {"success": True}, ) assert await node.async_set_date_and_time(datetime(2020, 1, 1, 12, 0, 0)) is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_date_and_time", "nodeId": node.node_id, "date": "2020-01-01T12:00:00", "messageId": uuid4, } async def test_set_date_and_time( climate_radio_thermostat_ct100_plus: node_pkg.Node, uuid4, mock_command ): """Test node.set_date_and_time command while waiting for response.""" node = climate_radio_thermostat_ct100_plus ack_commands = mock_command( {"command": "node.set_date_and_time", "nodeId": node.node_id}, {"success": True}, ) assert await node.async_set_date_and_time(datetime(2020, 1, 1, 12, 0, 0)) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_date_and_time", "nodeId": node.node_id, "date": "2020-01-01T12:00:00", "messageId": uuid4, } async def test_get_date_and_time(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.get_date_and_time command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_date_and_time", "nodeId": node.node_id}, {"dateAndTime": {"hour": 1, "minute": 2, "weekday": 5}}, ) date_and_time = await node.async_get_date_and_time() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_date_and_time", "nodeId": node.node_id, "messageId": uuid4, } assert date_and_time.hour == 1 assert date_and_time.minute == 2 assert date_and_time.weekday == Weekday.FRIDAY async def test_get_value_timestamp(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.get_value_timestamp command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.get_value_timestamp", "nodeId": node.node_id}, {"timestamp": 1234567890}, ) val = node.values["52-32-0-targetValue"] assert await node.async_get_value_timestamp(val) == 1234567890 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.get_value_timestamp", "nodeId": node.node_id, "valueId": {"commandClass": 32, "endpoint": 0, "property": "targetValue"}, "messageId": uuid4, } assert await node.async_get_value_timestamp("52-112-0-2") == 1234567890 assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "node.get_value_timestamp", "nodeId": node.node_id, "valueId": {"commandClass": 112, "endpoint": 0, "property": 2}, "messageId": uuid4, } async def test_is_health_check_in_progress( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test node.is_health_check_in_progress command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.is_health_check_in_progress", "nodeId": node.node_id}, {"progress": True}, ) assert await node.async_is_health_check_in_progress() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.is_health_check_in_progress", "nodeId": node.node_id, "messageId": uuid4, } async def test_abort_health_check(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test node.abort_health_check command.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.abort_health_check", "nodeId": node.node_id}, {}, ) await node.async_abort_health_check() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.abort_health_check", "nodeId": node.node_id, "messageId": uuid4, } async def test_unknown_event(multisensor_6: node_pkg.Node): """Test that an unknown event type causes an exception.""" with pytest.raises(KeyError): assert multisensor_6.receive_event(Event("unknown_event", {"source": "node"})) async def test_default_volume(multisensor_6: node_pkg.Node, uuid4, mock_command): """Test default volume.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_default_volume", "nodeId": node.node_id}, {}, ) assert node.default_volume is None await node.async_set_default_volume(10) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_default_volume", "defaultVolume": 10, "nodeId": node.node_id, "messageId": uuid4, } assert node.default_volume == 10 async def test_default_transition_duration( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test default transition duration.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.set_default_transition_duration", "nodeId": node.node_id}, {}, ) assert node.default_transition_duration is None await node.async_set_default_transition_duration(10) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_default_transition_duration", "defaultTransitionDuration": 10, "nodeId": node.node_id, "messageId": uuid4, } assert node.default_transition_duration == 10 async def test_has_device_config_changed( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test has device config changed.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.has_device_config_changed", "nodeId": node.node_id}, {"changed": True}, ) assert await node.async_has_device_config_changed() assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.has_device_config_changed", "nodeId": node.node_id, "messageId": uuid4, } async def test_has_device_config_changed_undefined( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test has device config changed returns undefined.""" node = multisensor_6 ack_commands = mock_command( {"command": "node.has_device_config_changed", "nodeId": node.node_id}, {}, ) assert await node.async_has_device_config_changed() is None assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.has_device_config_changed", "nodeId": node.node_id, "messageId": uuid4, } async def test_is_secure_none(client, multisensor_6_state): """Test is_secure when it's not included in the dump.""" node_state = deepcopy(multisensor_6_state) node_state.pop("isSecure") node = node_pkg.Node(client, node_state) assert node.is_secure is None async def test_set_raw_config_parameter_value( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test set raw config parameter value.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id}, {}, ) result = await node.async_set_raw_config_parameter_value(1, 101, 1) assert result == SetConfigParameterResult(CommandStatus.QUEUED) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id, "endpoint": 0, "parameter": 101, "bitMask": 1, "value": 1, "messageId": uuid4, } result = await node.async_set_raw_config_parameter_value(2, 0) assert result == SetConfigParameterResult(CommandStatus.QUEUED) assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id, "endpoint": 0, "parameter": 0, "value": 2, "messageId": uuid4, } # wake up node event = Event( "wake up", {"source": "node", "event": "wake up", "nodeId": node.node_id} ) node.receive_event(event) result = await node.async_set_raw_config_parameter_value( 1, 2, value_size=1, value_format=ConfigurationValueFormat.SIGNED_INTEGER ) assert result == SetConfigParameterResult(CommandStatus.ACCEPTED) assert len(ack_commands) == 3 assert ack_commands[2] == { "command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id, "endpoint": 0, "parameter": 2, "valueSize": 1, "valueFormat": 0, "value": 1, "messageId": uuid4, } # Test failures with pytest.raises(ValueError): await node.async_set_raw_config_parameter_value(1, 101, 1, 1) with pytest.raises(ValueError): await node.async_set_raw_config_parameter_value( 1, 101, 1, value_format=ConfigurationValueFormat.SIGNED_INTEGER ) with pytest.raises(ValueError): await node.async_set_raw_config_parameter_value( 1, 101, 1, 1, ConfigurationValueFormat.SIGNED_INTEGER ) async def test_get_raw_config_parameter_value( multisensor_6: node_pkg.Node, uuid4, mock_command ): """Test get raw config parameter value.""" node = multisensor_6 ack_commands = mock_command( {"command": "endpoint.get_raw_config_parameter_value", "nodeId": node.node_id}, {"value": 1}, ) value = await node.async_get_raw_config_parameter_value(101) assert value == 1 assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.get_raw_config_parameter_value", "nodeId": node.node_id, "endpoint": 0, "parameter": 101, "messageId": uuid4, } async def test_supervision_result(inovelli_switch: node_pkg.Node, uuid4, mock_command): """Test Supervision Result.""" node = inovelli_switch mock_command( {"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id}, {"result": {"status": 1, "remainingDuration": "default"}}, ) result = await node.async_set_raw_config_parameter_value(1, 1) assert result.result.status is SupervisionStatus.WORKING duration = result.result.remaining_duration assert duration.unit == "default" async def test_supervision_result_invalid( inovelli_switch: node_pkg.Node, uuid4, mock_command ): """Test invalid Supervision Result.""" node = inovelli_switch mock_command( {"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id}, {"result": {"status": 1}}, ) with pytest.raises(ValueError): await node.async_set_raw_config_parameter_value(1, 1) zwave-js-server-python-0.63.0/test/model/test_utils.py000066400000000000000000000075251500374325600230370ustar00rootroot00000000000000"""Test general utility functions.""" import pytest from zwave_js_server.const import ( Protocols, ProvisioningEntryStatus, QRCodeVersion, SecurityClass, ) from zwave_js_server.model.utils import ( async_parse_qr_code_string, async_try_parse_dsk_from_qr_code_string, ) async def test_parse_qr_code_string(client, mock_command, uuid4): """Test parsing a QR code string.""" ack_commands = mock_command( {"command": "utils.parse_qr_code_string"}, { "qrProvisioningInformation": { "version": 0, "securityClasses": [0, 1, 2], "requestedSecurityClasses": [0], "status": 1, "dsk": "test", "genericDeviceClass": 1, "specificDeviceClass": 1, "installerIconType": 1, "manufacturerId": 1, "productType": 1, "productId": 1, "applicationVersion": "test", "maxInclusionRequestInterval": 1, "uuid": "test", "supportedProtocols": [0], } }, ) qr_provisioning_info = await async_parse_qr_code_string( client, "90testtesttesttesttesttesttesttesttesttesttesttesttest" ) assert ack_commands[0] == { "command": "utils.parse_qr_code_string", "qr": "90testtesttesttesttesttesttesttesttesttesttesttesttest", "messageId": uuid4, } assert qr_provisioning_info.version == QRCodeVersion.S2 assert set(qr_provisioning_info.security_classes) == { SecurityClass.S2_ACCESS_CONTROL, SecurityClass.S2_AUTHENTICATED, SecurityClass.S2_UNAUTHENTICATED, } assert qr_provisioning_info.requested_security_classes == [ SecurityClass.S2_UNAUTHENTICATED ] assert qr_provisioning_info.status == ProvisioningEntryStatus.INACTIVE assert ( qr_provisioning_info.dsk == qr_provisioning_info.application_version == qr_provisioning_info.uuid == "test" ) assert ( qr_provisioning_info.generic_device_class == qr_provisioning_info.specific_device_class == qr_provisioning_info.installer_icon_type == qr_provisioning_info.manufacturer_id == qr_provisioning_info.product_type == qr_provisioning_info.product_id == qr_provisioning_info.max_inclusion_request_interval == 1 ) assert qr_provisioning_info.supported_protocols == [Protocols.ZWAVE] # Test invalid QR code length fails with pytest.raises(ValueError): await async_parse_qr_code_string(client, "test") async def test_async_try_parse_dsk_from_qr_code_string(client, mock_command, uuid4): """Test trying to parse a DSK from a qr code string.""" ack_commands = mock_command( {"command": "utils.try_parse_dsk_from_qr_code_string"}, {"dsk": "abc"} ) dsk = await async_try_parse_dsk_from_qr_code_string( client, "90testtesttesttesttesttesttesttesttesttesttesttesttest" ) assert ack_commands[0] == { "command": "utils.try_parse_dsk_from_qr_code_string", "qr": "90testtesttesttesttesttesttesttesttesttesttesttesttest", "messageId": uuid4, } assert dsk == "abc" async def test_async_try_parse_dsk_from_qr_code_string_fails( client, mock_command, uuid4 ): """Test trying to parse a DSK from a qr code string fails.""" ack_commands = mock_command( {"command": "utils.try_parse_dsk_from_qr_code_string"}, {} ) dsk = await async_try_parse_dsk_from_qr_code_string( client, "90testtesttesttesttesttesttesttesttesttesttesttesttest" ) assert ack_commands[0] == { "command": "utils.try_parse_dsk_from_qr_code_string", "qr": "90testtesttesttesttesttesttesttesttesttesttesttesttest", "messageId": uuid4, } assert dsk is None zwave-js-server-python-0.63.0/test/model/test_value.py000066400000000000000000000206231500374325600230050ustar00rootroot00000000000000"""Test value model.""" from copy import deepcopy from zwave_js_server.const import ConfigurationValueType, SetValueStatus from zwave_js_server.model.node import Node from zwave_js_server.model.value import ( ConfigurationValue, ConfigurationValueFormat, MetaDataType, SetValueResult, ValueDataType, get_value_id_str, ) def test_value_size(lock_schlage_be469): """Test the value size property for a value.""" node = lock_schlage_be469 zwave_value = node.values["20-112-0-3"] assert zwave_value.metadata.value_size == 1 def test_buffer_dict(client, idl_101_lock_state): """Test that we handle buffer dictionary correctly.""" node_data = deepcopy(idl_101_lock_state) node = Node(client, node_data) value_id = get_value_id_str(node, 99, "userCode", 0, 3) assert value_id == "26-99-0-userCode-3" zwave_value = node.values[value_id] assert zwave_value.metadata.type == "buffer" assert zwave_value.value == "¤\x0eªV" def test_unparseable_value(client, unparseable_json_string_value_state): """Test that we handle string value with unparseable format.""" node = Node(client, unparseable_json_string_value_state) value_id = get_value_id_str(node, 99, "userCode", 0, 4) assert value_id == "20-99-0-userCode-4" assert value_id not in node.values def test_allow_manual_entry(client, inovelli_switch_state): """Test that allow_manaual_entry works correctly.""" node = Node(client, inovelli_switch_state) config_values = node.get_configuration_values() value_id = get_value_id_str(node, 112, 8, 0, 255) zwave_value = config_values[value_id] assert zwave_value.configuration_value_type == ConfigurationValueType.MANUAL_ENTRY value_id = get_value_id_str(node, 112, 8, 0, 65280) zwave_value = config_values[value_id] assert zwave_value.configuration_value_type == ConfigurationValueType.ENUMERATED def test_stateful(lock_schlage_be469): """Test the stateful property for a value.""" node = lock_schlage_be469 zwave_value = node.values["20-112-0-3"] assert not zwave_value.metadata.secret def test_secret(lock_schlage_be469): """Test the secret property for a value.""" node = lock_schlage_be469 zwave_value = node.values["20-112-0-3"] assert zwave_value.metadata.stateful def test_configuration_value_type(inovelli_switch_state): """Test configuration value types.""" value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="boolean", max=2, min=0, allowManualEntry=True, states={True: "On", False: "Off"}, ), ), ) assert value.configuration_value_type == ConfigurationValueType.MANUAL_ENTRY value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="boolean", max=1, min=0, allowManualEntry=False, states={True: "On", False: "Off"}, ), ), ) assert value.configuration_value_type == ConfigurationValueType.ENUMERATED value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="boolean", max=1, min=0, allowManualEntry=False, ), ), ) assert value.configuration_value_type == ConfigurationValueType.BOOLEAN value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="number", max=2, min=0, allowManualEntry=True, states={0: "On", 1: "Off"}, ), ), ) assert value.configuration_value_type == ConfigurationValueType.MANUAL_ENTRY value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="number", max=1, min=0, allowManualEntry=False, states={"1": "On", "0": "Off"}, ), ), ) assert value.configuration_value_type == ConfigurationValueType.ENUMERATED value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="number", max=2, min=0, allowManualEntry=False, ), ), ) assert value.configuration_value_type == ConfigurationValueType.RANGE value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="number", allowManualEntry=False, ), ), ) assert value.configuration_value_type == ConfigurationValueType.UNDEFINED def test_set_value_result_str(): """Test SetValueResult str.""" result = SetValueResult({"status": 255}) assert result.status == SetValueStatus.SUCCESS assert str(result) == "Success" result = SetValueResult({"status": 1, "remainingDuration": {"unit": "default"}}) assert result.status == SetValueStatus.WORKING assert str(result) == "Working (default duration)" result = SetValueResult( {"status": 1, "remainingDuration": {"unit": "seconds", "value": 1}} ) assert result.status == SetValueStatus.WORKING assert str(result) == "Working (1 seconds)" result = SetValueResult({"status": 3, "message": "test"}) assert result.status == SetValueStatus.ENDPOINT_NOT_FOUND assert str(result) == "Endpoint Not Found: test" result = SetValueResult({"status": 1, "remainingDuration": "unknown"}) assert result.status == SetValueStatus.WORKING assert str(result) == "Working (unknown duration)" def test_configuration_value_metadata(inovelli_switch_state): """Test configuration value specific metadata.""" value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="boolean", max=2, min=0, allowManualEntry=True, states={True: "On", False: "Off"}, ), ), ) metadata = value.metadata assert metadata.default is None assert metadata.is_advanced is None assert metadata.is_from_config is None assert metadata.requires_re_inclusion is None assert metadata.no_bulk_support is None assert metadata.value_size is None assert metadata.format is None value = ConfigurationValue( inovelli_switch_state, ValueDataType( commandClass=112, property=8, propertyName="8", endpoint=0, metadata=MetaDataType( type="boolean", max=2, min=0, allowManualEntry=True, states={True: "On", False: "Off"}, default=2, isAdvanced=True, isFromConfig=True, requiresReInclusion=True, noBulkSupport=True, valueSize=1, format=0, ), ), ) metadata = value.metadata assert metadata.default == 2 assert metadata.is_advanced assert metadata.is_from_config assert metadata.requires_re_inclusion assert metadata.no_bulk_support assert metadata.value_size == 1 assert metadata.format == ConfigurationValueFormat.SIGNED_INTEGER zwave-js-server-python-0.63.0/test/test_client.py000066400000000000000000000440151500374325600220500ustar00rootroot00000000000000"""Test the client.""" import asyncio from datetime import datetime import logging from unittest.mock import Mock, patch from aiohttp.client_exceptions import ClientError, WSServerHandshakeError from aiohttp.client_reqrep import ClientResponse, RequestInfo from aiohttp.http_websocket import WSMsgType import pytest from test.common import MockCommandProtocol from zwave_js_server.client import LOGGER, Client from zwave_js_server.const import MAX_SERVER_SCHEMA_VERSION, LogLevel, __version__ from zwave_js_server.event import Event from zwave_js_server.exceptions import ( CannotConnect, ConnectionFailed, FailedCommand, FailedZWaveCommand, InvalidMessage, InvalidServerVersion, InvalidState, NotConnected, ) from zwave_js_server.model.driver import Driver from zwave_js_server.model.log_config import LogConfig async def test_connect_disconnect(client_session, url): """Test client connect and disconnect.""" async with Client(url, client_session) as client: assert client.connected assert not client.connected @pytest.mark.parametrize( "error", [ClientError, WSServerHandshakeError(Mock(RequestInfo), (Mock(ClientResponse),))], ) async def test_cannot_connect(client_session, url, error): """Test cannot connect.""" client_session.ws_connect.side_effect = error client = Client(url, client_session) with pytest.raises(CannotConnect): await client.connect() assert not client.connected async def test_send_command_schema( client_session, url, ws_client, driver_ready, driver ): """Test sending unsupported command.""" client = Client(url, client_session) await client.connect() assert client.connected client.driver = driver await client.listen(driver_ready) ws_client.receive.assert_awaited() # test schema version is at server maximum if client.version.max_schema_version < MAX_SERVER_SCHEMA_VERSION: assert client.schema_version == client.version.max_schema_version # send command of current schema version should not fail with pytest.raises(NotConnected): await client.async_send_command( {"command": "test"}, require_schema=client.schema_version ) # send command of unsupported schema version should fail with pytest.raises(InvalidServerVersion): await client.async_send_command( {"command": "test"}, require_schema=client.schema_version + 2 ) with pytest.raises(InvalidServerVersion): await client.async_send_command_no_wait( {"command": "test"}, require_schema=client.schema_version + 2 ) async def test_min_schema_version(client_session, url, version_data): """Test client connect with invalid schema version.""" version_data["minSchemaVersion"] = 100 client = Client(url, client_session) with pytest.raises(InvalidServerVersion): await client.connect() assert not client.connected async def test_max_schema_version(client_session, url, version_data): """Test client connect with invalid schema version.""" version_data["maxSchemaVersion"] = 0 client = Client(url, client_session) with pytest.raises(InvalidServerVersion): await client.connect() assert not client.connected async def test_send_json_when_disconnected(client_session, url): """Test send json message when disconnected.""" client = Client(url, client_session) assert not client.connected with pytest.raises(NotConnected): await client.async_send_command({"test": None}) async def test_listen(client_session, url, driver_ready): """Test client listen.""" client = Client(url, client_session) assert not client.driver await client.connect() assert client.connected asyncio.create_task(client.listen(driver_ready)) await driver_ready.wait() assert client.driver await client.disconnect() assert not client.connected async def test_listen_client_error( client_session, url, ws_client, messages, ws_message, driver_ready ): """Test websocket error on listen.""" client = Client(url, client_session) await client.connect() assert client.connected messages.append(ws_message) ws_client.receive.side_effect = asyncio.CancelledError() # This should break out of the listen loop before any message is received. with pytest.raises(asyncio.CancelledError): await client.listen(driver_ready) assert not ws_message.json.called @pytest.mark.parametrize( "message_type, exception", [ (WSMsgType.ERROR, ConnectionFailed), (WSMsgType.BINARY, InvalidMessage), ], ) async def test_listen_error_message_types( client_session, url, messages, ws_message, message_type, exception, driver_ready ): """Test different websocket message types that should raise on listen.""" client = Client(url, client_session) await client.connect() assert client.connected ws_message.type = message_type messages.append(ws_message) with pytest.raises(exception): await client.listen(driver_ready) @pytest.mark.parametrize( "message_type", [WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING] ) async def test_listen_disconnect_message_types( client_session, url, ws_client, messages, ws_message, message_type, driver_ready ): """Test different websocket message types that stop listen.""" async with Client(url, client_session) as client: assert client.connected ws_message.type = message_type messages.append(ws_message) # This should break out of the listen loop before handling the received message. # Otherwise there will be an error. await client.listen(driver_ready) # Assert that we received a message. ws_client.receive.assert_awaited() async def test_listen_invalid_message_data( client_session, url, messages, ws_message, driver_ready ): """Test websocket message data that should raise on listen.""" client = Client(url, client_session) await client.connect() assert client.connected ws_message.json.side_effect = ValueError("Boom") messages.append(ws_message) with pytest.raises(InvalidMessage): await client.listen(driver_ready) async def test_listen_not_success(client_session, url, result, driver_ready): """Test receive result message with success False on listen.""" result["success"] = False result["errorCode"] = "error_code" result["message"] = "test" client = Client(url, client_session) await client.connect() with pytest.raises(FailedCommand): await client.listen(driver_ready) assert not client.connected async def test_initialize_not_success( client_session, url, initialize_data, driver_ready ): """Test receive result message with success False on listen.""" initialize_data["success"] = False initialize_data["errorCode"] = "error_code" initialize_data["message"] = "test" client = Client(url, client_session) await client.connect() with pytest.raises(FailedCommand): await client.listen(driver_ready) assert not client.connected async def test_get_log_config_not_success( client_session, url, get_log_config_data, driver_ready ): """Test receive log config message with success False on listen.""" get_log_config_data["success"] = False get_log_config_data["errorCode"] = "error_code" get_log_config_data["message"] = "test" client = Client(url, client_session) await client.connect() with pytest.raises(FailedCommand): await client.listen(driver_ready) assert not client.connected async def test_listen_without_connect(client_session, url, driver_ready): """Test listen without first being connected.""" client = Client(url, client_session) assert not client.connected with pytest.raises(InvalidState): await client.listen(driver_ready) async def test_listen_event( client_session, url, ws_client, messages, ws_message, result, driver_ready ): """Test receiving event result type on listen.""" client = Client(url, client_session) await client.connect() assert client.connected result["type"] = "event" result["event"] = { "source": "node", "event": "value updated", "nodeId": 52, "args": { "commandClassName": "Basic", "commandClass": 32, "endpoint": 0, "property": "currentValue", "newValue": 255, "prevValue": 255, "propertyName": "currentValue", }, } messages.append(ws_message) await client.listen(driver_ready) ws_client.receive.assert_awaited() async def test_listen_unknown_result_type( client_session, url, ws_client, result, driver_ready, driver ): """Test websocket message with unknown type on listen.""" client = Client(url, client_session) await client.connect() assert client.connected # Make sure there's a driver so we can test an unknown event. client.driver = driver result["type"] = "unknown" # Receiving an unknown message type should not error. await client.listen(driver_ready) ws_client.receive.assert_awaited() async def test_command_error_handling(client, mock_command): """Test error handling.""" mock_command( {"command": "some_command"}, {"errorCode": "unknown_command", "message": "test"}, False, ) with pytest.raises(FailedCommand) as raised: await client.async_send_command({"command": "some_command"}) assert raised.value.error_code == "unknown_command" assert str(raised.value) == "unknown_command: test" mock_command( {"command": "some_zjs_command"}, { "errorCode": "zwave_error", "zwaveErrorCode": 3, "zwaveErrorMessage": "Node 5 is dead", }, False, ) with pytest.raises(FailedZWaveCommand) as raised: await client.async_send_command({"command": "some_zjs_command"}) assert raised.value.error_code == "zwave_error" assert raised.value.zwave_error_code == 3 assert raised.value.zwave_error_message == "Node 5 is dead" async def test_record_messages(client, wallmote_central_scene, mock_command, uuid4): """Test recording messages.""" # pylint: disable=protected-access assert not client.recording_messages assert not client._recorded_commands assert not client._recorded_events client.begin_recording_messages() mock_command( {"command": "some_command"}, {}, ) with pytest.raises(InvalidState): client.begin_recording_messages() with patch("zwave_js_server.client.datetime") as mock_dt: mock_dt.utcnow.return_value = datetime(2022, 1, 7, 1) await client.async_send_command({"command": "some_command"}) assert len(client._recorded_commands) == 1 assert len(client._recorded_events) == 0 assert uuid4 in client._recorded_commands assert client._recorded_commands[uuid4]["record_type"] == "command" assert client._recorded_commands[uuid4]["command"] == "some_command" assert client._recorded_commands[uuid4]["command_msg"] == { "command": "some_command", "messageId": uuid4, } assert client._recorded_commands[uuid4]["result_msg"] == { "messageId": "1234", "result": {}, "success": True, "type": "result", } assert "ts" in client._recorded_commands[uuid4] assert "result_ts" in client._recorded_commands[uuid4] with patch("zwave_js_server.client.datetime") as mock_dt: mock_dt.utcnow.return_value = datetime(2022, 1, 7, 0) client._handle_incoming_message( { "type": "event", "event": { "source": "node", "event": "value updated", "nodeId": wallmote_central_scene.node_id, "args": { "commandClassName": "Binary Switch", "commandClass": 39, "endpoint": 0, "property": "currentValue", "newValue": False, "prevValue": True, "propertyName": "currentValue", }, }, } ) assert len(client._recorded_commands) == 1 assert len(client._recorded_events) == 1 logging.getLogger(__name__).error(client._recorded_events) event = client._recorded_events[0] assert event["record_type"] == "event" assert event["type"] == "value updated" assert event["event_msg"] == { "type": "event", "event": { "source": "node", "event": "value updated", "nodeId": wallmote_central_scene.node_id, "args": { "commandClassName": "Binary Switch", "commandClass": 39, "endpoint": 0, "property": "currentValue", "newValue": False, "prevValue": True, "propertyName": "currentValue", }, }, } assert "ts" in event replay_dump = client.end_recording_messages() assert len(replay_dump) == 2 assert len(client._recorded_commands) == 0 assert len(client._recorded_events) == 0 # Testing that events are properly sorted by timestamp. Even though the event # comes after the command in the code, the patch should make the event appear first assert replay_dump[0]["record_type"] == "event" with pytest.raises(InvalidState): client.end_recording_messages() async def test_additional_user_agent_components(client_session, url): """Test additionalUserAgentComponents parameter.""" # pylint: disable=protected-access client = Client( url, client_session, additional_user_agent_components={"foo": "bar"} ) client._client = True with ( patch( "zwave_js_server.client.Client._send_json_message", return_value=None ) as send_json_mock, patch( "zwave_js_server.client.Client._receive_json_or_raise", return_value={"success": True}, ), ): await client.initialize() send_json_mock.assert_called_once_with( { "command": "initialize", "messageId": "initialize", "schemaVersion": 40, "additionalUserAgentComponents": { "zwave-js-server-python": __version__, "foo": "bar", }, } ) async def test_pop_future_none(client_session, url, driver_ready): """Test when a future has been cleared from futures dict, popping still works.""" client = Client(url, client_session) await client.connect() assert client.connected asyncio.create_task(client.listen(driver_ready)) await driver_ready.wait() with pytest.raises(asyncio.CancelledError): await client.async_send_command({"command": "some_command"}) async def test_log_server( client: Client, driver: Driver, caplog: pytest.LogCaptureFixture, mock_command: MockCommandProtocol, ) -> None: """Test logging from server.""" # pylint: disable=protected-access assert client.connected mock_command( {"command": "start_listening_logs"}, {}, ) mock_command( {"command": "stop_listening_logs"}, {}, ) # Set log levels to force the lib to change log levels LOGGER.setLevel(logging.INFO) client.driver.log_config = LogConfig(True, LogLevel.DEBUG, False, None, None) await client.enable_server_logging() assert client.server_logging_enabled assert len(caplog.records) == 2 assert "logging is currently more verbose" in caplog.records[0].message assert caplog.records[0].name == "zwave_js_server" # Test that enabling again is a no-op await client.enable_server_logging() assert client.server_logging_enabled assert len(caplog.records) == 2 LOGGER.setLevel(logging.INFO) event = Event( "log config updated", data={ "source": "driver", "event": "log config updated", "config": {"level": "silly"}, }, ) driver.receive_event(event) assert len(caplog.records) == 3 assert "logging is currently more verbose" in caplog.records[2].message assert caplog.records[2].name == "zwave_js_server" event = Event( type="logging", data={ "source": "driver", "event": "logging", "formattedMessage": [ "2021-04-18T18:03:34.051Z CNTRLR [Node 005] [~] \n", "test", ], "level": "debug", "primaryTags": "[Node 005] [~] [Notification]", "secondaryTags": "[Endpoint 0]", "message": "Home Security[Motion sensor status]\n: 8 => 0", "direction": " ", "label": "CNTRLR", "timestamp": "2021-04-18T18:03:34.051Z", "multiline": True, "secondaryTagPadding": -1, "context": { "source": "controller", "type": "node", "nodeId": 5, "header": "Notification", "direction": "none", "change": "notification", "endpoint": 0, }, }, ) driver.receive_event(event) assert len(caplog.records) == 4 assert "Node 005" in caplog.records[3].message assert caplog.records[3].levelno == logging.DEBUG assert caplog.records[3].name == "zwave_js_server.server" # First time we disable should be clean client.disable_server_logging() assert not client.server_logging_enabled assert len(caplog.records) == 4 # Test that disabling again is a no-op client.disable_server_logging() assert not client.server_logging_enabled # Test that enabling server logging raises an error when client is not connected client.driver = None client._client = None with pytest.raises(InvalidState): await client.enable_server_logging() client.disable_server_logging() zwave-js-server-python-0.63.0/test/test_dump.py000066400000000000000000000065271500374325600215450ustar00rootroot00000000000000"""Test the dump helper.""" from unittest.mock import call import pytest from zwave_js_server.const import __version__ from zwave_js_server.dump import dump_msgs from .common import update_ws_client_msg_queue @pytest.fixture(name="event") def event_fixture(): """Return a received event from the websocket client.""" return { "type": "event", "event": { "source": "node", "event": "value updated", "nodeId": 52, "args": { "commandClassName": "Basic", "commandClass": 32, "endpoint": 0, "property": "currentValue", "newValue": 255, "prevValue": 255, "propertyName": "currentValue", }, }, } async def test_dump( client_session, result, url, version_data, initialize_data, ws_client, ): """Test the dump function.""" update_ws_client_msg_queue(ws_client, (version_data, initialize_data, result)) messages = await dump_msgs(url, client_session) assert ws_client.receive_json.call_count == 3 assert ws_client.send_json.call_count == 2 assert ws_client.send_json.call_args == call( {"command": "start_listening", "messageId": "start-listening"} ) assert ws_client.close.call_count == 1 assert messages assert len(messages) == 3 assert messages[0] == version_data assert messages[1] == initialize_data assert messages[2] == result async def test_dump_timeout( client_session, result, url, event, version_data, initialize_data, ws_client, ): """Test the dump function with timeout.""" update_ws_client_msg_queue( ws_client, (version_data, initialize_data, result, event) ) messages = await dump_msgs(url, client_session, timeout=0.05) assert ws_client.receive_json.call_count == 5 assert ws_client.send_json.call_count == 2 assert ws_client.send_json.call_args == call( {"command": "start_listening", "messageId": "start-listening"} ) assert ws_client.close.call_count == 1 assert messages assert len(messages) == 4 assert messages[0] == version_data assert messages[1] == initialize_data assert messages[2] == result assert messages[3] == event async def test_dump_additional_user_agent_components( client_session, result, url, version_data, initialize_data, ws_client, ): """Test the dump function with additional user agent components.""" update_ws_client_msg_queue(ws_client, (version_data, initialize_data, result)) messages = await dump_msgs( url, client_session, additional_user_agent_components={"foo": "bar"} ) assert ws_client.receive_json.call_count == 3 assert ws_client.send_json.call_count == 2 assert ws_client.send_json.call_args_list[0] == call( { "command": "initialize", "messageId": "initialize", "schemaVersion": 40, "additionalUserAgentComponents": { "zwave-js-server-python": __version__, "foo": "bar", }, } ) assert ws_client.close.call_count == 1 assert messages assert len(messages) == 3 assert messages[0] == version_data assert messages[1] == initialize_data assert messages[2] == result zwave-js-server-python-0.63.0/test/test_event.py000066400000000000000000000010431500374325600217050ustar00rootroot00000000000000"""Test event helpers.""" from zwave_js_server import event def test_once(): """Test once listens to event once.""" mock = event.EventBase() calls = [] mock.once("test-event", calls.append) mock.emit("test-event", 1) mock.emit("test-event", 2) assert len(calls) == 1 def test_exception_on_emit(caplog): """Test exception on emit gets handled.""" mock = event.EventBase() mock.on("test-event", lambda _: 1 / 0) mock.emit("test-event", 1) assert "Error handling event: test-event" in caplog.text zwave-js-server-python-0.63.0/test/test_firmware.py000066400000000000000000000134151500374325600224060ustar00rootroot00000000000000"""Test the firmware update helper.""" from unittest.mock import patch from zwave_js_server.firmware import controller_firmware_update_otw, update_firmware from zwave_js_server.model.controller.firmware import ( ControllerFirmwareUpdateData, ControllerFirmwareUpdateStatus, ) from zwave_js_server.model.node.firmware import ( NodeFirmwareUpdateData, NodeFirmwareUpdateStatus, ) async def test_update_firmware_guess_format(url, client_session, multisensor_6): """Test update_firmware with guessed format.""" with ( patch("zwave_js_server.firmware.Client.connect") as connect_mock, patch("zwave_js_server.firmware.Client.initialize") as initialize_mock, patch("zwave_js_server.firmware.Client.async_send_command") as cmd_mock, patch("zwave_js_server.firmware.Client.disconnect") as disconnect_mock, ): node = multisensor_6 cmd_mock.return_value = { "result": {"status": 255, "success": True, "reInterview": False} } result = await update_firmware( url, node, [NodeFirmwareUpdateData("test", bytes(10))], client_session ) assert result.status == NodeFirmwareUpdateStatus.OK_RESTART_PENDING assert result.success assert not result.reinterview connect_mock.assert_called_once() initialize_mock.assert_called_once() cmd_mock.assert_called_once_with( { "command": "node.update_firmware", "nodeId": node.node_id, "updates": [ { "filename": "test", "file": "AAAAAAAAAAAAAA==", } ], }, require_schema=29, ) disconnect_mock.assert_called_once() async def test_update_firmware_known_format_and_target( url, client_session, multisensor_6 ): """Test update_firmware with known format.""" with ( patch("zwave_js_server.firmware.Client.connect") as connect_mock, patch("zwave_js_server.firmware.Client.initialize") as initialize_mock, patch("zwave_js_server.firmware.Client.async_send_command") as cmd_mock, patch("zwave_js_server.firmware.Client.disconnect") as disconnect_mock, ): node = multisensor_6 cmd_mock.return_value = { "result": {"status": 255, "success": True, "reInterview": False} } result = await update_firmware( url=url, node=node, updates=[NodeFirmwareUpdateData("test", bytes(10), "test", 1)], session=client_session, ) assert result.status == NodeFirmwareUpdateStatus.OK_RESTART_PENDING assert result.success assert not result.reinterview connect_mock.assert_called_once() initialize_mock.assert_called_once() cmd_mock.assert_called_once_with( { "command": "node.update_firmware", "nodeId": node.node_id, "updates": [ { "filename": "test", "file": "AAAAAAAAAAAAAA==", "fileFormat": "test", "firmwareTarget": 1, } ], }, require_schema=29, ) disconnect_mock.assert_called_once() async def test_controller_firmware_update_otw_guess_format(url, client_session): """Test controller_firmware_update_otw with guessed format.""" with ( patch("zwave_js_server.firmware.Client.connect") as connect_mock, patch("zwave_js_server.firmware.Client.initialize") as initialize_mock, patch("zwave_js_server.firmware.Client.async_send_command") as cmd_mock, patch("zwave_js_server.firmware.Client.disconnect") as disconnect_mock, ): cmd_mock.return_value = {"result": {"status": 255, "success": True}} result = await controller_firmware_update_otw( url, ControllerFirmwareUpdateData("test", bytes(10)), client_session ) assert result.status == ControllerFirmwareUpdateStatus.OK assert result.success connect_mock.assert_called_once() initialize_mock.assert_called_once() cmd_mock.assert_called_once_with( { "command": "controller.firmware_update_otw", "filename": "test", "file": "AAAAAAAAAAAAAA==", }, require_schema=29, ) disconnect_mock.assert_called_once() async def test_controller_firmware_update_otw_known_format_and_target( url, client_session ): """Test controller_firmware_update_otw with known format.""" with ( patch("zwave_js_server.firmware.Client.connect") as connect_mock, patch("zwave_js_server.firmware.Client.initialize") as initialize_mock, patch("zwave_js_server.firmware.Client.async_send_command") as cmd_mock, patch("zwave_js_server.firmware.Client.disconnect") as disconnect_mock, ): cmd_mock.return_value = {"result": {"status": 255, "success": True}} result = await controller_firmware_update_otw( url=url, firmware_file=ControllerFirmwareUpdateData("test", bytes(10), "test"), session=client_session, ) assert result.status == ControllerFirmwareUpdateStatus.OK assert result.success connect_mock.assert_called_once() initialize_mock.assert_called_once() cmd_mock.assert_called_once_with( { "command": "controller.firmware_update_otw", "filename": "test", "file": "AAAAAAAAAAAAAA==", "fileFormat": "test", }, require_schema=29, ) disconnect_mock.assert_called_once() zwave-js-server-python-0.63.0/test/test_main.py000066400000000000000000000045251500374325600215200ustar00rootroot00000000000000"""Test the CLI in main.""" import sys from unittest.mock import AsyncMock, patch import pytest from zwave_js_server.__main__ import main from .common import update_ws_client_msg_queue # pylint: disable=unused-argument @pytest.fixture(name="client_session") def client_session_fixture(ws_client): """Mock the aiohttp client session.""" with patch("aiohttp.ClientSession") as session: session.return_value.__aenter__.return_value.ws_connect.side_effect = AsyncMock( return_value=ws_client ) yield session def test_server_version(client_session, url, ws_client, result, capsys): """Test print server version.""" with ( patch.object(sys, "argv", ["zwave_js_server", url, "--server-version"]), pytest.raises(SystemExit) as sys_exit, ): main() assert sys_exit.value.code == 0 captured = capsys.readouterr() assert captured.out == ( "Driver: test_driver_version\n" "Server: test_server_version\n" "Home ID: test_home_id\n" ) assert ws_client.receive_json.call_count == 1 assert ws_client.close.call_count == 1 @pytest.mark.parametrize("result", ["test_result"]) def test_dump_state( client_session, url, ws_client, result, version_data, initialize_data, capsys ): """Test dump state.""" update_ws_client_msg_queue(ws_client, (version_data, initialize_data, result)) with ( patch.object(sys, "argv", ["zwave_js_server", url, "--dump-state"]), pytest.raises(SystemExit) as sys_exit, ): main() assert sys_exit.value.code == 0 captured = capsys.readouterr() assert captured.out == ( "{'type': 'version', 'driverVersion': 'test_driver_version', " "'serverVersion': 'test_server_version', 'homeId': 'test_home_id', " "'minSchemaVersion': 0, 'maxSchemaVersion': 40}\n" "{'type': 'result', 'success': True, 'result': {}, 'messageId': 'initialize'}\n" "test_result\n" ) assert ws_client.receive_json.call_count == 3 assert ws_client.close.call_count == 1 def test_connect(client_session, url, ws_client): """Test connect.""" with ( patch.object(sys, "argv", ["zwave_js_server", url]), pytest.raises(SystemExit) as sys_exit, ): main() assert sys_exit.value.code == 0 assert ws_client.receive.call_count == 5 zwave-js-server-python-0.63.0/test/test_version.py000066400000000000000000000025401500374325600222540ustar00rootroot00000000000000"""Test the server version helper.""" from unittest.mock import call from zwave_js_server.version import get_server_version async def test_get_server_version(client_session, ws_client, url, version_data): """Test the get server version helper.""" ws_client.receive_json.return_value = version_data version_info = await get_server_version(url, client_session) assert client_session.ws_connect.called assert client_session.ws_connect.call_args == call(url) assert version_info.driver_version == version_data["driverVersion"] assert version_info.server_version == version_data["serverVersion"] assert version_info.home_id == version_data["homeId"] assert version_info.min_schema_version == version_data["minSchemaVersion"] assert version_info.max_schema_version == version_data["maxSchemaVersion"] assert ws_client.close.called async def test_missing_server_schema_version( client_session, ws_client, url, version_data ): """Test missing schema version processed as schema version 0.""" del version_data["minSchemaVersion"] del version_data["maxSchemaVersion"] ws_client.receive_json.return_value = version_data version_info = await get_server_version(url, client_session) assert version_info.min_schema_version == 0 assert version_info.max_schema_version == 0 assert ws_client.close.called zwave-js-server-python-0.63.0/test/util/000077500000000000000000000000001500374325600201325ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/util/__init__.py000066400000000000000000000000261500374325600222410ustar00rootroot00000000000000"""Test utilities.""" zwave-js-server-python-0.63.0/test/util/command_class/000077500000000000000000000000001500374325600227355ustar00rootroot00000000000000zwave-js-server-python-0.63.0/test/util/command_class/__init__.py000066400000000000000000000000441500374325600250440ustar00rootroot00000000000000"""Test Command Class utilities.""" zwave-js-server-python-0.63.0/test/util/command_class/test_energy_production.py000066400000000000000000000057461500374325600301210ustar00rootroot00000000000000"""Test Energy Production command class utility functions.""" import pytest from zwave_js_server.const import CommandClass from zwave_js_server.const.command_class.energy_production import ( CC_SPECIFIC_PARAMETER, CC_SPECIFIC_SCALE, EnergyProductionParameter, PowerScale, ) from zwave_js_server.exceptions import InvalidCommandClass, UnknownValueData from zwave_js_server.model.node import Node from zwave_js_server.model.value import ( MetaDataType, Value, ValueDataType, get_value_id_str, ) from zwave_js_server.util.command_class.energy_production import ( get_energy_production_parameter, get_energy_production_scale_type, ) async def test_get_energy_production_parameter(energy_production: Node): """Test get_energy_production_parameter function.""" node = energy_production value_id = get_value_id_str(node, CommandClass.VERSION, "protocolVersion") with pytest.raises(InvalidCommandClass): get_energy_production_parameter(node.values.get(value_id)) value_id = get_value_id_str( node, CommandClass.ENERGY_PRODUCTION, "value", property_key=0 ) assert ( get_energy_production_parameter(node.values.get(value_id)) == EnergyProductionParameter.POWER ) async def test_invalid_get_energy_production_parameter( invalid_multilevel_sensor_type: Node, ): """Test receiving an invalid energy production parameter.""" node = invalid_multilevel_sensor_type # Create value with an invalid parameter ID metadata = MetaDataType(ccSpecific={CC_SPECIFIC_PARAMETER: -1}) value_data = ValueDataType( commandClass=CommandClass.ENERGY_PRODUCTION, commandClassName="EnergyProduction", endpoint=0, property="value", propertyKey=0, metadata=metadata, ) value = Value(node, value_data) with pytest.raises(UnknownValueData): get_energy_production_parameter(value) async def test_get_energy_production_scale_type(energy_production: Node): """Test get_energy_production_scale_type function.""" node = energy_production value_id = get_value_id_str( node, CommandClass.ENERGY_PRODUCTION, "value", property_key=0 ) assert ( get_energy_production_scale_type(node.values.get(value_id)) == PowerScale.WATTS ) async def test_invalid_get_energy_production_scale_type( invalid_multilevel_sensor_type: Node, ): """Test receiving an invalid energy production scale type.""" node = invalid_multilevel_sensor_type # Create value with an invalid scale ID metadata = MetaDataType( ccSpecific={CC_SPECIFIC_PARAMETER: 0, CC_SPECIFIC_SCALE: -1} ) value_data = ValueDataType( commandClass=CommandClass.ENERGY_PRODUCTION, commandClassName="EnergyProduction", endpoint=0, property="value", propertyKey=0, metadata=metadata, ) value = Value(node, value_data) with pytest.raises(UnknownValueData): get_energy_production_scale_type(value) zwave-js-server-python-0.63.0/test/util/command_class/test_meter.py000066400000000000000000000051331500374325600254640ustar00rootroot00000000000000"""Test command class utility functions.""" import pytest from zwave_js_server.const import CommandClass from zwave_js_server.const.command_class.meter import ( CC_SPECIFIC_METER_TYPE, CC_SPECIFIC_SCALE, ElectricScale, MeterType, ) from zwave_js_server.exceptions import InvalidCommandClass, UnknownValueData from zwave_js_server.model.node import Node from zwave_js_server.model.value import ( MetaDataType, Value, ValueDataType, get_value_id_str, ) from zwave_js_server.util.command_class.meter import ( get_meter_scale_type, get_meter_type, ) async def test_get_meter_type(inovelli_switch: Node): """Test get_meter_type function.""" node = inovelli_switch value_id = get_value_id_str(node, CommandClass.SWITCH_BINARY, "currentValue") with pytest.raises(InvalidCommandClass): get_meter_type(node.values.get(value_id)) value_id = get_value_id_str(node, CommandClass.METER, "value", property_key=65537) assert get_meter_type(node.values.get(value_id)) == MeterType.ELECTRIC async def test_get_invalid_meter_type(invalid_multilevel_sensor_type: Node): """Test receiving an invalid meter type.""" node = invalid_multilevel_sensor_type # Create value with an invalid meterType ID metadata = MetaDataType(ccSpecific={CC_SPECIFIC_METER_TYPE: -1}) value_data = ValueDataType( commandClass=CommandClass.METER, commandClassName="Meter", endpoint=0, property="value", propertyKey=9999999, metadata=metadata, ) value = Value(node, value_data) with pytest.raises(UnknownValueData): get_meter_type(value) async def test_get_meter_scale_type(inovelli_switch: Node): """Test get_meter_scale_type function.""" node = inovelli_switch value_id = get_value_id_str(node, CommandClass.METER, "value", property_key=65537) assert ( get_meter_scale_type(node.values.get(value_id)) == ElectricScale.KILOWATT_HOUR ) async def test_get_invalid_meter_scale_type(invalid_multilevel_sensor_type: Node): """Test receiving an invalid meter scale type.""" node = invalid_multilevel_sensor_type # Create value with an invalid scale ID metadata = MetaDataType( ccSpecific={CC_SPECIFIC_METER_TYPE: 1, CC_SPECIFIC_SCALE: -1} ) value_data = ValueDataType( commandClass=CommandClass.METER, commandClassName="Meter", endpoint=0, property="value", propertyKey=9999999, metadata=metadata, ) value = Value(node, value_data) with pytest.raises(UnknownValueData): get_meter_scale_type(value) zwave-js-server-python-0.63.0/test/util/command_class/test_multilevel_sensor.py000066400000000000000000000052161500374325600301250ustar00rootroot00000000000000"""Test command class utility functions.""" import pytest from zwave_js_server.const import CommandClass from zwave_js_server.const.command_class.multilevel_sensor import ( MultilevelSensorType, TemperatureScale, ) from zwave_js_server.exceptions import InvalidCommandClass, UnknownValueData from zwave_js_server.model.node import Node from zwave_js_server.model.value import ( MetaDataType, Value, ValueDataType, get_value_id_str, ) from zwave_js_server.util.command_class.multilevel_sensor import ( CC_SPECIFIC_SCALE, CC_SPECIFIC_SENSOR_TYPE, get_multilevel_sensor_scale_type, get_multilevel_sensor_type, ) async def test_get_multilevel_sensor_type(multisensor_6: Node): """Test get_multilevel_sensor_type function.""" node = multisensor_6 value_id = get_value_id_str(node, CommandClass.SENSOR_BINARY, "Any") with pytest.raises(InvalidCommandClass): get_multilevel_sensor_type(node.values.get(value_id)) value_id = get_value_id_str(node, CommandClass.SENSOR_MULTILEVEL, "Air temperature") assert ( get_multilevel_sensor_type(node.values.get(value_id)) == MultilevelSensorType.AIR_TEMPERATURE ) async def test_get_invalid_multilevel_sensor_type(invalid_multilevel_sensor_type: Node): """Test receiving an invalid multilevel sensor type.""" node = invalid_multilevel_sensor_type value_id = get_value_id_str( node, CommandClass.SENSOR_MULTILEVEL, "UNKNOWN (0x00)", endpoint=2 ) with pytest.raises(UnknownValueData): get_multilevel_sensor_type(node.values.get(value_id)) async def test_get_multilevel_sensor_scale_type(multisensor_6: Node): """Test get_multilevel_sensor_scale_type function.""" node = multisensor_6 value_id = get_value_id_str(node, CommandClass.SENSOR_MULTILEVEL, "Air temperature") assert ( get_multilevel_sensor_scale_type(node.values.get(value_id)) == TemperatureScale.CELSIUS ) async def test_get_invalid_multilevel_sensor_scale_type( invalid_multilevel_sensor_type: Node, ): """Test receiving an invalid multilevel sensor scale type.""" node = invalid_multilevel_sensor_type # Create value with an invalid scale ID metadata = MetaDataType( ccSpecific={CC_SPECIFIC_SENSOR_TYPE: 1, CC_SPECIFIC_SCALE: -1} ) value_data = ValueDataType( commandClass=CommandClass.SENSOR_MULTILEVEL, commandClassName="Multilevel Sensor", endpoint=0, property="value", propertyKey=9999999, metadata=metadata, ) value = Value(node, value_data) with pytest.raises(UnknownValueData): get_multilevel_sensor_scale_type(value) zwave-js-server-python-0.63.0/test/util/const.py000066400000000000000000000101351500374325600216320ustar00rootroot00000000000000"""Constants for utility tests.""" from zwave_js_server.const.command_class.lock import ( ATTR_CODE_SLOT, ATTR_IN_USE, ATTR_NAME, ATTR_USERCODE, ) CODE_SLOTS = [ { ATTR_CODE_SLOT: 1, ATTR_IN_USE: True, ATTR_NAME: "User Code (1)", ATTR_USERCODE: "**********", }, { ATTR_CODE_SLOT: 2, ATTR_IN_USE: True, ATTR_NAME: "User Code (2)", ATTR_USERCODE: "**********", }, { ATTR_CODE_SLOT: 3, ATTR_IN_USE: True, ATTR_NAME: "User Code (3)", ATTR_USERCODE: "**********", }, { ATTR_CODE_SLOT: 4, ATTR_IN_USE: True, ATTR_NAME: "User Code (4)", ATTR_USERCODE: "7030\n\r", }, { ATTR_CODE_SLOT: 5, ATTR_IN_USE: False, ATTR_NAME: "User Code (5)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 6, ATTR_IN_USE: False, ATTR_NAME: "User Code (6)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 7, ATTR_IN_USE: False, ATTR_NAME: "User Code (7)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 8, ATTR_IN_USE: False, ATTR_NAME: "User Code (8)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 9, ATTR_IN_USE: False, ATTR_NAME: "User Code (9)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 10, ATTR_IN_USE: False, ATTR_NAME: "User Code (10)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 11, ATTR_IN_USE: False, ATTR_NAME: "User Code (11)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 12, ATTR_IN_USE: False, ATTR_NAME: "User Code (12)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 13, ATTR_IN_USE: False, ATTR_NAME: "User Code (13)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 14, ATTR_IN_USE: False, ATTR_NAME: "User Code (14)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 15, ATTR_IN_USE: False, ATTR_NAME: "User Code (15)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 16, ATTR_IN_USE: False, ATTR_NAME: "User Code (16)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 17, ATTR_IN_USE: False, ATTR_NAME: "User Code (17)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 18, ATTR_IN_USE: False, ATTR_NAME: "User Code (18)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 19, ATTR_IN_USE: False, ATTR_NAME: "User Code (19)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 20, ATTR_IN_USE: False, ATTR_NAME: "User Code (20)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 21, ATTR_IN_USE: False, ATTR_NAME: "User Code (21)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 22, ATTR_IN_USE: False, ATTR_NAME: "User Code (22)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 23, ATTR_IN_USE: False, ATTR_NAME: "User Code (23)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 24, ATTR_IN_USE: False, ATTR_NAME: "User Code (24)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 25, ATTR_IN_USE: False, ATTR_NAME: "User Code (25)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 26, ATTR_IN_USE: False, ATTR_NAME: "User Code (26)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 27, ATTR_IN_USE: False, ATTR_NAME: "User Code (27)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 28, ATTR_IN_USE: False, ATTR_NAME: "User Code (28)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 29, ATTR_IN_USE: False, ATTR_NAME: "User Code (29)", ATTR_USERCODE: "", }, { ATTR_CODE_SLOT: 30, ATTR_IN_USE: None, ATTR_NAME: "User Code (30)", ATTR_USERCODE: None, }, ] zwave-js-server-python-0.63.0/test/util/test_lock.py000066400000000000000000000264401500374325600225010ustar00rootroot00000000000000"""Test lock utility functions.""" import copy import pytest from test.common import MockCommandProtocol from zwave_js_server.const import SupervisionStatus from zwave_js_server.const.command_class.lock import ( ATTR_CODE_SLOT, ATTR_IN_USE, ATTR_NAME, ATTR_USERCODE, LOCK_USERCODE_ID_PROPERTY, LOCK_USERCODE_PROPERTY, LOCK_USERCODE_STATUS_PROPERTY, CodeSlotStatus, DoorLockCCConfigurationSetOptions, OperationType, ) from zwave_js_server.exceptions import NotFoundError from zwave_js_server.model.node import Node from zwave_js_server.model.value import SupervisionResult from zwave_js_server.util.lock import ( clear_usercode, get_code_slots, get_usercode, get_usercode_from_node, get_usercodes, set_configuration, set_usercode, set_usercodes, ) from .const import CODE_SLOTS def test_get_code_slots(lock_schlage_be469): """Test get_code_slots utility function.""" node = lock_schlage_be469 assert get_code_slots(node) == [ {k: v for k, v in code_slot.items() if k != ATTR_USERCODE} for code_slot in CODE_SLOTS ] def test_get_usercode(lock_schlage_be469): """Test get_usercode utility function.""" node = lock_schlage_be469 # Test in use slot slot = get_usercode(node, 1) assert all(char == "*" for char in slot[ATTR_USERCODE]) # Test unused slot assert get_usercode(node, 29)[ATTR_USERCODE] == "" # Test unknown slot assert get_usercode(node, 30)[ATTR_USERCODE] is None # Test invalid slot with pytest.raises(NotFoundError): get_usercode(node, 100) def test_get_usercodes(lock_schlage_be469): """Test get_usercodes utility function.""" node = lock_schlage_be469 assert get_usercodes(node) == CODE_SLOTS async def test_set_usercode(lock_schlage_be469, mock_command, uuid4): """Test set_usercode utility function.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) # Test valid code await set_usercode(node, 1, "1234") assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_value", "nodeId": 20, "messageId": uuid4, "valueId": { "commandClass": 99, "endpoint": 0, "property": "userCode", "propertyKey": 1, }, "value": "1234", } # Test invalid code slot with pytest.raises(NotFoundError): await set_usercode(node, 100, "1234") # assert no new command calls assert len(ack_commands) == 1 async def test_set_usercodes( lock_schlage_be469: Node, mock_command: MockCommandProtocol, uuid4: str ) -> None: """Test set_usercodes utility function.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "endpoint": 0, "nodeId": node.node_id}, {"response": {"status": 255}}, ) assert await set_usercodes(node, {1: "1234"}) == SupervisionResult( {"status": SupervisionStatus.SUCCESS} ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "commandClass": 99, "endpoint": 0, "methodName": "setMany", "nodeId": 20, "messageId": uuid4, "args": [ [ { LOCK_USERCODE_STATUS_PROPERTY: CodeSlotStatus.ENABLED, LOCK_USERCODE_ID_PROPERTY: 1, LOCK_USERCODE_PROPERTY: "1234", } ] ], } async def test_set_usercodes_invalid( lock_schlage_be469: Node, mock_command: MockCommandProtocol ) -> None: """Test set_usercodes utility function with invalid response.""" node = lock_schlage_be469 mock_command( {"command": "endpoint.invoke_cc_api", "endpoint": 0, "nodeId": node.node_id}, {"response": {}}, ) with pytest.raises(ValueError): assert await set_usercodes(node, {"1": 1234}) async def test_clear_usercode(lock_schlage_be469, mock_command, uuid4): """Test clear_usercode utility function.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) # Test valid code await clear_usercode(node, 1) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_value", "nodeId": 20, "messageId": uuid4, "valueId": { "commandClass": 99, "endpoint": 0, "property": "userIdStatus", "propertyKey": 1, }, "value": 0, } # Test invalid code slot with pytest.raises(NotFoundError): await clear_usercode(node, 100) # assert no new command calls assert len(ack_commands) == 1 async def test_get_usercode_from_node(lock_schlage_be469, mock_command, uuid4): """Test get_usercode_from_node utility function.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {"response": {"userIdStatus": 1, "userCode": "**********"}}, ) # Test valid code assert await get_usercode_from_node(node, 1) == { ATTR_NAME: "User Code (1)", ATTR_CODE_SLOT: 1, ATTR_IN_USE: True, ATTR_USERCODE: "**********", } assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": 20, "endpoint": 0, "commandClass": 99, "messageId": uuid4, "methodName": "get", "args": [1], } async def test_set_configuration_empty_response( lock_schlage_be469, mock_command, uuid4 ): """Test set_configuration utility function without response.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {}, ) await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions(OperationType.CONSTANT), ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": 20, "endpoint": 0, "commandClass": 98, "messageId": uuid4, "methodName": "setConfiguration", "args": [ { "insideHandlesCanOpenDoorConfiguration": [True, True, True, True], "operationType": 1, "outsideHandlesCanOpenDoorConfiguration": [True, True, True, True], } ], } with pytest.raises(ValueError): await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions(OperationType.CONSTANT, 1), ) with pytest.raises(ValueError): await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions(OperationType.TIMED), ) async def test_set_configuration_with_response(lock_schlage_be469, mock_command, uuid4): """Test set_configuration utility function with response.""" node = lock_schlage_be469 ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {"response": {"status": 0}}, ) result = await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions(OperationType.CONSTANT), ) assert result.status == SupervisionStatus.NO_SUPPORT assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": 20, "endpoint": 0, "commandClass": 98, "messageId": uuid4, "methodName": "setConfiguration", "args": [ { "insideHandlesCanOpenDoorConfiguration": [True, True, True, True], "operationType": 1, "outsideHandlesCanOpenDoorConfiguration": [True, True, True, True], } ], } async def test_set_configuration_v4( driver, lock_ultraloq_ubolt_pro_state, mock_command, uuid4 ): """Test v4 properties in set_configuration utility function.""" node_state = copy.deepcopy(lock_ultraloq_ubolt_pro_state) node_state["values"].remove( { "endpoint": 0, "commandClass": 98, "commandClassName": "Door Lock", "property": "twistAssist", "propertyName": "twistAssist", "ccVersion": 4, "metadata": { "type": "boolean", "readable": True, "writeable": True, "label": "Twist Assist enabled", }, "value": False, }, ) node = Node(driver.client, node_state) ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {}, ) await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions( OperationType.CONSTANT, hold_and_release_time=2, block_to_block=True ), ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": 34, "endpoint": 0, "commandClass": 98, "messageId": uuid4, "methodName": "setConfiguration", "args": [ { "insideHandlesCanOpenDoorConfiguration": [True, True, True, True], "operationType": 1, "outsideHandlesCanOpenDoorConfiguration": [True, True, True, True], "autoRelockTime": 0, "holdAndReleaseTime": 2, "blockToBlock": True, } ], } # Test a property that isn't on the node with pytest.raises(ValueError): await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions( OperationType.CONSTANT, twist_assist=True ), ) @pytest.mark.usefixtures("driver") async def test_set_configuration_timed_lock( timed_lock: Node, mock_command: MockCommandProtocol, uuid4: str ) -> None: """Test a timed lock in set_configuration utility function.""" node = timed_lock ack_commands = mock_command( {"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0}, {}, ) await set_configuration( node.endpoints[0], DoorLockCCConfigurationSetOptions( OperationType.TIMED, lock_timeout_configuration=42 ), ) assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "endpoint.invoke_cc_api", "nodeId": 7, "endpoint": 0, "commandClass": 98, "messageId": uuid4, "methodName": "setConfiguration", "args": [ { "operationType": OperationType.TIMED, "autoRelockTime": 0, "blockToBlock": True, "holdAndReleaseTime": 0, "twistAssist": True, "insideHandlesCanOpenDoorConfiguration": [True, True, True, True], "outsideHandlesCanOpenDoorConfiguration": [True, True, True, True], "lockTimeoutConfiguration": 42, } ], } zwave-js-server-python-0.63.0/test/util/test_multicast.py000066400000000000000000000230701500374325600235520ustar00rootroot00000000000000"""Test node utility functions.""" from zwave_js_server.const import CommandClass, SetValueStatus from zwave_js_server.util.multicast import ( async_multicast_endpoint_get_cc_version, async_multicast_endpoint_invoke_cc_api, async_multicast_endpoint_supports_cc, async_multicast_endpoint_supports_cc_api, async_multicast_get_endpoint_count, async_multicast_set_value, ) async def test_endpoint_get_cc_version_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.get_cc_version command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.get_cc_version"}, {"version": 1}, ) assert ( await async_multicast_endpoint_get_cc_version( client, 1, CommandClass.NOTIFICATION, [node1, node2] ) == 1 ) assert ack_commands[0] == { "command": "multicast_group.get_cc_version", "index": 1, "commandClass": 113, "nodeIDs": [node1.node_id, node2.node_id], "messageId": uuid4, } async def test_endpoint_get_cc_version_broadcast(client, uuid4, mock_command): """Test broadcast_node.get_cc_version command.""" ack_commands = mock_command( {"command": "broadcast_node.get_cc_version"}, {"version": 1}, ) assert ( await async_multicast_endpoint_get_cc_version( client, 1, CommandClass.NOTIFICATION ) == 1 ) assert ack_commands[0] == { "command": "broadcast_node.get_cc_version", "index": 1, "commandClass": 113, "messageId": uuid4, } async def test_endpoint_supports_cc_broadcast(client, uuid4, mock_command): """Test broadcast_node.supports_cc command.""" ack_commands = mock_command( {"command": "broadcast_node.supports_cc"}, {"supported": True}, ) assert await async_multicast_endpoint_supports_cc( client, 1, CommandClass.NOTIFICATION ) assert ack_commands[0] == { "command": "broadcast_node.supports_cc", "index": 1, "commandClass": 113, "messageId": uuid4, } async def test_endpoint_supports_cc_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.supports_cc command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.supports_cc"}, {"supported": True}, ) assert await async_multicast_endpoint_supports_cc( client, 1, CommandClass.NOTIFICATION, [node1, node2] ) assert ack_commands[0] == { "command": "multicast_group.supports_cc", "index": 1, "commandClass": 113, "nodeIDs": [node1.node_id, node2.node_id], "messageId": uuid4, } async def test_get_endpoint_count_broadcast(client, uuid4, mock_command): """Test broadcast_node.get_endpoint_count command.""" ack_commands = mock_command( {"command": "broadcast_node.get_endpoint_count"}, {"count": 1}, ) assert await async_multicast_get_endpoint_count(client) == 1 assert ack_commands[0] == { "command": "broadcast_node.get_endpoint_count", "messageId": uuid4, } async def test_get_endpoint_count_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.get_endpoint_count command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.get_endpoint_count"}, {"count": 1}, ) assert await async_multicast_get_endpoint_count(client, [node1, node2]) == 1 assert ack_commands[0] == { "command": "multicast_group.get_endpoint_count", "nodeIDs": [node1.node_id, node2.node_id], "messageId": uuid4, } async def test_set_value_broadcast(client, driver, uuid4, mock_command): """Test broadcast_node.set_value command.""" ack_commands = mock_command( {"command": "broadcast_node.set_value"}, {"result": {"status": 255}}, ) result = await async_multicast_set_value( client, 1, {"commandClass": 1, "property": 1} ) assert result.status == SetValueStatus.SUCCESS assert ack_commands[0] == { "command": "broadcast_node.set_value", "value": 1, "valueId": {"commandClass": 1, "property": 1}, "options": None, "messageId": uuid4, } async def test_set_value_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.set_value command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.set_value"}, {"result": {"status": 255}}, ) result = await async_multicast_set_value( client, 1, {"commandClass": 112, "property": 1}, [node1, node2] ) assert result.status == SetValueStatus.SUCCESS assert ack_commands[0] == { "command": "multicast_group.set_value", "nodeIDs": [node1.node_id, node2.node_id], "value": 1, "valueId": {"commandClass": 112, "property": 1}, "options": None, "messageId": uuid4, } async def test_set_value_multicast_basic( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.set_value command with Basic CC.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.set_value"}, {"result": {"status": 255}}, ) result = await async_multicast_set_value( client, 1, {"commandClass": 32, "property": "targetValue"}, [node1, node2] ) assert result.status == SetValueStatus.SUCCESS assert ack_commands[0] == { "command": "multicast_group.set_value", "nodeIDs": [node1.node_id, node2.node_id], "value": 1, "valueId": {"commandClass": 32, "property": "targetValue"}, "options": None, "messageId": uuid4, } async def test_invoke_cc_api_broadcast(client, uuid4, mock_command): """Test broadcast_node.invoke_cc_api command.""" ack_commands = mock_command( {"command": "broadcast_node.invoke_cc_api"}, {"response": 1}, ) assert ( await async_multicast_endpoint_invoke_cc_api( client, 1, 1, "test", ["test_args", "test_args2"] ) == 1 ) assert ack_commands[0] == { "command": "broadcast_node.invoke_cc_api", "index": 1, "commandClass": 1, "methodName": "test", "args": ["test_args", "test_args2"], "messageId": uuid4, } async def test_invoke_cc_api_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.invoke_cc_api command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.invoke_cc_api"}, {"response": 1}, ) assert ( await async_multicast_endpoint_invoke_cc_api( client, 1, 1, "test", ["test_args", "test_args2"], [node1, node2] ) == 1 ) assert ack_commands[0] == { "command": "multicast_group.invoke_cc_api", "nodeIDs": [node1.node_id, node2.node_id], "index": 1, "commandClass": 1, "methodName": "test", "args": ["test_args", "test_args2"], "messageId": uuid4, } async def test_supports_cc_api_broadcast(client, uuid4, mock_command): """Test broadcast_node.supports_cc_api command.""" ack_commands = mock_command( {"command": "broadcast_node.supports_cc_api"}, {"supported": True}, ) assert await async_multicast_endpoint_supports_cc_api(client, 1, 1) assert ack_commands[0] == { "command": "broadcast_node.supports_cc_api", "index": 1, "commandClass": 1, "messageId": uuid4, } async def test_supports_cc_api_multicast( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.supports_cc_api command.""" node1 = climate_radio_thermostat_ct100_plus node2 = inovelli_switch ack_commands = mock_command( {"command": "multicast_group.supports_cc_api"}, {"supported": True}, ) assert await async_multicast_endpoint_supports_cc_api(client, 1, 1, [node1, node2]) assert ack_commands[0] == { "command": "multicast_group.supports_cc_api", "nodeIDs": [node1.node_id, node2.node_id], "index": 1, "commandClass": 1, "messageId": uuid4, } async def test_set_value_broadcast_missing_value( climate_radio_thermostat_ct100_plus, inovelli_switch, client, uuid4, mock_command ): """Test multicast_group.set_value command with value missing from a node.""" ack_commands = mock_command( {"command": "broadcast_node.set_value"}, {"result": {"status": 255}}, ) result = await async_multicast_set_value( client, 1, {"commandClass": 67, "property": "blah"} ) assert result.status == SetValueStatus.SUCCESS assert ack_commands[0] == { "command": "broadcast_node.set_value", "value": 1, "valueId": {"commandClass": 67, "property": "blah"}, "options": None, "messageId": uuid4, } zwave-js-server-python-0.63.0/test/util/test_node.py000066400000000000000000000324651500374325600225020ustar00rootroot00000000000000"""Test node utility functions.""" import copy from unittest.mock import patch import pytest from zwave_js_server.const import CommandClass, CommandStatus from zwave_js_server.exceptions import ( BulkSetConfigParameterFailed, InvalidNewValue, NotFoundError, SetValueFailed, ValueTypeError, ) from zwave_js_server.model.node import Node from zwave_js_server.model.value import ConfigurationValue from zwave_js_server.util.node import ( async_bulk_set_partial_config_parameters, async_set_config_parameter, dump_node_state, ) @pytest.mark.parametrize("endpoint", [0, 1]) async def test_configuration_parameter_values( endpoint, client, climate_radio_thermostat_ct100_plus_state, inovelli_switch_state, uuid4, mock_command, ): """Test node methods to get and set configuration parameter values.""" node_state = copy.deepcopy(climate_radio_thermostat_ct100_plus_state) node_2_state = copy.deepcopy(inovelli_switch_state) # Put all config parameters on endpoint we are testing for state in (node_state, node_2_state): for value in state["values"]: if ( value["commandClass"] == CommandClass.CONFIGURATION and value["endpoint"] == 0 ): value["endpoint"] = endpoint node: Node = Node(client, node_state) node_2: Node = Node(client, node_2_state) ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) assert node.node_id == 13 config_values = node.get_configuration_values() assert len(config_values) == 12 assert node_2.node_id == 31 config_values_2 = node_2.get_configuration_values() assert len(config_values_2) == 15 for value in config_values.values(): assert isinstance(value, ConfigurationValue) # Test setting a configuration parameter that has no metadata with pytest.raises(NotImplementedError): await async_set_config_parameter(node, 1, 2, endpoint=endpoint) # Test setting a manual entry configuration parameter with a valid value ack_commands_2 = mock_command( {"command": "node.set_value", "nodeId": node_2.node_id}, {"result": {"status": 255}}, ) zwave_value, cmd_status = await async_set_config_parameter( node_2, 190, 8, 255, endpoint=endpoint ) assert isinstance(zwave_value, ConfigurationValue) assert cmd_status.status == CommandStatus.ACCEPTED value = node_2.values[f"31-112-{endpoint}-8-255"] assert len(ack_commands_2) == 1 assert ack_commands_2[0] == { "command": "node.set_value", "nodeId": node_2.node_id, "valueId": { "commandClass": 112, "endpoint": endpoint, "property": 8, "propertyKey": 255, }, "value": 190, "messageId": uuid4, } zwave_value, cmd_status = await async_set_config_parameter( node_2, "Blue", 8, 255, endpoint=endpoint ) assert isinstance(zwave_value, ConfigurationValue) assert cmd_status.status == CommandStatus.ACCEPTED value = node_2.values[f"31-112-{endpoint}-8-255"] assert len(ack_commands_2) == 2 assert ack_commands_2[1] == { "command": "node.set_value", "nodeId": node_2.node_id, "valueId": { "commandClass": 112, "endpoint": endpoint, "property": 8, "propertyKey": 255, }, "value": 170, "messageId": uuid4, } # Test configuration parameter not found when using an invalid property name with pytest.raises(NotFoundError): await async_set_config_parameter( node, 5, "fake configuration parameter name", endpoint=endpoint ) # Test using an invalid state label to set a value with pytest.raises(InvalidNewValue): await async_set_config_parameter(node, "fake state label", 1, endpoint=endpoint) # Test configuration parameter not found when property key is invalid with pytest.raises(NotFoundError): await async_set_config_parameter(node, 1, 1, property_key=1, endpoint=endpoint) # Test setting a configuration parameter by state label and property name zwave_value, cmd_status = await async_set_config_parameter( node, "2.0\u00b0 F", "Temperature Reporting Threshold", endpoint=endpoint ) assert isinstance(zwave_value, ConfigurationValue) assert cmd_status.status == CommandStatus.ACCEPTED value = node.values[f"13-112-{endpoint}-1"] assert len(ack_commands) == 3 assert ack_commands[2] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": 112, "endpoint": endpoint, "property": 1, }, "value": 4, "messageId": uuid4, } @pytest.mark.parametrize("endpoint", [0, 1]) async def test_bulk_set_partial_config_parameters( endpoint, client, multisensor_6_state, uuid4, mock_command ): """Test bulk setting partial config parameters.""" node_state = copy.deepcopy(multisensor_6_state) # Put all config parameters on endpoint we are testing for value in node_state["values"]: if ( value["commandClass"] == CommandClass.CONFIGURATION and value["endpoint"] == 0 ): value["endpoint"] = endpoint node: Node = Node(client, node_state) ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) cmd_status = await async_bulk_set_partial_config_parameters( node, 101, 241, endpoint=endpoint ) assert cmd_status.status == CommandStatus.QUEUED assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": 101, }, "value": 241, "messageId": uuid4, } cmd_status = await async_bulk_set_partial_config_parameters( node, 101, {128: 1, 64: 1, 32: 1, 16: 1, 1: 1}, endpoint=endpoint ) assert cmd_status.status == CommandStatus.QUEUED assert len(ack_commands) == 2 assert ack_commands[1] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": 101, }, "value": 241, "messageId": uuid4, } # Only set some values so we use cached values for the rest cmd_status = await async_bulk_set_partial_config_parameters( node, 101, {64: 1, 32: 1, 16: 1, 1: 1}, endpoint=endpoint ) assert cmd_status.status == CommandStatus.QUEUED assert len(ack_commands) == 3 assert ack_commands[2] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": 101, }, "value": 241, "messageId": uuid4, } # Use property key names instead of bitmasks for dict key cmd_status = await async_bulk_set_partial_config_parameters( node, 101, { "Group 1: Send humidity reports": 1, "Group 1: Send temperature reports": 1, "Group 1: Send ultraviolet reports": 1, "Group 1: Send battery reports": 1, }, endpoint=endpoint, ) assert cmd_status.status == CommandStatus.QUEUED assert len(ack_commands) == 4 assert ack_commands[3] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": 101, }, "value": 241, "messageId": uuid4, } # Use an invalid property with pytest.raises(NotFoundError): await async_bulk_set_partial_config_parameters(node, 999, 99, endpoint=endpoint) # use an invalid bitmask with pytest.raises(NotFoundError): await async_bulk_set_partial_config_parameters( node, 101, {128: 1, 64: 1, 32: 1, 16: 1, 2: 1}, endpoint=endpoint ) # use an invalid property name with pytest.raises(NotFoundError): await async_bulk_set_partial_config_parameters( node, 101, {"Invalid property name": 1}, endpoint=endpoint ) # use an invalid state value with pytest.raises(BulkSetConfigParameterFailed): await async_bulk_set_partial_config_parameters( node, 101, {128: "fake state", 64: 1, 32: 1, 16: 1, 1: 1}, endpoint=endpoint ) # Try to bulkset a property that isn't broken into partials with a dictionary with pytest.raises(ValueTypeError): await async_bulk_set_partial_config_parameters( node, 252, {1: 1}, endpoint=endpoint ) # Try to bulkset a property that isn't broken into partials, it should fall back to # async_set_config_parameter with patch("zwave_js_server.util.node.async_set_config_parameter") as mock_cmd: mock_cmd.return_value = (None, None) await async_bulk_set_partial_config_parameters(node, 252, 1, endpoint=endpoint) mock_cmd.assert_called_once() @pytest.mark.parametrize("endpoint", [0, 1]) async def test_bulk_set_with_full_and_partial_parameters( endpoint, client, partial_and_full_parameter_state, uuid4, mock_command ): """Test bulk setting config parameters when state has full and partial values.""" node_state = copy.deepcopy(partial_and_full_parameter_state) # Put all config parameters on endpoint we are testing for value in node_state["values"]: if ( value["commandClass"] == CommandClass.CONFIGURATION and value["endpoint"] == 0 ): value["endpoint"] = endpoint node: Node = Node(client, node_state) ack_commands = mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) cmd_status = await async_bulk_set_partial_config_parameters( node, 8, 34867929, endpoint=endpoint ) assert cmd_status.status == CommandStatus.ACCEPTED assert len(ack_commands) == 1 assert ack_commands[0] == { "command": "node.set_value", "nodeId": node.node_id, "valueId": { "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": 8, }, "value": 34867929, "messageId": uuid4, } @pytest.mark.parametrize("endpoint", [0, 1]) async def test_failures(endpoint, client, multisensor_6_state, mock_command): """Test setting config parameter failures.""" node_state = copy.deepcopy(multisensor_6_state) # Put all config parameters on endpoint we are testing for value in node_state["values"]: if ( value["commandClass"] == CommandClass.CONFIGURATION and value["endpoint"] == 0 ): value["endpoint"] = endpoint node: Node = Node(client, node_state) # We need the node to be alive so we wait for a response node.handle_alive(node) mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 0}}, ) with pytest.raises(SetValueFailed): await async_bulk_set_partial_config_parameters( node, 101, {64: 1, 32: 1, 16: 1, 1: 1}, endpoint=endpoint ) with pytest.raises(SetValueFailed): await async_set_config_parameter(node, 1, 101, 64, endpoint=endpoint) @pytest.mark.parametrize("endpoint", [0, 1]) async def test_returned_values(endpoint, client, multisensor_6_state, mock_command): """Test returned values from setting config parameters.""" node_state = copy.deepcopy(multisensor_6_state) # Put all config parameters on endpoint we are testing for value in node_state["values"]: if ( value["commandClass"] == CommandClass.CONFIGURATION and value["endpoint"] == 0 ): value["endpoint"] = endpoint node: Node = Node(client, node_state) # We need the node to be alive so we wait for a response node.handle_alive(node) mock_command( {"command": "node.set_value", "nodeId": node.node_id}, {"result": {"status": 255}}, ) cmd_status = await async_bulk_set_partial_config_parameters( node, 101, {64: 1, 32: 1, 16: 1, 1: 1}, endpoint=endpoint ) assert cmd_status.status == CommandStatus.ACCEPTED zwave_value, cmd_status = await async_set_config_parameter( node, 1, 101, 64, endpoint=endpoint ) assert isinstance(zwave_value, ConfigurationValue) assert cmd_status.status == CommandStatus.ACCEPTED async def test_dump_node_state(inovelli_switch, inovelli_switch_state): """Test dumping the node state.""" assert inovelli_switch_state != inovelli_switch.data assert "values" not in inovelli_switch.data assert "endpoints" not in inovelli_switch.data dump_state = dump_node_state(inovelli_switch) for val in dump_state["values"].values(): assert val in inovelli_switch_state["values"] for endpoint in dump_state["endpoints"].values(): assert endpoint in inovelli_switch_state["endpoints"] zwave-js-server-python-0.63.0/tox.ini000066400000000000000000000012311500374325600175060ustar00rootroot00000000000000[tox] envlist = py312, py313, lint, mypy skip_missing_interpreters = True [gh-actions] python = 3.12: py312, lint, mypy 3.13: py313 [testenv] commands = pytest --timeout=30 --cov=zwave_js_server --cov-report=xml {posargs} deps = -rrequirements.txt -rrequirements_test.txt [testenv:lint] basepython = python3 ignore_errors = True commands = black --check ./ ruff check zwave_js_server scripts test pylint zwave_js_server deps = -rrequirements.txt -rrequirements_lint.txt -rrequirements_test.txt [testenv:mypy] basepython = python3 ignore_errors = True commands = mypy zwave_js_server deps = -rrequirements.txt -rrequirements_lint.txt zwave-js-server-python-0.63.0/zwave_js_server/000077500000000000000000000000001500374325600214145ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/__init__.py000066400000000000000000000000551500374325600235250ustar00rootroot00000000000000"""Provide a package for zwave-js-server.""" zwave-js-server-python-0.63.0/zwave_js_server/__main__.py000066400000000000000000000071131500374325600235100ustar00rootroot00000000000000"""Basic CLI to test Z-Wave JS server.""" from __future__ import annotations import argparse import asyncio import logging import sys import aiohttp from .client import Client from .dump import dump_msgs from .version import get_server_version LOGGER = logging.getLogger(__package__) def get_arguments() -> argparse.Namespace: """Get parsed passed in arguments.""" parser = argparse.ArgumentParser(description="Z-Wave JS Server Python") parser.add_argument("--debug", action="store_true", help="Log with debug level") parser.add_argument( "--server-version", action="store_true", help="Print the version of the server" ) parser.add_argument( "--dump-state", action="store_true", help="Dump the driver state" ) parser.add_argument( "--event-timeout", help="How long to listen for events when dumping state", ) parser.add_argument( "url", type=str, help="URL of server, ie ws://localhost:3000", ) arguments = parser.parse_args() return arguments async def start_cli() -> None: """Run main.""" args = get_arguments() level = logging.DEBUG if args.debug else logging.INFO logging.basicConfig(level=level) async with aiohttp.ClientSession() as session: if args.server_version: await print_version(args, session) elif args.dump_state: await handle_dump_state(args, session) else: await connect(args, session) async def print_version( args: argparse.Namespace, session: aiohttp.ClientSession ) -> None: """Print the version of the server.""" LOGGER.setLevel(logging.WARNING) version = await get_server_version(args.url, session) print("Driver:", version.driver_version) print("Server:", version.server_version) print("Home ID:", version.home_id) async def handle_dump_state( args: argparse.Namespace, session: aiohttp.ClientSession ) -> None: """Dump the state of the server.""" timeout = None if args.event_timeout is None else float(args.event_timeout) msgs = await dump_msgs(args.url, session, timeout=timeout) for msg in msgs: print(msg) async def connect(args: argparse.Namespace, session: aiohttp.ClientSession) -> None: """Connect to the server.""" async with Client(args.url, session) as client: driver_ready = asyncio.Event() asyncio.create_task(on_driver_ready(client, driver_ready)) await client.listen(driver_ready) async def on_driver_ready(client: Client, driver_ready: asyncio.Event) -> None: """Act on driver ready.""" await driver_ready.wait() assert client.driver # Set up listeners on new nodes client.driver.controller.on( "node added", lambda event: event["node"].on("value updated", log_value_updated), ) # Set up listeners on existing nodes for node in client.driver.controller.nodes.values(): node.on("value updated", log_value_updated) def log_value_updated(event: dict) -> None: """Log node value changes.""" node = event["node"] value = event["value"] if node.device_config: description = node.device_config.description else: description = f"{node.device_class.generic} (missing device config)" LOGGER.info( "Node %s %s (%s) changed to %s", description, value.property_name or "", value.value_id, value.value, ) def main() -> None: """Run main.""" try: asyncio.run(start_cli()) except KeyboardInterrupt: pass sys.exit(0) if __name__ == "__main__": main() zwave-js-server-python-0.63.0/zwave_js_server/client.py000066400000000000000000000462051500374325600232530ustar00rootroot00000000000000"""Client.""" from __future__ import annotations import asyncio from collections import defaultdict from collections.abc import Callable from copy import deepcopy from datetime import datetime import logging from operator import itemgetter import pprint from types import TracebackType from typing import Any, cast import uuid from aiohttp import ClientSession, ClientWebSocketResponse, WSMsgType, client_exceptions from .const import ( LOG_LEVEL_MAP, MAX_SERVER_SCHEMA_VERSION, MIN_SERVER_SCHEMA_VERSION, PACKAGE_NAME, LogLevel, __version__, ) from .event import Event from .exceptions import ( CannotConnect, ConnectionClosed, ConnectionFailed, FailedCommand, FailedZWaveCommand, InvalidMessage, InvalidServerVersion, InvalidState, NotConnected, ) from .model.driver import Driver from .model.log_message import LogMessage from .model.version import VersionInfo, VersionInfoDataType SIZE_PARSE_JSON_EXECUTOR = 8192 # Message IDs INITIALIZE_MESSAGE_ID = "initialize" GET_INITIAL_LOG_CONFIG_MESSAGE_ID = "get-initial-log-config" START_LISTENING_MESSAGE_ID = "start-listening" LISTEN_MESSAGE_IDS = ( GET_INITIAL_LOG_CONFIG_MESSAGE_ID, INITIALIZE_MESSAGE_ID, START_LISTENING_MESSAGE_ID, ) LOGGER = logging.getLogger(__package__) SERVER_LOGGER = logging.getLogger(f"{__package__}.server") class Client: """Class to manage the IoT connection.""" def __init__( self, ws_server_url: str, aiohttp_session: ClientSession, schema_version: int = MAX_SERVER_SCHEMA_VERSION, additional_user_agent_components: dict[str, str] | None = None, record_messages: bool = False, ): """Initialize the Client class.""" self.ws_server_url = ws_server_url self.aiohttp_session = aiohttp_session self.driver: Driver | None = None # The WebSocket client self._client: ClientWebSocketResponse | None = None # Version of the connected server self.version: VersionInfo | None = None self.schema_version: int = schema_version self.additional_user_agent_components = { PACKAGE_NAME: __version__, **(additional_user_agent_components or {}), } self._loop = asyncio.get_running_loop() self._result_futures: dict[str, asyncio.Future] = {} self._shutdown_complete_event: asyncio.Event | None = None self._server_logger_unsubs: list[Callable[[], None]] = [] self._server_logging_enabled: bool = False self._record_messages = record_messages self._recorded_commands: defaultdict[str, dict] = defaultdict(dict) self._recorded_events: list[dict] = [] def __repr__(self) -> str: """Return the representation.""" prefix = "" if self.connected else "not " return ( f"{type(self).__name__}(ws_server_url={self.ws_server_url!r}, " f"{prefix}connected)" ) @property def connected(self) -> bool: """Return if we're currently connected.""" return self._client is not None and not self._client.closed @property def recording_messages(self) -> bool: """Return True if messages are being recorded.""" return self._record_messages async def async_send_command( self, message: dict[str, Any], require_schema: int | None = None ) -> dict: """Send a command and get a response.""" if require_schema is not None and require_schema > self.schema_version: assert self.version raise InvalidServerVersion( self.version, require_schema, "Command not available due to incompatible server version. Update " "the Z-Wave JS Server to a version that supports at least api schema " f"{require_schema}.", ) future: asyncio.Future[dict] = self._loop.create_future() message_id = message["messageId"] = uuid.uuid4().hex self._result_futures[message_id] = future await self._send_json_message(message) try: return await future finally: self._result_futures.pop(message_id, None) async def async_send_command_no_wait( self, message: dict[str, Any], require_schema: int | None = None ) -> None: """Send a command without waiting for the response.""" if require_schema is not None and require_schema > self.schema_version: assert self.version raise InvalidServerVersion( self.version, require_schema, "Command not available due to incompatible server version. Update " "the Z-Wave JS Server to a version that supports at least api schema " f"{require_schema}.", ) message["messageId"] = uuid.uuid4().hex await self._send_json_message(message) async def connect(self) -> None: """Connect to the websocket server.""" if self.driver is not None: raise InvalidState("Re-connected with existing driver") LOGGER.debug("Trying to connect") try: self._client = await self.aiohttp_session.ws_connect( self.ws_server_url, heartbeat=55, compress=15, max_msg_size=0, ) except ( client_exceptions.WSServerHandshakeError, client_exceptions.ClientError, ) as err: raise CannotConnect(err) from err self.version = version = VersionInfo.from_message( cast(VersionInfoDataType, await self._receive_json_or_raise()) ) # basic check for server schema version compatibility if ( version.min_schema_version > MAX_SERVER_SCHEMA_VERSION or version.max_schema_version < MIN_SERVER_SCHEMA_VERSION ): await self._client.close() assert version raise InvalidServerVersion( version, MIN_SERVER_SCHEMA_VERSION, f"Z-Wave JS Server version ({version.server_version}) is " "incompatible. Update the Z-Wave JS Server to a version that supports " f"at least api schema {MIN_SERVER_SCHEMA_VERSION}", ) # store the (highest possible) schema version we're going to use/request # this is a bit future proof as we might decide to use a pinned version at some # point for now we just negotiate the highest available schema version and # guard incompatibility with the MIN_SERVER_SCHEMA_VERSION if version.max_schema_version < MAX_SERVER_SCHEMA_VERSION: self.schema_version = version.max_schema_version LOGGER.info( "Connected to Home %s (Server %s, Driver %s, Using Schema %s)", version.home_id, version.server_version, version.driver_version, self.schema_version, ) async def initialize(self) -> None: """Initialize connection to server by setting schema version and user agent.""" assert self._client # set preferred schema version on the server # note: we already check for (in)compatible schemas in the connect call await self._send_json_message( { "command": "initialize", "messageId": INITIALIZE_MESSAGE_ID, "schemaVersion": self.schema_version, "additionalUserAgentComponents": self.additional_user_agent_components, } ) set_api_msg = await self._receive_json_or_raise() if not set_api_msg["success"]: # this should not happen, but just in case await self._client.close() raise FailedCommand( set_api_msg["messageId"], set_api_msg["errorCode"], set_api_msg["message"], ) async def listen(self, driver_ready: asyncio.Event) -> None: """Start listening to the websocket.""" if not self.connected: raise InvalidState("Not connected when start listening") assert self._client try: await self.initialize() await self._send_json_message( { "command": "driver.get_log_config", "messageId": GET_INITIAL_LOG_CONFIG_MESSAGE_ID, } ) log_msg = await self._receive_json_or_raise() # this should not happen, but just in case if not log_msg["success"]: await self._client.close() raise FailedCommand( log_msg["messageId"], log_msg["errorCode"], log_msg["message"] ) # send start_listening command to the server # we will receive a full state dump and from now on get events await self._send_json_message( {"command": "start_listening", "messageId": START_LISTENING_MESSAGE_ID} ) state_msg = await self._receive_json_or_raise() if not state_msg["success"]: await self._client.close() raise FailedCommand( state_msg["messageId"], state_msg["errorCode"], state_msg["message"] ) self.driver = cast( Driver, await self._loop.run_in_executor( None, Driver, self, state_msg["result"]["state"], log_msg["result"]["config"], ), ) driver_ready.set() LOGGER.info( "Z-Wave JS initialized. %s nodes", len(self.driver.controller.nodes) ) await self.receive_until_closed() except ConnectionClosed: pass finally: LOGGER.debug("Listen completed. Cleaning up") for future in self._result_futures.values(): future.cancel() self._result_futures.clear() if not self._client.closed: await self._client.close() if self._shutdown_complete_event: self._shutdown_complete_event.set() async def disconnect(self) -> None: """Disconnect the client.""" LOGGER.debug("Closing client connection") if not self.connected: return assert self._client # 'listen' was never called if self.driver is None: await self._client.close() return self._shutdown_complete_event = asyncio.Event() await self._client.close() await self._shutdown_complete_event.wait() self._shutdown_complete_event = None self.driver = None async def async_start_listening_logs(self) -> None: """Send command to start listening to log events.""" await self.async_send_command( {"command": "start_listening_logs"}, require_schema=31 ) async def async_stop_listening_logs(self) -> None: """Send command to stop listening to log events.""" await self.async_send_command( {"command": "stop_listening_logs"}, require_schema=31 ) def begin_recording_messages(self) -> None: """Begin recording messages for replay later.""" if self._record_messages: raise InvalidState("Already recording messages") self._record_messages = True def end_recording_messages(self) -> list[dict]: """End recording messages and return messages that were recorded.""" if not self._record_messages: raise InvalidState("Not recording messages") self._record_messages = False data = sorted( (*self._recorded_commands.values(), *self._recorded_events), key=itemgetter("ts"), ) self._recorded_commands.clear() self._recorded_events.clear() return list(data) @property def server_logging_enabled(self) -> bool: """Return whether server logging is currently enabled.""" return self._server_logging_enabled async def enable_server_logging(self) -> None: """ Enable logging from the server. Embeds server logs in the library's logs. """ if not self.connected or not self.driver: raise InvalidState( "Can't enable server logging when not connected to server" ) if (log_level := self.driver.log_config.level) and ( level := LOG_LEVEL_MAP[log_level] ) < LOGGER.level: LOGGER.warning( ( "Server logging is currently more verbose than library logging, " "setting library log level to %s to match." ), logging.getLevelName(level), ) LOGGER.setLevel(level) if self._server_logging_enabled: return self._server_logging_enabled = True def handle_server_logs(event: dict) -> None: """Handle driver `logging` event.""" log_msg: LogMessage = event["log_message"] log_level = LogLevel(log_msg.level) SERVER_LOGGER.log( LOG_LEVEL_MAP[log_level], "%s:\n%s", log_msg.timestamp, "\n".join(log_msg.formatted_message), ) def handle_log_config_updates(event: dict) -> None: """Handle driver `log config updated` events.""" if (log_level := event["config"]["level"].lower()) and ( level := LOG_LEVEL_MAP[log_level] ) < LOGGER.level: LOGGER.warning( ( "Server logging is currently more verbose than library " "logging, setting library log level to %s to match." ), logging.getLevelName(level), ) LOGGER.setLevel(level) self._server_logger_unsubs = [ self.driver.on("logging", handle_server_logs), self.driver.on("log config updated", handle_log_config_updates), ] await self.async_start_listening_logs() def disable_server_logging(self) -> None: """Disable logging from the server.""" if not self._server_logging_enabled or not self._server_logger_unsubs: return for unsub in self._server_logger_unsubs: unsub() self._server_logger_unsubs.clear() self._server_logging_enabled = False async def receive_until_closed(self) -> None: """Receive messages until client is closed.""" assert self._client while not self._client.closed: data = await self._receive_json_or_raise() self._handle_incoming_message(data) async def _receive_json_or_raise(self) -> dict: """Receive json or raise.""" assert self._client msg = await self._client.receive() if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSED, WSMsgType.CLOSING): raise ConnectionClosed("Connection was closed.") if msg.type == WSMsgType.ERROR: raise ConnectionFailed() if msg.type != WSMsgType.TEXT: raise InvalidMessage(f"Received non-Text message: {msg.type}") try: if len(msg.data) > SIZE_PARSE_JSON_EXECUTOR: data: dict = await self._loop.run_in_executor(None, msg.json) else: data = msg.json() except ValueError as err: raise InvalidMessage("Received invalid JSON.") from err if LOGGER.isEnabledFor(logging.DEBUG) and not ( self.server_logging_enabled and data.get("type") == "event" and data.get("event", {}).get("event") == "logging" ): LOGGER.debug("Received message:\n%s\n", pprint.pformat(msg)) return data def _handle_incoming_message(self, msg: dict) -> None: """Handle incoming message. Run all async tasks in a wrapper to log appropriately. """ if msg["type"] == "result": future = self._result_futures.get(msg["messageId"]) if future is None or future.cancelled(): # no listener for this result or the future was canceled return if self._record_messages and msg["messageId"] not in LISTEN_MESSAGE_IDS: self._recorded_commands[msg["messageId"]].update( { "result_ts": datetime.utcnow().isoformat(), "result_msg": deepcopy(msg), } ) if msg["success"]: future.set_result(msg["result"]) return if msg["errorCode"] != "zwave_error": err = FailedCommand(msg["messageId"], msg["errorCode"], msg["message"]) else: err = FailedZWaveCommand( msg["messageId"], msg["zwaveErrorCode"], msg["zwaveErrorMessage"] ) future.set_exception(err) return if msg["type"] != "event": # Can't handle LOGGER.debug( "Received message with unknown type '%s': %s", msg["type"], msg, ) return if self._record_messages and not ( self.server_logging_enabled and msg["event"]["event"] == "logging" ): self._recorded_events.append( { "record_type": "event", "ts": datetime.utcnow().isoformat(), "type": msg["event"]["event"], "event_msg": deepcopy(msg), } ) event = Event(type=msg["event"]["event"], data=msg["event"]) self.driver.receive_event(event) # type: ignore async def _send_json_message(self, message: dict[str, Any]) -> None: """Send a message. Raises NotConnected if client not connected. """ if not self.connected: raise NotConnected if LOGGER.isEnabledFor(logging.DEBUG): LOGGER.debug("Publishing message:\n%s\n", pprint.pformat(message)) assert self._client assert "messageId" in message if self._record_messages and message["messageId"] not in LISTEN_MESSAGE_IDS: # We don't need to deepcopy command_msg because it is always released by # the caller after the command is sent. self._recorded_commands[message["messageId"]].update( { "record_type": "command", "ts": datetime.utcnow().isoformat(), "command": message["command"], "command_msg": message, } ) await self._client.send_json(message) async def __aenter__(self) -> Client: """Connect to the websocket.""" await self.connect() return self async def __aexit__( self, exc_type: Exception, exc_value: str, traceback: TracebackType ) -> None: """Disconnect from the websocket.""" await self.disconnect() zwave-js-server-python-0.63.0/zwave_js_server/const/000077500000000000000000000000001500374325600225425ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/const/__init__.py000066400000000000000000000336701500374325600246640ustar00rootroot00000000000000"""Constants for the Z-Wave JS python library.""" from __future__ import annotations from dataclasses import dataclass, field from enum import Enum, IntEnum import logging from typing import TypedDict PACKAGE_NAME = "zwave-js-server-python" __version__ = "0.63.0" # minimal server schema version we can handle MIN_SERVER_SCHEMA_VERSION = 39 # max server schema version we can handle (and our code is compatible with) MAX_SERVER_SCHEMA_VERSION = 40 VALUE_UNKNOWN = "unknown" NOT_INTERVIEWED = "None" INTERVIEW_FAILED = "Failed" CURRENT_STATE_PROPERTY = "currentState" TARGET_STATE_PROPERTY = "targetState" CURRENT_VALUE_PROPERTY = "currentValue" TARGET_VALUE_PROPERTY = "targetValue" DURATION_PROPERTY = "duration" TRANSITION_DURATION_OPTION = "transitionDuration" VOLUME_OPTION = "volume" class CommandStatus(str, Enum): """Status of a command sent to zwave-js-server.""" ACCEPTED = "accepted" QUEUED = "queued" # Multiple inheritance so that LogLevel will JSON serialize properly # Reference: https://stackoverflow.com/a/51976841 class LogLevel(str, Enum): """Enum for log levels used by node-zwave-js.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/log/shared.ts#L12 # https://github.com/winstonjs/triple-beam/blame/master/config/npm.js#L14 ERROR = "error" WARN = "warn" INFO = "info" HTTP = "http" VERBOSE = "verbose" DEBUG = "debug" SILLY = "silly" LOG_LEVEL_MAP: dict[LogLevel, int] = { LogLevel.ERROR: logging.ERROR, LogLevel.WARN: logging.WARN, LogLevel.INFO: logging.INFO, LogLevel.HTTP: logging.INFO, LogLevel.VERBOSE: logging.DEBUG, LogLevel.DEBUG: logging.DEBUG, LogLevel.SILLY: logging.DEBUG, } class CommandClass(IntEnum): """Enum with all known CommandClasses.""" SENSOR_ALARM = 156 SILENCE_ALARM = 157 SWITCH_ALL = 39 ANTITHEFT = 93 ANTITHEFT_UNLOCK = 126 APPLICATION_CAPABILITY = 87 APPLICATION_STATUS = 34 ASSOCIATION = 133 ASSOCIATION_COMMAND_CONFIGURATION = 155 ASSOCIATION_GRP_INFO = 89 AUTHENTICATION = 161 AUTHENTICATION_MEDIA_WRITE = 162 BARRIER_OPERATOR = 102 BASIC = 32 BASIC_TARIFF_INFO = 54 BASIC_WINDOW_COVERING = 80 BATTERY = 128 SENSOR_BINARY = 48 SWITCH_BINARY = 37 SWITCH_TOGGLE_BINARY = 40 CLIMATE_CONTROL_SCHEDULE = 70 CENTRAL_SCENE = 91 CLOCK = 129 SWITCH_COLOR = 51 CONFIGURATION = 112 CONTROLLER_REPLICATION = 33 CRC_16_ENCAP = 86 DCP_CONFIG = 58 DCP_MONITOR = 59 DEVICE_RESET_LOCALLY = 90 DOOR_LOCK = 98 DOOR_LOCK_LOGGING = 76 ENERGY_PRODUCTION = 144 ENTRY_CONTROL = 111 FIRMWARE_UPDATE_MD = 122 GENERIC_SCHEDULE = 163 GEOGRAPHIC_LOCATION = 140 GROUPING_NAME = 123 HAIL = 130 HRV_STATUS = 55 HRV_CONTROL = 57 HUMIDITY_CONTROL_MODE = 109 HUMIDITY_CONTROL_OPERATING_STATE = 110 HUMIDITY_CONTROL_SETPOINT = 100 INCLUSION_CONTROLLER = 116 INDICATOR = 135 IP_ASSOCIATION = 92 IP_CONFIGURATION = 154 IR_REPEATER = 160 IRRIGATION = 107 LANGUAGE = 137 LOCK = 118 MAILBOX = 105 MANUFACTURER_PROPRIETARY = 145 MANUFACTURER_SPECIFIC = 114 MARK = 239 METER = 50 METER_TBL_CONFIG = 60 METER_TBL_MONITOR = 61 METER_TBL_PUSH = 62 MTP_WINDOW_COVERING = 81 MULTI_CHANNEL = 96 MULTI_CHANNEL_ASSOCIATION = 142 MULTI_CMD = 143 SENSOR_MULTILEVEL = 49 SWITCH_MULTILEVEL = 38 SWITCH_TOGGLE_MULTILEVEL = 41 NETWORK_MANAGEMENT_BASIC = 77 NETWORK_MANAGEMENT_INCLUSION = 52 NETWORK_MANAGEMENT_INSTALLATION_MAINTENANCE = 103 NETWORK_MANAGEMENT_PRIMARY = 84 NETWORK_MANAGEMENT_PROXY = 82 NO_OPERATION = 0 NODE_NAMING = 119 NODE_PROVISIONING = 120 NOTIFICATION = 113 POWERLEVEL = 115 PREPAYMENT = 63 PREPAYMENT_ENCAPSULATION = 65 PROPRIETARY = 136 PROTECTION = 117 METER_PULSE = 53 RATE_TBL_CONFIG = 72 RATE_TBL_MONITOR = 73 REMOTE_ASSOCIATION_ACTIVATE = 124 REMOTE_ASSOCIATION = 125 SCENE_ACTIVATION = 43 SCENE_ACTUATOR_CONF = 44 SCENE_CONTROLLER_CONF = 45 SCHEDULE = 83 SCHEDULE_ENTRY_LOCK = 78 SCREEN_ATTRIBUTES = 147 SCREEN_MD = 146 SECURITY = 152 SECURITY_2 = 159 SECURITY_SCHEME0_MARK = 61696 SENSOR_CONFIGURATION = 158 SIMPLE_AV_CONTROL = 148 SOUND_SWITCH = 121 SUPERVISION = 108 TARIFF_CONFIG = 74 TARIFF_TBL_MONITOR = 75 THERMOSTAT_FAN_MODE = 68 THERMOSTAT_FAN_STATE = 69 THERMOSTAT_MODE = 64 THERMOSTAT_OPERATING_STATE = 66 THERMOSTAT_SETBACK = 71 THERMOSTAT_SETPOINT = 67 TIME = 138 TIME_PARAMETERS = 139 TRANSPORT_SERVICE = 85 USER_CODE = 99 VERSION = 134 WAKE_UP = 132 WINDOW_COVERING = 106 ZIP = 35 ZIP_6LOWPAN = 79 ZIP_GATEWAY = 95 ZIP_NAMING = 104 ZIP_ND = 88 ZIP_PORTAL = 97 ZWAVEPLUS_INFO = 94 class ProtocolVersion(IntEnum): """Protocol version.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/Types.ts#L149 UNKNOWN = 0 VERSION_2_0 = 1 VERSION_4_2X_OR_5_0X = 2 VERSION_4_5X_OR_6_0X = 3 class NodeStatus(IntEnum): """Enum with all Node status values.""" # https://zwave-js.github.io/node-zwave-js/#/api/node?id=status UNKNOWN = 0 ASLEEP = 1 AWAKE = 2 DEAD = 3 ALIVE = 4 class ConfigurationValueType(str, Enum): """Enum for configuration value types.""" BOOLEAN = "boolean" ENUMERATED = "enumerated" MANUAL_ENTRY = "manual_entry" RANGE = "range" UNDEFINED = "undefined" class NodeType(IntEnum): """Enum with all Node types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/capabilities/NodeInfo.ts#L151-L156 CONTROLLER = 0 END_NODE = 1 # Exclusion enums class ExclusionStrategy(IntEnum): """Enum with all exclusion strategies.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L49-L56 EXCLUDE_ONLY = 0 DISABLE_PROVISIONING_ENTRY = 1 UNPROVISION = 2 # Inclusion enums class InclusionStrategy(IntEnum): """Enum for all known inclusion strategies.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L9-L46 DEFAULT = 0 SMART_START = 1 INSECURE = 2 SECURITY_S0 = 3 SECURITY_S2 = 4 class SecurityClass(IntEnum): """Enum for all known security classes.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/security/SecurityClass.ts#L3-L17 NONE = -1 S2_UNAUTHENTICATED = 0 S2_AUTHENTICATED = 1 S2_ACCESS_CONTROL = 2 S0_LEGACY = 7 class QRCodeVersion(IntEnum): """Enum for all known QR Code versions.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/security/QR.ts#L43-L46 S2 = 0 SMART_START = 1 class Protocols(IntEnum): """Enum for all known protocols.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/capabilities/Protocols.ts#L1-L4 ZWAVE = 0 ZWAVE_LONG_RANGE = 1 # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/security/QR.ts#L41 MINIMUM_QR_STRING_LENGTH = 52 class ZwaveFeature(IntEnum): """Enum for all known Zwave features.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Features.ts#L4 SMART_START = 0 class PowerLevel(IntEnum): """Enum for all known power levels.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/PowerlevelCC.ts#L38 NORMAL_POWER = 0 DBM_MINUS_1 = 1 DBM_MINUS_2 = 2 DBM_MINUS_3 = 3 DBM_MINUS_4 = 4 DBM_MINUS_5 = 5 DBM_MINUS_6 = 6 DBM_MINUS_7 = 7 DBM_MINUS_8 = 8 DBM_MINUS_9 = 9 class InclusionState(IntEnum): """Enum for all known inclusion states.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L154 IDLE = 0 INCLUDING = 1 EXCLUDING = 2 BUSY = 3 SMART_START = 4 class RFRegion(IntEnum): """Enum for all known RF regions.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/definitions/RFRegion.ts#L1 EUROPE = 0 USA = 1 AUSTRALIA_AND_NEW_ZEALAND = 2 HONG_KONG = 3 INDIA = 5 ISRAEL = 6 RUSSIA = 7 CHINA = 8 USA_LONG_RANGE = 9 EUROPE_LONG_RANGE = 11 JAPAN = 32 KOREA = 33 UNKNOWN = 254 DEFAULT_EU = 255 class ProtocolDataRate(IntEnum): """Enum for all known protocol data rates.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/capabilities/Protocols.ts#L6 ZWAVE_9K6 = 1 ZWAVE_40K = 2 ZWAVE_100K = 3 LONG_RANGE_100K = 4 class RssiError(IntEnum): """Enum for all known RSSI errors.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/SendDataShared.ts#L79 NOT_AVAILABLE = 127 RECEIVER_SATURATED = 126 NO_SIGNAL_DETECTED = 125 class ProvisioningEntryStatus(IntEnum): """Enum for all known provisioning entry statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L136 ACTIVE = 0 INACTIVE = 1 class SecurityBootstrapFailure(IntEnum): """Enum with all security bootstrap failure reasons.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L16 USER_CANCELED = 0 NO_KEYS_CONFIGURED = 1 S2_NO_USER_CALLBACKS = 2 TIMEOUT = 3 PARAMETER_MISMATCH = 4 NODE_CANCELED = 5 S2_INCORRECT_PIN = 6 S2_WRONG_SECURITY_LEVEL = 7 UNKNOWN = 8 class SetValueStatus(IntEnum): """Enum for all known setValue statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/API.ts#L83 # The device reports no support for this command NO_DEVICE_SUPPORT = 0 # The device has accepted the command and is working on it WORKING = 1 # The device has rejected the command FAIL = 2 # The endpoint specified in the value ID does not exist ENDPOINT_NOT_FOUND = 3 # The given CC or its API is not implemented (yet) or it has no `setValue` # implementation NOT_IMPLEMENTED = 4 # The value to set (or a related value) is invalid INVALID_VALUE = 5 # The command was sent successfully, but it is unknown whether it was executed SUCCESS_UNSUPERVISED = 254 # The device has executed the command successfully SUCCESS = 255 SET_VALUE_SUCCESS = ( SetValueStatus.SUCCESS, SetValueStatus.SUCCESS_UNSUPERVISED, SetValueStatus.WORKING, ) class RemoveNodeReason(IntEnum): """Enum for all known reasons why a node was removed.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L266 # The node was excluded by the user or an inclusion controller EXCLUDED = 0 # The node was excluded by an inclusion controller PROXY_EXCLUDED = 1 # The node was removed using the "remove failed node" feature REMOVE_FAILED = 2 # The node was replaced using the "replace failed node" feature REPLACED = 3 # The node was replaced by an inclusion controller PROXY_REPLACED = 4 # The node was reset locally and was auto-removed RESET = 5 # SmartStart inclusion failed, and the node was auto-removed as a result. SMART_START_FAILED = 6 class Weekday(IntEnum): """Enum for all known weekdays.""" UNKNOWN = 0 MONDAY = 1 TUESDAY = 2 WEDNESDAY = 3 THURSDAY = 4 FRIDAY = 5 SATURDAY = 6 SUNDAY = 7 class DateAndTimeDataType(TypedDict, total=False): """Represent a date and time data type.""" hour: int minute: int weekday: int second: int year: int month: int day: int dstOffset: int standardOffset: int @dataclass class DateAndTime: """Represent a date and time.""" data: DateAndTimeDataType = field(repr=False) hour: int | None = field(init=False) minute: int | None = field(init=False) weekday: Weekday | None = field(default=None, init=False) second: int | None = field(init=False) year: int | None = field(init=False) month: int | None = field(init=False) day: int | None = field(init=False) dst_offset: int | None = field(init=False) standard_offset: int | None = field(init=False) def __post_init__(self) -> None: """Post initialization.""" self.hour = self.data.get("hour") self.minute = self.data.get("minute") if weekday := self.data.get("weekday"): self.weekday = Weekday(weekday) self.second = self.data.get("second") self.year = self.data.get("year") self.month = self.data.get("month") self.day = self.data.get("day") self.dst_offset = self.data.get("dstOffset") self.standard_offset = self.data.get("standardOffset") class ControllerStatus(IntEnum): """Enum for all known controller statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/consts/ControllerStatus.TS # The controller is ready to accept commands and transmit READY = 0 # The controller is unresponsive UNRESPONSIVE = 1 # The controller is unable to transmit JAMMED = 2 class SupervisionStatus(IntEnum): """Enum for all known supervision statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/cc_api_options/packages/core/src/consts/Transmission.ts#L304 NO_SUPPORT = 0 WORKING = 1 FAIL = 2 SUCCESS = 255 class AssociationCheckResult(IntEnum): """Enum for all known association check results.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L47 OK = 1 FORBIDDEN_DESTINATION_IS_LONG_RANGE = 2 FORBIDDEN_SOURCE_IS_LONG_RANGE = 3 FORBIDDEN_SELF_ASSOCIATION = 4 FORBIDDEN_SECURITY_CLASS_MISMATCH = 5 FORBIDDEN_DESTINATION_SECURITY_CLASS_NOT_GRANTED = 6 FORBIDDEN_NO_SUPPORTED_CCS = 7 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/000077500000000000000000000000001500374325600253455ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/__init__.py000066400000000000000000000000451500374325600274550ustar00rootroot00000000000000"""Constants for Command Classes.""" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/barrier_operator.py000066400000000000000000000014641500374325600312650ustar00rootroot00000000000000"""Constants for the Barrier Operator CC.""" from __future__ import annotations from enum import IntEnum SIGNALING_STATE_PROPERTY = "signalingState" class BarrierEventSignalingSubsystemState(IntEnum): """Enum with all (known/used) Z-Wave Barrier Event Signaling Subsystem States.""" # https://github.com/zwave-js/node-zwave-js/blob/15e1b59f627bfad8bfae114bd774a14089c76683/packages/zwave-js/src/lib/commandclass/BarrierOperatorCC.ts#L46-L49 OFF = 0 ON = 255 class BarrierState(IntEnum): """Enum with all (known/used) Z-Wave Barrier States.""" # https://github.com/zwave-js/node-zwave-js/blob/15e1b59f627bfad8bfae114bd774a14089c76683/packages/zwave-js/src/lib/commandclass/BarrierOperatorCC.ts#L107-L113 CLOSED = 0 CLOSING = 252 STOPPED = 253 OPENING = 254 OPEN = 255 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/basic.py000066400000000000000000000001401500374325600267730ustar00rootroot00000000000000"""Constants for the Basic CC.""" from __future__ import annotations EVENT_PROPERTY = "event" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/central_scene.py000066400000000000000000000001501500374325600305200ustar00rootroot00000000000000"""Constants for the Central Scene CC.""" from __future__ import annotations SCENE_PROPERTY = "scene" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/color_switch.py000066400000000000000000000016731500374325600304250ustar00rootroot00000000000000"""Constants for the Color Switch CC.""" from __future__ import annotations from enum import IntEnum class ColorComponent(IntEnum): """Enum with all (known/used) Color Switch CC colors.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ColorSwitchCC.ts#L62 WARM_WHITE = 0 COLD_WHITE = 1 RED = 2 GREEN = 3 BLUE = 4 AMBER = 5 CYAN = 6 PURPLE = 7 INDEX = 8 # Keys for the Color Switch CC combined colors value # https://github.com/zwave-js/node-zwave-js/pull/1782 COLOR_SWITCH_COMBINED_RED = "red" COLOR_SWITCH_COMBINED_GREEN = "green" COLOR_SWITCH_COMBINED_BLUE = "blue" COLOR_SWITCH_COMBINED_AMBER = "amber" COLOR_SWITCH_COMBINED_CYAN = "cyan" COLOR_SWITCH_COMBINED_PURPLE = "purple" COLOR_SWITCH_COMBINED_WARM_WHITE = "warmWhite" COLOR_SWITCH_COMBINED_COLD_WHITE = "coldWhite" CURRENT_COLOR_PROPERTY = "currentColor" TARGET_COLOR_PROPERTY = "targetColor" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/energy_production.py000066400000000000000000000027351500374325600314650ustar00rootroot00000000000000"""Constants for the Energy Production CC.""" from __future__ import annotations from enum import IntEnum class EnergyProductionParameter(IntEnum): """Energy Production CC parameter.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L508 POWER = 0 TOTAL_PRODUCTION = 1 TODAYS_PRODUCTION = 2 TOTAL_TIME = 3 CC_SPECIFIC_PARAMETER = "parameter" CC_SPECIFIC_SCALE = "scale" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L520 class EnergyProductionScaleType(IntEnum): """Common base class for Energy Production scale enums.""" class PowerScale(EnergyProductionScaleType): """Enum with all known Energy Production power scale values.""" WATTS = 0 class TotalProductionScale(EnergyProductionScaleType): """Enum with all known Energy Production total production scale values.""" WATT_HOURS = 0 TodaysProductionScale = TotalProductionScale class TotalTimeScale(EnergyProductionScaleType): """Enum with all known Energy Production total time scale values.""" SECONDS = 0 HOURS = 1 ENERGY_PRODUCTION_PARAMETER_TO_SCALE_ENUM_MAP: dict[ EnergyProductionParameter, type[EnergyProductionScaleType] ] = { EnergyProductionParameter.POWER: PowerScale, EnergyProductionParameter.TOTAL_PRODUCTION: TotalProductionScale, EnergyProductionParameter.TODAYS_PRODUCTION: TodaysProductionScale, EnergyProductionParameter.TOTAL_TIME: TotalTimeScale, } zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/entry_control.py000066400000000000000000000017141500374325600306230ustar00rootroot00000000000000"""Constants for the Entry Control CC.""" from __future__ import annotations from enum import IntEnum class EntryControlEventType(IntEnum): """Entry control event types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/EntryControlCC.ts#L54 CACHING = 0 CACHED_KEYS = 1 ENTER = 2 DISARM_ALL = 3 ARM_ALL = 4 ARM_AWAY = 5 ARM_HOME = 6 EXIT_DELAY = 7 ARM1 = 8 ARM2 = 9 ARM3 = 10 ARM4 = 11 ARM5 = 12 ARM6 = 13 RFID = 14 BELL = 15 FIRE = 16 POLICE = 17 ALERT_PANIC = 18 ALERT_MEDICAL = 19 GATE_OPEN = 20 GATE_CLOSE = 21 LOCK = 22 UNLOCK = 23 TEST = 24 CANCEL = 25 class EntryControlDataType(IntEnum): """Entry control data types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/EntryControlCC.ts#L83 NONE = 0 RAW = 1 ASCII = 2 MD5 = 3 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/humidity_control.py000066400000000000000000000035461500374325600313230ustar00rootroot00000000000000""" Constants for the Humidity Control CCs. Includes Humidity Control Mode, Humidity Control Operating State, and Humidity Control Setpoint CCs. """ from __future__ import annotations from enum import IntEnum HUMIDITY_CONTROL_MODE_PROPERTY = "mode" HUMIDITY_CONTROL_OPERATING_STATE_PROPERTY = "state" HUMIDITY_CONTROL_SETPOINT_PROPERTY = "setpoint" HUMIDITY_CONTROL_SETPOINT_SCALE_PROPERTY = "setpointScale" HUMIDITY_CONTROL_SUPPORTED_SETPOINT_TYPES_PROPERTY = "supportedSetpointTypes" class HumidityControlMode(IntEnum): """Enum with all (known/used) Z-Wave HumidityControlModes.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/HumidityControlModeCC.ts OFF = 0 HUMIDIFY = 1 DEHUMIDIFY = 2 AUTO = 3 class HumidityControlOperatingState(IntEnum): """Enum with all (known/used) Z-Wave Humidity Control OperatingStates.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/HumidityControlOperatingStateCC.ts IDLE = 0 HUMIDIFYING = 1 DEHUMIDIFYING = 2 class HumidityControlSetpointType(IntEnum): """ Enum with all (known/used) Z-Wave Humidity Control Setpoint Types. Returns tuple of (property_key, property_key_name). """ # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/HumidityControlSetpointCC.ts NA = 0 HUMIDIFIER = 1 DEHUMIDIFIER = 2 AUTO = 3 HUMIDITY_CONTROL_MODE_SETPOINT_MAP: dict[int, list[HumidityControlSetpointType]] = { HumidityControlMode.OFF: [], HumidityControlMode.HUMIDIFY: [HumidityControlSetpointType.HUMIDIFIER], HumidityControlMode.DEHUMIDIFY: [HumidityControlSetpointType.DEHUMIDIFIER], HumidityControlMode.AUTO: [ HumidityControlSetpointType.HUMIDIFIER, HumidityControlSetpointType.DEHUMIDIFIER, ], } zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/lock.py000066400000000000000000000151271500374325600266550ustar00rootroot00000000000000""" Constants for lock related CCs. Includes Door Lock and Lock CCs. """ from __future__ import annotations from dataclasses import dataclass, field from enum import Enum, IntEnum from typing import TypedDict from .. import CommandClass class DoorLockMode(IntEnum): """Enum with all (known/used) Z-Wave lock states for CommandClass.DOOR_LOCK.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/DoorLockCC.ts#L56-L65 UNSECURED = 0 UNSECURED_WITH_TIMEOUT = 1 INSIDE_UNSECURED = 2 INSIDE_UNSECURED_WITH_TIMEOUT = 3 OUTSIDE_UNSECURED = 4 OUTSIDE_UNSECURED_WITH_TIMEOUT = 5 UNKNOWN = 254 SECURED = 255 class OperationType(IntEnum): """Enum with all (known/used) Z-Wave lock operation types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L496 CONSTANT = 1 TIMED = 2 DOOR_LOCK_CC_UNSECURED_MAP = { OperationType.CONSTANT: { DoorLockMode.UNSECURED, DoorLockMode.INSIDE_UNSECURED, DoorLockMode.OUTSIDE_UNSECURED, }, OperationType.TIMED: { DoorLockMode.UNSECURED_WITH_TIMEOUT, DoorLockMode.INSIDE_UNSECURED_WITH_TIMEOUT, DoorLockMode.OUTSIDE_UNSECURED_WITH_TIMEOUT, }, } class LatchStatus(str, Enum): """Enum with all (known/used) Z-Wave latch statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/DoorLockCC.ts#L854 OPEN = "open" CLOSED = "closed" class BoltStatus(str, Enum): """Enum with all (known/used) Z-Wave bolt statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/DoorLockCC.ts#L854 LOCKED = "locked" UNLOCKED = "unlocked" class DoorStatus(str, Enum): """Enum with all (known/used) Z-Wave door statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/DoorLockCC.ts#L854 OPEN = "open" CLOSED = "closed" class CodeSlotStatus(IntEnum): """Enum with all (known/used) Z-Wave code slot statuses.""" AVAILABLE = 0 ENABLED = 1 DISABLED = 2 # Depending on the Command Class being used by the lock, the lock state is # different so we need a map to track it LOCK_CMD_CLASS_TO_LOCKED_STATE_MAP = { CommandClass.DOOR_LOCK: DoorLockMode.SECURED, CommandClass.LOCK: True, } # Door Lock CC value constants BOLT_STATUS_PROPERTY = "boltStatus" CURRENT_AUTO_RELOCK_TIME_PROPERTY = "autoRelockTime" CURRENT_BLOCK_TO_BLOCK_PROPERTY = "blockToBlock" CURRENT_HOLD_AND_RELEASE_TIME_PROPERTY = "holdAndReleaseTime" CURRENT_INSIDE_HANDLES_CAN_OPEN_DOOR_PROPERTY = "insideHandlesCanOpenDoor" CURRENT_LOCK_TIMEOUT_PROPERTY = "lockTimeout" CURRENT_MODE_PROPERTY = "currentMode" CURRENT_OPERATION_TYPE_PROPERTY = "operationType" CURRENT_OUTSIDE_HANDLES_CAN_OPEN_DOOR_PROPERTY = "outsideHandlesCanOpenDoor" CURRENT_TWIST_ASSIST_PROPERTY = "twistAssist" DOOR_STATUS_PROPERTY = "doorStatus" LATCH_STATUS_PROPERTY = "latchStatus" TARGET_MODE_PROPERTY = "targetMode" # Door Lock CC configuration constants TARGET_AUTO_RELOCK_TIME_PROPERTY = CURRENT_AUTO_RELOCK_TIME_PROPERTY TARGET_BLOCK_TO_BLOCK_PROPERTY = CURRENT_BLOCK_TO_BLOCK_PROPERTY TARGET_HOLD_AND_RELEASE_TIME_PROPERTY = CURRENT_HOLD_AND_RELEASE_TIME_PROPERTY TARGET_INSIDE_HANDLES_CAN_OPEN_DOOR_PROPERTY = "insideHandlesCanOpenDoorConfiguration" TARGET_LOCK_TIMEOUT_PROPERTY = "lockTimeoutConfiguration" TARGET_OPERATION_TYPE_PROPERTY = CURRENT_OPERATION_TYPE_PROPERTY TARGET_OUTSIDE_HANDLES_CAN_OPEN_DOOR_PROPERTY = "outsideHandlesCanOpenDoorConfiguration" TARGET_TWIST_ASSIST_PROPERTY = CURRENT_TWIST_ASSIST_PROPERTY # Lock CC constants LOCKED_PROPERTY = "locked" # User Code CC constants LOCK_USERCODE_PROPERTY = "userCode" LOCK_USERCODE_ID_PROPERTY = "userId" LOCK_USERCODE_STATUS_PROPERTY = "userIdStatus" ATTR_CODE_SLOT = "code_slot" ATTR_IN_USE = "in_use" ATTR_NAME = "name" ATTR_USERCODE = "usercode" # Depending on the Command Class being used by the lock, the locked state property # is different so we need a map to track it LOCK_CMD_CLASS_TO_PROPERTY_MAP = { CommandClass.DOOR_LOCK: TARGET_MODE_PROPERTY, CommandClass.LOCK: LOCKED_PROPERTY, } class DoorLockCCConfigurationSetOptionsDataType(TypedDict, total=False): """Door Lock CC Configuration Set command options.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/DoorLockCC.ts#L1156 operationType: int # required lockTimeoutConfiguration: int outsideHandlesCanOpenDoorConfiguration: list[bool] # required when from device insideHandlesCanOpenDoorConfiguration: list[bool] # required when from device autoRelockTime: int holdAndReleaseTime: int twistAssist: bool blockToBlock: bool DEFAULT_HANDLE_CONFIGURATION = [True, True, True, True] @dataclass class DoorLockCCConfigurationSetOptions: """Door Lock CC Configuration Set command options.""" operation_type: OperationType lock_timeout_configuration: int | None = None outside_handles_can_open_door_configuration: list[bool] = field( default_factory=list ) inside_handles_can_open_door_configuration: list[bool] = field(default_factory=list) auto_relock_time: int | None = None hold_and_release_time: int | None = None twist_assist: bool | None = None block_to_block: bool | None = None def __post_init__(self) -> None: """Post initialization.""" for attr_name in ( "inside_handles_can_open_door_configuration", "outside_handles_can_open_door_configuration", ): if not getattr(self, attr_name): setattr(self, attr_name, DEFAULT_HANDLE_CONFIGURATION) def to_dict(self) -> DoorLockCCConfigurationSetOptionsDataType: """Convert command options to dict.""" data = DoorLockCCConfigurationSetOptionsDataType( operationType=self.operation_type, outsideHandlesCanOpenDoorConfiguration=( self.outside_handles_can_open_door_configuration ), insideHandlesCanOpenDoorConfiguration=( self.inside_handles_can_open_door_configuration ), ) for prop_name, val in ( (TARGET_LOCK_TIMEOUT_PROPERTY, self.lock_timeout_configuration), (TARGET_AUTO_RELOCK_TIME_PROPERTY, self.auto_relock_time), (TARGET_HOLD_AND_RELEASE_TIME_PROPERTY, self.hold_and_release_time), (TARGET_TWIST_ASSIST_PROPERTY, self.twist_assist), (TARGET_BLOCK_TO_BLOCK_PROPERTY, self.block_to_block), ): if val is not None: data[prop_name] = val # type: ignore[literal-required] return data zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/meter.py000066400000000000000000000077461500374325600270510ustar00rootroot00000000000000"""Constants for Meter CC.""" from __future__ import annotations from enum import IntEnum VALUE_PROPERTY = "value" RESET_PROPERTY = "reset" CC_SPECIFIC_SCALE = "scale" CC_SPECIFIC_METER_TYPE = "meterType" CC_SPECIFIC_RATE_TYPE = "rateType" RESET_METER_CC_API = "reset" # optional attributes when calling the Meter CC reset API. # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/MeterCC.ts RESET_METER_OPTION_TARGET_VALUE = "targetValue" RESET_METER_OPTION_TYPE = "type" RESET_METER_OPTION_SCALE = "scale" RESET_METER_OPTION_RATE_TYPE = "rateType" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/config/config/meters.json class MeterType(IntEnum): """Enum with all known meter types.""" ELECTRIC = 1 GAS = 2 WATER = 3 HEATING = 4 COOLING = 5 class RateType(IntEnum): """Enum with all known rate types.""" # https://github.com/raman325/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L996 UNSPECIFIED = 0 CONSUMED = 1 PRODUCED = 2 class MeterScaleType(IntEnum): """Common base class for meter scale enums.""" class ElectricScale(MeterScaleType): """Enum with all known electric meter scale values.""" KILOWATT_HOUR = 0 KILOVOLT_AMPERE_HOUR = 1 WATT = 2 PULSE_COUNT = 3 VOLT = 4 AMPERE = 5 POWER_FACTOR = 6 KILOVOLT_AMPERE_REACTIVE = 7 KILOVOLT_AMPERE_REACTIVE_HOUR = 8 class GasScale(MeterScaleType): """Enum with all known gas meter scale values.""" CUBIC_METER = 0 CUBIC_FEET = 1 PULSE_COUNT = 3 class WaterScale(MeterScaleType): """Enum with all known water meter scale values.""" CUBIC_METER = 0 CUBIC_FEET = 1 US_GALLON = 2 PULSE_COUNT = 3 class HeatingScale(MeterScaleType): """Enum with all known heating meter scale values.""" KILOWATT_HOUR = 0 CoolingScale = HeatingScale METER_TYPE_TO_SCALE_ENUM_MAP: dict[MeterType, type[MeterScaleType]] = { MeterType.ELECTRIC: ElectricScale, MeterType.GAS: GasScale, MeterType.WATER: WaterScale, MeterType.HEATING: HeatingScale, MeterType.COOLING: CoolingScale, } ENERGY_TOTAL_INCREASING_METER_TYPES: list[MeterScaleType] = [ ElectricScale.KILOWATT_HOUR, ElectricScale.KILOVOLT_AMPERE_HOUR, ElectricScale.KILOVOLT_AMPERE_REACTIVE_HOUR, HeatingScale.KILOWATT_HOUR, CoolingScale.KILOWATT_HOUR, ElectricScale.PULSE_COUNT, ] POWER_METER_TYPES: list[MeterScaleType] = [ ElectricScale.WATT, ElectricScale.KILOVOLT_AMPERE_REACTIVE, ] POWER_FACTOR_METER_TYPES: list[MeterScaleType] = [ElectricScale.POWER_FACTOR] VOLTAGE_METER_TYPES: list[MeterScaleType] = [ElectricScale.VOLT] CURRENT_METER_TYPES: list[MeterScaleType] = [ElectricScale.AMPERE] GAS_METER_TYPES: list[MeterScaleType] = [ GasScale.CUBIC_METER, GasScale.CUBIC_FEET, GasScale.PULSE_COUNT, ] WATER_METER_TYPES: list[MeterScaleType] = [ WaterScale.CUBIC_METER, WaterScale.CUBIC_FEET, WaterScale.US_GALLON, WaterScale.PULSE_COUNT, ] UNIT_KILOWATT_HOUR: list[MeterScaleType] = [ ElectricScale.KILOWATT_HOUR, HeatingScale.KILOWATT_HOUR, CoolingScale.KILOWATT_HOUR, ] UNIT_KILOVOLT_AMPERE_HOUR: list[MeterScaleType] = [ElectricScale.KILOVOLT_AMPERE_HOUR] UNIT_WATT: list[MeterScaleType] = [ElectricScale.WATT] UNIT_PULSE_COUNT: list[MeterScaleType] = [ ElectricScale.PULSE_COUNT, GasScale.PULSE_COUNT, WaterScale.PULSE_COUNT, ] UNIT_VOLT: list[MeterScaleType] = [ElectricScale.VOLT] UNIT_AMPERE: list[MeterScaleType] = [ElectricScale.AMPERE] UNIT_POWER_FACTOR: list[MeterScaleType] = [ElectricScale.POWER_FACTOR] UNIT_KILOVOLT_AMPERE_REACTIVE: list[MeterScaleType] = [ ElectricScale.KILOVOLT_AMPERE_REACTIVE ] UNIT_KILOVOLT_AMPERE_REACTIVE_HOUR: list[MeterScaleType] = [ ElectricScale.KILOVOLT_AMPERE_REACTIVE_HOUR ] UNIT_CUBIC_METER: list[MeterScaleType] = [GasScale.CUBIC_METER, WaterScale.CUBIC_METER] UNIT_CUBIC_FEET: list[MeterScaleType] = [GasScale.CUBIC_FEET, WaterScale.CUBIC_FEET] UNIT_US_GALLON: list[MeterScaleType] = [WaterScale.US_GALLON] zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/multilevel_sensor.py000066400000000000000000001106531500374325600315000ustar00rootroot00000000000000"""Constants for the Multilevel Sensor CC.""" # ----------------------------------------------------------------------------------- # # **BEGINNING OF AUTOGENERATED CONTENT** (TO ADD ADDITIONAL MANUAL CONTENT, LOOK FOR # # THE "END OF AUTOGENERATED CONTENT" COMMENT BLOCK AND ADD YOUR CODE BELOW IT) # # ----------------------------------------------------------------------------------- # from __future__ import annotations from enum import IntEnum CC_SPECIFIC_SCALE = "scale" CC_SPECIFIC_SENSOR_TYPE = "sensorType" ACCELERATION_X_AXIS_PROPERTY = "Acceleration X-axis" ACCELERATION_Y_AXIS_PROPERTY = "Acceleration Y-axis" ACCELERATION_Z_AXIS_PROPERTY = "Acceleration Z-axis" AIR_FLOW_PROPERTY = "Air flow" AIR_TEMPERATURE_PROPERTY = "Air temperature" AMMONIA_PROPERTY = "Ammonia" ANGLE_POSITION_PROPERTY = "Angle position" APPLIED_FORCE_ON_THE_SENSOR_PROPERTY = "Applied force on the sensor" ATMOSPHERIC_PRESSURE_PROPERTY = "Atmospheric pressure" BAROMETRIC_PRESSURE_PROPERTY = "Barometric pressure" BASIS_METABOLIC_RATE_PROPERTY = "Basis metabolic rate (BMR)" BLOOD_PRESSURE_PROPERTY = "Blood pressure" BODY_MASS_INDEX_PROPERTY = "Body Mass Index (BMI)" BOILER_WATER_TEMPERATURE_PROPERTY = "Boiler water temperature" BONE_MASS_PROPERTY = "Bone mass" CARBON_DIOXIDE_LEVEL_PROPERTY = "Carbon dioxide (CO₂) level" CARBON_MONOXIDE_LEVEL_PROPERTY = "Carbon monoxide (CO) level" CONDENSER_COIL_TEMPERATURE_PROPERTY = "Condenser Coil temperature" CURRENT_PROPERTY = "Current" DEFROST_TEMPERATURE_PROPERTY = "Defrost temperature" DEW_POINT_PROPERTY = "Dew point" DIRECTION_PROPERTY = "Direction" DISCHARGE_LINE_TEMPERATURE_PROPERTY = "Discharge Line temperature" DISCHARGE_PRESSURE_PROPERTY = "Discharge Pressure" DISTANCE_PROPERTY = "Distance" DOMESTIC_HOT_WATER_TEMPERATURE_PROPERTY = "Domestic Hot Water (DHW) temperature" ELECTRICAL_CONDUCTIVITY_PROPERTY = "Electrical conductivity" ELECTRICAL_RESISTIVITY_PROPERTY = "Electrical resistivity" EVAPORATOR_COIL_TEMPERATURE_PROPERTY = "Evaporator Coil temperature" EXHAUST_TEMPERATURE_PROPERTY = "Exhaust temperature" FAT_MASS_PROPERTY = "Fat mass" FORMALDEHYDE_LEVEL_PROPERTY = "Formaldehyde (CH₂O) level" FREQUENCY_PROPERTY = "Frequency" GENERAL_PURPOSE_PROPERTY = "General purpose" HEART_RATE_PROPERTY = "Heart rate" HEART_RATE_LF_HF_RATIO_PROPERTY = "Heart Rate LF/HF ratio" HUMIDITY_PROPERTY = "Humidity" ILLUMINANCE_PROPERTY = "Illuminance" LEAD_PROPERTY = "Lead" LIQUID_LINE_TEMPERATURE_PROPERTY = "Liquid Line temperature" LOUDNESS_PROPERTY = "Loudness" METHANE_DENSITY_PROPERTY = "Methane (CH₄) density" MOISTURE_PROPERTY = "Moisture" MOTION_DIRECTION_PROPERTY = "Motion Direction" MUSCLE_MASS_PROPERTY = "Muscle mass" NITROGEN_DIOXIDE_PROPERTY = "Nitrogen dioxide" OUTSIDE_TEMPERATURE_PROPERTY = "Outside temperature" OZONE_PROPERTY = "Ozone" PARTICULATE_MATTER_1_PROPERTY = "Particulate Matter 1" PARTICULATE_MATTER_10_PROPERTY = "Particulate Matter 10" PARTICULATE_MATTER_2_5_PROPERTY = "Particulate Matter 2.5" PERSON_COUNTER_ENTERING_PROPERTY = "Person counter (entering)" PERSON_COUNTER_EXITING_PROPERTY = "Person counter (exiting)" POWER_PROPERTY = "Power" RADON_CONCENTRATION_PROPERTY = "Radon concentration" RAIN_RATE_PROPERTY = "Rain rate" RELATIVE_MODULATION_LEVEL_PROPERTY = "Relative Modulation level" RESPIRATORY_RATE_PROPERTY = "Respiratory rate" RETURN_AIR_TEMPERATURE_PROPERTY = "Return Air temperature" RF_SIGNAL_STRENGTH_PROPERTY = "RF signal strength" ROTATION_PROPERTY = "Rotation" SEISMIC_INTENSITY_PROPERTY = "Seismic Intensity" SEISMIC_MAGNITUDE_PROPERTY = "Seismic magnitude" SMOKE_DENSITY_PROPERTY = "Smoke density" SOIL_HUMIDITY_PROPERTY = "Soil humidity" SOIL_REACTIVITY_PROPERTY = "Soil reactivity" SOIL_SALINITY_PROPERTY = "Soil salinity" SOIL_TEMPERATURE_PROPERTY = "Soil temperature" SOLAR_RADIATION_PROPERTY = "Solar radiation" SUCTION_PRESSURE_PROPERTY = "Suction Pressure" SULFUR_DIOXIDE_PROPERTY = "Sulfur dioxide" SUPPLY_AIR_TEMPERATURE_PROPERTY = "Supply Air temperature" TANK_CAPACITY_PROPERTY = "Tank capacity" TARGET_TEMPERATURE_PROPERTY = "Target temperature" TIDE_LEVEL_PROPERTY = "Tide level" TIME_PROPERTY = "Time" TOTAL_BODY_WATER_PROPERTY = "Total body water (TBW)" ULTRAVIOLET_PROPERTY = "Ultraviolet" VELOCITY_PROPERTY = "Velocity" VOLATILE_ORGANIC_COMPOUND_LEVEL_PROPERTY = "Volatile Organic Compound level" VOLTAGE_PROPERTY = "Voltage" WATER_ACIDITY_PROPERTY = "Water acidity" WATER_CHLORINE_LEVEL_PROPERTY = "Water Chlorine level" WATER_FLOW_PROPERTY = "Water flow" WATER_OXIDATION_REDUCTION_POTENTIAL_PROPERTY = "Water Oxidation reduction potential" WATER_PRESSURE_PROPERTY = "Water pressure" WATER_TEMPERATURE_PROPERTY = "Water temperature" WEIGHT_PROPERTY = "Weight" class MultilevelSensorType(IntEnum): """Enum for known multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts ACCELERATION_X_AXIS = 52 ACCELERATION_Y_AXIS = 53 ACCELERATION_Z_AXIS = 54 AIR_FLOW = 18 AIR_TEMPERATURE = 1 AMMONIA = 84 ANGLE_POSITION = 21 APPLIED_FORCE_ON_THE_SENSOR = 71 ATMOSPHERIC_PRESSURE = 8 BAROMETRIC_PRESSURE = 9 BASIS_METABOLIC_RATE = 50 BLOOD_PRESSURE = 45 BODY_MASS_INDEX = 51 BOILER_WATER_TEMPERATURE = 62 BONE_MASS = 48 CARBON_DIOXIDE_LEVEL = 17 CARBON_MONOXIDE_LEVEL = 40 CONDENSER_COIL_TEMPERATURE = 74 CURRENT = 16 DEFROST_TEMPERATURE = 80 DEW_POINT = 11 DIRECTION = 7 DISCHARGE_LINE_TEMPERATURE = 77 DISCHARGE_PRESSURE = 79 DISTANCE = 20 DOMESTIC_HOT_WATER_TEMPERATURE = 63 ELECTRICAL_CONDUCTIVITY = 29 ELECTRICAL_RESISTIVITY = 28 EVAPORATOR_COIL_TEMPERATURE = 75 EXHAUST_TEMPERATURE = 65 FAT_MASS = 47 FORMALDEHYDE_LEVEL = 36 FREQUENCY = 32 GENERAL_PURPOSE = 2 HEART_RATE = 44 HEART_RATE_LF_HF_RATIO = 69 HUMIDITY = 5 ILLUMINANCE = 3 LEAD = 85 LIQUID_LINE_TEMPERATURE = 76 LOUDNESS = 30 METHANE_DENSITY = 38 MOISTURE = 31 MOTION_DIRECTION = 70 MUSCLE_MASS = 46 NITROGEN_DIOXIDE = 83 OUTSIDE_TEMPERATURE = 64 OZONE = 81 PARTICULATE_MATTER_1 = 86 PARTICULATE_MATTER_10 = 59 PARTICULATE_MATTER_2_5 = 35 PERSON_COUNTER_ENTERING = 87 PERSON_COUNTER_EXITING = 88 POWER = 4 RADON_CONCENTRATION = 37 RAIN_RATE = 12 RELATIVE_MODULATION_LEVEL = 61 RESPIRATORY_RATE = 60 RETURN_AIR_TEMPERATURE = 72 RF_SIGNAL_STRENGTH = 58 ROTATION = 22 SEISMIC_INTENSITY = 25 SEISMIC_MAGNITUDE = 26 SMOKE_DENSITY = 55 SOIL_HUMIDITY = 41 SOIL_REACTIVITY = 42 SOIL_SALINITY = 43 SOIL_TEMPERATURE = 24 SOLAR_RADIATION = 10 SUCTION_PRESSURE = 78 SULFUR_DIOXIDE = 82 SUPPLY_AIR_TEMPERATURE = 73 TANK_CAPACITY = 19 TARGET_TEMPERATURE = 34 TIDE_LEVEL = 13 TIME = 33 TOTAL_BODY_WATER = 49 ULTRAVIOLET = 27 VELOCITY = 6 VOLATILE_ORGANIC_COMPOUND_LEVEL = 39 VOLTAGE = 15 WATER_ACIDITY = 67 WATER_CHLORINE_LEVEL = 66 WATER_FLOW = 56 WATER_OXIDATION_REDUCTION_POTENTIAL = 68 WATER_PRESSURE = 57 WATER_TEMPERATURE = 23 WEIGHT = 14 class MultilevelSensorScaleType(IntEnum): """Common base class for multilevel sensor scale enums.""" class AccelerationScale(MultilevelSensorScaleType): """Enum for known scales for ACCELERATION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts METER_PER_SQUARE_SECOND = 0 class AcidityScale(MultilevelSensorScaleType): """Enum for known scales for ACIDITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts ACIDITY = 0 class AirFlowScale(MultilevelSensorScaleType): """Enum for known scales for AIR_FLOW multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts CUBIC_FEET_PER_MINUTE = 1 CUBIC_METER_PER_HOUR = 0 class AirPressureScale(MultilevelSensorScaleType): """Enum for known scales for AIR_PRESSURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts INCHES_OF_MERCURY = 1 KILOPASCAL = 0 class AnglePositionScale(MultilevelSensorScaleType): """Enum for known scales for ANGLE_POSITION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW = 1 DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW = 2 PERCENTAGE_VALUE = 0 class AppliedForceOnTheSensorScale(MultilevelSensorScaleType): """Enum for known scales for APPLIED_FORCE_ON_THE_SENSOR multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts NEWTON = 0 class BasisMetabolicRateScale(MultilevelSensorScaleType): """Enum for known scales for BASIS_METABOLIC_RATE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts JOULE = 0 class BloodPressureScale(MultilevelSensorScaleType): """Enum for known scales for BLOOD_PRESSURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts DIASTOLIC = 1 SYSTOLIC = 0 class BodyMassIndexScale(MultilevelSensorScaleType): """Enum for known scales for BODY_MASS_INDEX multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BODY_MASS_INDEX = 0 class CarbonDioxideLevelScale(MultilevelSensorScaleType): """Enum for known scales for CARBON_DIOXIDE_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts PARTS_MILLION = 0 class CarbonMonoxideLevelScale(MultilevelSensorScaleType): """Enum for known scales for CARBON_MONOXIDE_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MOLE_PER_CUBIC_METER = 0 PARTS_MILLION = 1 class CurrentScale(MultilevelSensorScaleType): """Enum for known scales for CURRENT multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts AMPERE = 0 MILLIAMPERE = 1 class DensityScale(MultilevelSensorScaleType): """Enum for known scales for DENSITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts DENSITY = 0 class DirectionScale(MultilevelSensorScaleType): """Enum for known scales for DIRECTION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts DEGREES = 0 class DistanceScale(MultilevelSensorScaleType): """Enum for known scales for DISTANCE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts CENTIMETER = 1 FEET = 2 METER = 0 class ElectricalConductivityScale(MultilevelSensorScaleType): """Enum for known scales for ELECTRICAL_CONDUCTIVITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts SIEMENS_PER_METER = 0 class ElectricalResistivityScale(MultilevelSensorScaleType): """Enum for known scales for ELECTRICAL_RESISTIVITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts OHM_METER = 0 class FormaldehydeLevelScale(MultilevelSensorScaleType): """Enum for known scales for FORMALDEHYDE_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MOLE_PER_CUBIC_METER = 0 class FrequencyScale(MultilevelSensorScaleType): """Enum for known scales for FREQUENCY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts HERTZ = 0 KILOHERTZ = 1 class GeneralPurposeScale(MultilevelSensorScaleType): """Enum for known scales for GENERAL_PURPOSE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts DIMENSIONLESS_VALUE = 1 PERCENTAGE_VALUE = 0 class HeartRateScale(MultilevelSensorScaleType): """Enum for known scales for HEART_RATE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BEATS_PER_MINUTE = 0 class HumidityScale(MultilevelSensorScaleType): """Enum for known scales for HUMIDITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts ABSOLUTE_HUMIDITY = 1 PERCENTAGE_VALUE = 0 class IlluminanceScale(MultilevelSensorScaleType): """Enum for known scales for ILLUMINANCE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts LUX = 1 PERCENTAGE_VALUE = 0 class LoudnessScale(MultilevelSensorScaleType): """Enum for known scales for LOUDNESS multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts A_WEIGHTED_DECIBELS = 1 DECIBEL = 0 class MassScale(MultilevelSensorScaleType): """Enum for known scales for MASS multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts KILOGRAM = 0 class MethaneDensityScale(MultilevelSensorScaleType): """Enum for known scales for METHANE_DENSITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MOLE_PER_CUBIC_METER = 0 class MoistureScale(MultilevelSensorScaleType): """Enum for known scales for MOISTURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts IMPEDANCE = 2 PERCENTAGE_VALUE = 0 VOLUME_WATER_CONTENT = 1 WATER_ACTIVITY = 3 class ParticulateMatter10Scale(MultilevelSensorScaleType): """Enum for known scales for PARTICULATE_MATTER_10 multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MICROGRAM_PER_CUBIC_METER = 1 MOLE_PER_CUBIC_METER = 0 class ParticulateMatter25Scale(MultilevelSensorScaleType): """Enum for known scales for PARTICULATE_MATTER_2_5 multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MICROGRAM_PER_CUBIC_METER = 1 MOLE_PER_CUBIC_METER = 0 class PercentageScale(MultilevelSensorScaleType): """Enum for known scales for PERCENTAGE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts PERCENTAGE_VALUE = 0 class PowerScale(MultilevelSensorScaleType): """Enum for known scales for POWER multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BTU_H = 1 WATT = 0 class PressureScale(MultilevelSensorScaleType): """Enum for known scales for PRESSURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts KILOPASCAL = 0 POUND_PER_SQUARE_INCH = 1 class RadonConcentrationScale(MultilevelSensorScaleType): """Enum for known scales for RADON_CONCENTRATION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BECQUEREL_PER_CUBIC_METER = 0 PICOCURIES_PER_LITER = 1 class RainRateScale(MultilevelSensorScaleType): """Enum for known scales for RAIN_RATE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts INCHES_PER_HOUR = 1 MILLIMETER_HOUR = 0 class RespiratoryRateScale(MultilevelSensorScaleType): """Enum for known scales for RESPIRATORY_RATE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BREATHS_PER_MINUTE = 0 class RfSignalStrengthScale(MultilevelSensorScaleType): """Enum for known scales for RF_SIGNAL_STRENGTH multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts POWER_LEVEL = 1 RSSI = 0 class RotationScale(MultilevelSensorScaleType): """Enum for known scales for ROTATION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts HERTZ = 1 REVOLUTIONS_PER_MINUTE = 0 class SeismicIntensityScale(MultilevelSensorScaleType): """Enum for known scales for SEISMIC_INTENSITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts EUROPEAN_MACROSEISMIC = 1 LIEDU = 2 MERCALLI = 0 SHINDO = 3 class SeismicMagnitudeScale(MultilevelSensorScaleType): """Enum for known scales for SEISMIC_MAGNITUDE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts BODY_WAVE = 3 LOCAL = 0 MOMENT = 1 SURFACE_WAVE = 2 class SoilSalinityScale(MultilevelSensorScaleType): """Enum for known scales for SOIL_SALINITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MOLE_PER_CUBIC_METER = 0 class SolarRadiationScale(MultilevelSensorScaleType): """Enum for known scales for SOLAR_RADIATION multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts WATT_PER_SQUARE_METER = 0 class TankCapacityScale(MultilevelSensorScaleType): """Enum for known scales for TANK_CAPACITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts CUBIC_METER = 1 GALLONS = 2 LITER = 0 class TemperatureScale(MultilevelSensorScaleType): """Enum for known scales for TEMPERATURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts CELSIUS = 0 FAHRENHEIT = 1 class TideLevelScale(MultilevelSensorScaleType): """Enum for known scales for TIDE_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts FEET = 1 METER = 0 class TimeScale(MultilevelSensorScaleType): """Enum for known scales for TIME multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts SECOND = 0 class UltravioletScale(MultilevelSensorScaleType): """Enum for known scales for ULTRAVIOLET multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts UV_INDEX = 0 class UnitlessScale(MultilevelSensorScaleType): """Enum for known scales for UNITLESS multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts UNITLESS = 0 class VelocityScale(MultilevelSensorScaleType): """Enum for known scales for VELOCITY multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MPH = 1 M_S = 0 class VolatileOrganicCompoundLevelScale(MultilevelSensorScaleType): """Enum for known scales for VOLATILE_ORGANIC_COMPOUND_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MOLE_PER_CUBIC_METER = 0 PARTS_MILLION = 1 class VoltageScale(MultilevelSensorScaleType): """Enum for known scales for VOLTAGE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MILLIVOLT = 1 VOLT = 0 class WaterChlorineLevelScale(MultilevelSensorScaleType): """Enum for known scales for WATER_CHLORINE_LEVEL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MILLIGRAM_PER_LITER = 0 class WaterFlowScale(MultilevelSensorScaleType): """Enum for known scales for WATER_FLOW multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts LITER_PER_HOUR = 0 class WaterOxidationReductionPotentialScale(MultilevelSensorScaleType): """Enum for known scales for WATER_OXIDATION_REDUCTION_POTENTIAL multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts MILLIVOLT = 0 class WaterPressureScale(MultilevelSensorScaleType): """Enum for known scales for WATER_PRESSURE multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts KILOPASCAL = 0 class WeightScale(MultilevelSensorScaleType): """Enum for known scales for WEIGHT multilevel sensor types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/SensorTypes.ts KILOGRAM = 0 POUNDS = 1 MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP: dict[ MultilevelSensorType, type[MultilevelSensorScaleType] ] = { MultilevelSensorType.ACCELERATION_X_AXIS: AccelerationScale, MultilevelSensorType.ACCELERATION_Y_AXIS: AccelerationScale, MultilevelSensorType.ACCELERATION_Z_AXIS: AccelerationScale, MultilevelSensorType.AIR_FLOW: AirFlowScale, MultilevelSensorType.AIR_TEMPERATURE: TemperatureScale, MultilevelSensorType.AMMONIA: DensityScale, MultilevelSensorType.ANGLE_POSITION: AnglePositionScale, MultilevelSensorType.APPLIED_FORCE_ON_THE_SENSOR: AppliedForceOnTheSensorScale, MultilevelSensorType.ATMOSPHERIC_PRESSURE: AirPressureScale, MultilevelSensorType.BAROMETRIC_PRESSURE: AirPressureScale, MultilevelSensorType.BASIS_METABOLIC_RATE: BasisMetabolicRateScale, MultilevelSensorType.BLOOD_PRESSURE: BloodPressureScale, MultilevelSensorType.BODY_MASS_INDEX: BodyMassIndexScale, MultilevelSensorType.BOILER_WATER_TEMPERATURE: TemperatureScale, MultilevelSensorType.BONE_MASS: MassScale, MultilevelSensorType.CARBON_DIOXIDE_LEVEL: CarbonDioxideLevelScale, MultilevelSensorType.CARBON_MONOXIDE_LEVEL: CarbonMonoxideLevelScale, MultilevelSensorType.CONDENSER_COIL_TEMPERATURE: TemperatureScale, MultilevelSensorType.CURRENT: CurrentScale, MultilevelSensorType.DEFROST_TEMPERATURE: TemperatureScale, MultilevelSensorType.DEW_POINT: TemperatureScale, MultilevelSensorType.DIRECTION: DirectionScale, MultilevelSensorType.DISCHARGE_LINE_TEMPERATURE: TemperatureScale, MultilevelSensorType.DISCHARGE_PRESSURE: PressureScale, MultilevelSensorType.DISTANCE: DistanceScale, MultilevelSensorType.DOMESTIC_HOT_WATER_TEMPERATURE: TemperatureScale, MultilevelSensorType.ELECTRICAL_CONDUCTIVITY: ElectricalConductivityScale, MultilevelSensorType.ELECTRICAL_RESISTIVITY: ElectricalResistivityScale, MultilevelSensorType.EVAPORATOR_COIL_TEMPERATURE: TemperatureScale, MultilevelSensorType.EXHAUST_TEMPERATURE: TemperatureScale, MultilevelSensorType.FAT_MASS: MassScale, MultilevelSensorType.FORMALDEHYDE_LEVEL: FormaldehydeLevelScale, MultilevelSensorType.FREQUENCY: FrequencyScale, MultilevelSensorType.GENERAL_PURPOSE: GeneralPurposeScale, MultilevelSensorType.HEART_RATE: HeartRateScale, MultilevelSensorType.HEART_RATE_LF_HF_RATIO: UnitlessScale, MultilevelSensorType.HUMIDITY: HumidityScale, MultilevelSensorType.ILLUMINANCE: IlluminanceScale, MultilevelSensorType.LEAD: DensityScale, MultilevelSensorType.LIQUID_LINE_TEMPERATURE: TemperatureScale, MultilevelSensorType.LOUDNESS: LoudnessScale, MultilevelSensorType.METHANE_DENSITY: MethaneDensityScale, MultilevelSensorType.MOISTURE: MoistureScale, MultilevelSensorType.MOTION_DIRECTION: DirectionScale, MultilevelSensorType.MUSCLE_MASS: MassScale, MultilevelSensorType.NITROGEN_DIOXIDE: DensityScale, MultilevelSensorType.OUTSIDE_TEMPERATURE: TemperatureScale, MultilevelSensorType.OZONE: DensityScale, MultilevelSensorType.PARTICULATE_MATTER_1: DensityScale, MultilevelSensorType.PARTICULATE_MATTER_10: ParticulateMatter10Scale, MultilevelSensorType.PARTICULATE_MATTER_2_5: ParticulateMatter25Scale, MultilevelSensorType.PERSON_COUNTER_ENTERING: UnitlessScale, MultilevelSensorType.PERSON_COUNTER_EXITING: UnitlessScale, MultilevelSensorType.POWER: PowerScale, MultilevelSensorType.RADON_CONCENTRATION: RadonConcentrationScale, MultilevelSensorType.RAIN_RATE: RainRateScale, MultilevelSensorType.RELATIVE_MODULATION_LEVEL: PercentageScale, MultilevelSensorType.RESPIRATORY_RATE: RespiratoryRateScale, MultilevelSensorType.RETURN_AIR_TEMPERATURE: TemperatureScale, MultilevelSensorType.RF_SIGNAL_STRENGTH: RfSignalStrengthScale, MultilevelSensorType.ROTATION: RotationScale, MultilevelSensorType.SEISMIC_INTENSITY: SeismicIntensityScale, MultilevelSensorType.SEISMIC_MAGNITUDE: SeismicMagnitudeScale, MultilevelSensorType.SMOKE_DENSITY: PercentageScale, MultilevelSensorType.SOIL_HUMIDITY: PercentageScale, MultilevelSensorType.SOIL_REACTIVITY: AcidityScale, MultilevelSensorType.SOIL_SALINITY: SoilSalinityScale, MultilevelSensorType.SOIL_TEMPERATURE: TemperatureScale, MultilevelSensorType.SOLAR_RADIATION: SolarRadiationScale, MultilevelSensorType.SUCTION_PRESSURE: PressureScale, MultilevelSensorType.SULFUR_DIOXIDE: DensityScale, MultilevelSensorType.SUPPLY_AIR_TEMPERATURE: TemperatureScale, MultilevelSensorType.TANK_CAPACITY: TankCapacityScale, MultilevelSensorType.TARGET_TEMPERATURE: TemperatureScale, MultilevelSensorType.TIDE_LEVEL: TideLevelScale, MultilevelSensorType.TIME: TimeScale, MultilevelSensorType.TOTAL_BODY_WATER: MassScale, MultilevelSensorType.ULTRAVIOLET: UltravioletScale, MultilevelSensorType.VELOCITY: VelocityScale, MultilevelSensorType.VOLATILE_ORGANIC_COMPOUND_LEVEL: VolatileOrganicCompoundLevelScale, MultilevelSensorType.VOLTAGE: VoltageScale, MultilevelSensorType.WATER_ACIDITY: AcidityScale, MultilevelSensorType.WATER_CHLORINE_LEVEL: WaterChlorineLevelScale, MultilevelSensorType.WATER_FLOW: WaterFlowScale, MultilevelSensorType.WATER_OXIDATION_REDUCTION_POTENTIAL: WaterOxidationReductionPotentialScale, MultilevelSensorType.WATER_PRESSURE: WaterPressureScale, MultilevelSensorType.WATER_TEMPERATURE: TemperatureScale, MultilevelSensorType.WEIGHT: WeightScale, } UNIT_ABSOLUTE_HUMIDITY: list[MultilevelSensorScaleType] = [ HumidityScale.ABSOLUTE_HUMIDITY ] UNIT_ACIDITY: list[MultilevelSensorScaleType] = [AcidityScale.ACIDITY] UNIT_AMPERE: list[MultilevelSensorScaleType] = [CurrentScale.AMPERE] UNIT_A_WEIGHTED_DECIBELS: list[MultilevelSensorScaleType] = [ LoudnessScale.A_WEIGHTED_DECIBELS ] UNIT_BEATS_PER_MINUTE: list[MultilevelSensorScaleType] = [ HeartRateScale.BEATS_PER_MINUTE ] UNIT_BECQUEREL_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [ RadonConcentrationScale.BECQUEREL_PER_CUBIC_METER ] UNIT_BODY_MASS_INDEX: list[MultilevelSensorScaleType] = [ BodyMassIndexScale.BODY_MASS_INDEX ] UNIT_BODY_WAVE: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.BODY_WAVE] UNIT_BREATHS_PER_MINUTE: list[MultilevelSensorScaleType] = [ RespiratoryRateScale.BREATHS_PER_MINUTE ] UNIT_BTU_H: list[MultilevelSensorScaleType] = [PowerScale.BTU_H] UNIT_CELSIUS: list[MultilevelSensorScaleType] = [TemperatureScale.CELSIUS] UNIT_CENTIMETER: list[MultilevelSensorScaleType] = [DistanceScale.CENTIMETER] UNIT_CUBIC_FEET_PER_MINUTE: list[MultilevelSensorScaleType] = [ AirFlowScale.CUBIC_FEET_PER_MINUTE ] UNIT_CUBIC_METER: list[MultilevelSensorScaleType] = [TankCapacityScale.CUBIC_METER] UNIT_CUBIC_METER_PER_HOUR: list[MultilevelSensorScaleType] = [ AirFlowScale.CUBIC_METER_PER_HOUR ] UNIT_DECIBEL: list[MultilevelSensorScaleType] = [LoudnessScale.DECIBEL] UNIT_DEGREES: list[MultilevelSensorScaleType] = [DirectionScale.DEGREES] UNIT_DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW: list[ MultilevelSensorScaleType ] = [AnglePositionScale.DEGREES_RELATIVE_TO_NORTH_POLE_OF_STANDING_EYE_VIEW] UNIT_DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW: list[ MultilevelSensorScaleType ] = [AnglePositionScale.DEGREES_RELATIVE_TO_SOUTH_POLE_OF_STANDING_EYE_VIEW] UNIT_DENSITY: list[MultilevelSensorScaleType] = [DensityScale.DENSITY] UNIT_DIASTOLIC: list[MultilevelSensorScaleType] = [BloodPressureScale.DIASTOLIC] UNIT_DIMENSIONLESS_VALUE: list[MultilevelSensorScaleType] = [ GeneralPurposeScale.DIMENSIONLESS_VALUE ] UNIT_EUROPEAN_MACROSEISMIC: list[MultilevelSensorScaleType] = [ SeismicIntensityScale.EUROPEAN_MACROSEISMIC ] UNIT_FAHRENHEIT: list[MultilevelSensorScaleType] = [TemperatureScale.FAHRENHEIT] UNIT_FEET: list[MultilevelSensorScaleType] = [DistanceScale.FEET, TideLevelScale.FEET] UNIT_GALLONS: list[MultilevelSensorScaleType] = [TankCapacityScale.GALLONS] UNIT_HERTZ: list[MultilevelSensorScaleType] = [ FrequencyScale.HERTZ, RotationScale.HERTZ, ] UNIT_IMPEDANCE: list[MultilevelSensorScaleType] = [MoistureScale.IMPEDANCE] UNIT_INCHES_OF_MERCURY: list[MultilevelSensorScaleType] = [ AirPressureScale.INCHES_OF_MERCURY ] UNIT_INCHES_PER_HOUR: list[MultilevelSensorScaleType] = [RainRateScale.INCHES_PER_HOUR] UNIT_JOULE: list[MultilevelSensorScaleType] = [BasisMetabolicRateScale.JOULE] UNIT_KILOGRAM: list[MultilevelSensorScaleType] = [ MassScale.KILOGRAM, WeightScale.KILOGRAM, ] UNIT_KILOHERTZ: list[MultilevelSensorScaleType] = [FrequencyScale.KILOHERTZ] UNIT_KILOPASCAL: list[MultilevelSensorScaleType] = [ AirPressureScale.KILOPASCAL, PressureScale.KILOPASCAL, WaterPressureScale.KILOPASCAL, ] UNIT_LIEDU: list[MultilevelSensorScaleType] = [SeismicIntensityScale.LIEDU] UNIT_LITER: list[MultilevelSensorScaleType] = [TankCapacityScale.LITER] UNIT_LITER_PER_HOUR: list[MultilevelSensorScaleType] = [WaterFlowScale.LITER_PER_HOUR] UNIT_LOCAL: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.LOCAL] UNIT_LUX: list[MultilevelSensorScaleType] = [IlluminanceScale.LUX] UNIT_MERCALLI: list[MultilevelSensorScaleType] = [SeismicIntensityScale.MERCALLI] UNIT_METER: list[MultilevelSensorScaleType] = [ DistanceScale.METER, TideLevelScale.METER, ] UNIT_METER_PER_SQUARE_SECOND: list[MultilevelSensorScaleType] = [ AccelerationScale.METER_PER_SQUARE_SECOND ] UNIT_MICROGRAM_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [ ParticulateMatter10Scale.MICROGRAM_PER_CUBIC_METER, ParticulateMatter25Scale.MICROGRAM_PER_CUBIC_METER, ] UNIT_MILLIAMPERE: list[MultilevelSensorScaleType] = [CurrentScale.MILLIAMPERE] UNIT_MILLIGRAM_PER_LITER: list[MultilevelSensorScaleType] = [ WaterChlorineLevelScale.MILLIGRAM_PER_LITER ] UNIT_MILLIMETER_HOUR: list[MultilevelSensorScaleType] = [RainRateScale.MILLIMETER_HOUR] UNIT_MILLIVOLT: list[MultilevelSensorScaleType] = [ VoltageScale.MILLIVOLT, WaterOxidationReductionPotentialScale.MILLIVOLT, ] UNIT_MOLE_PER_CUBIC_METER: list[MultilevelSensorScaleType] = [ CarbonMonoxideLevelScale.MOLE_PER_CUBIC_METER, FormaldehydeLevelScale.MOLE_PER_CUBIC_METER, MethaneDensityScale.MOLE_PER_CUBIC_METER, ParticulateMatter10Scale.MOLE_PER_CUBIC_METER, ParticulateMatter25Scale.MOLE_PER_CUBIC_METER, SoilSalinityScale.MOLE_PER_CUBIC_METER, VolatileOrganicCompoundLevelScale.MOLE_PER_CUBIC_METER, ] UNIT_MOMENT: list[MultilevelSensorScaleType] = [SeismicMagnitudeScale.MOMENT] UNIT_MPH: list[MultilevelSensorScaleType] = [VelocityScale.MPH] UNIT_M_S: list[MultilevelSensorScaleType] = [VelocityScale.M_S] UNIT_NEWTON: list[MultilevelSensorScaleType] = [AppliedForceOnTheSensorScale.NEWTON] UNIT_OHM_METER: list[MultilevelSensorScaleType] = [ElectricalResistivityScale.OHM_METER] UNIT_PARTS_MILLION: list[MultilevelSensorScaleType] = [ CarbonDioxideLevelScale.PARTS_MILLION, CarbonMonoxideLevelScale.PARTS_MILLION, VolatileOrganicCompoundLevelScale.PARTS_MILLION, ] UNIT_PERCENTAGE_VALUE: list[MultilevelSensorScaleType] = [ AnglePositionScale.PERCENTAGE_VALUE, GeneralPurposeScale.PERCENTAGE_VALUE, HumidityScale.PERCENTAGE_VALUE, IlluminanceScale.PERCENTAGE_VALUE, MoistureScale.PERCENTAGE_VALUE, PercentageScale.PERCENTAGE_VALUE, ] UNIT_PICOCURIES_PER_LITER: list[MultilevelSensorScaleType] = [ RadonConcentrationScale.PICOCURIES_PER_LITER ] UNIT_POUNDS: list[MultilevelSensorScaleType] = [WeightScale.POUNDS] UNIT_POUND_PER_SQUARE_INCH: list[MultilevelSensorScaleType] = [ PressureScale.POUND_PER_SQUARE_INCH ] UNIT_POWER_LEVEL: list[MultilevelSensorScaleType] = [RfSignalStrengthScale.POWER_LEVEL] UNIT_REVOLUTIONS_PER_MINUTE: list[MultilevelSensorScaleType] = [ RotationScale.REVOLUTIONS_PER_MINUTE ] UNIT_RSSI: list[MultilevelSensorScaleType] = [RfSignalStrengthScale.RSSI] UNIT_SECOND: list[MultilevelSensorScaleType] = [TimeScale.SECOND] UNIT_SHINDO: list[MultilevelSensorScaleType] = [SeismicIntensityScale.SHINDO] UNIT_SIEMENS_PER_METER: list[MultilevelSensorScaleType] = [ ElectricalConductivityScale.SIEMENS_PER_METER ] UNIT_SURFACE_WAVE: list[MultilevelSensorScaleType] = [ SeismicMagnitudeScale.SURFACE_WAVE ] UNIT_SYSTOLIC: list[MultilevelSensorScaleType] = [BloodPressureScale.SYSTOLIC] UNIT_UNITLESS: list[MultilevelSensorScaleType] = [UnitlessScale.UNITLESS] UNIT_UV_INDEX: list[MultilevelSensorScaleType] = [UltravioletScale.UV_INDEX] UNIT_VOLT: list[MultilevelSensorScaleType] = [VoltageScale.VOLT] UNIT_VOLUME_WATER_CONTENT: list[MultilevelSensorScaleType] = [ MoistureScale.VOLUME_WATER_CONTENT ] UNIT_WATER_ACTIVITY: list[MultilevelSensorScaleType] = [MoistureScale.WATER_ACTIVITY] UNIT_WATT: list[MultilevelSensorScaleType] = [PowerScale.WATT] UNIT_WATT_PER_SQUARE_METER: list[MultilevelSensorScaleType] = [ SolarRadiationScale.WATT_PER_SQUARE_METER ] # ----------------------------------------------------------------------------------- # # **END OF AUTOGENERATED CONTENT** (DO NOT EDIT/REMOVE THIS COMMENT BLOCK AND DO NOT # # EDIT ANYTHING ABOVE IT. IF A NEW IMPORT IS NEEDED, ADD IT TO THE IMPORTS IN THE # # CORRESPONDING GENERATION SCRIPT THEN RE-RUN THE SCRIPT. LINES WRITTEN BELOW THIS # # BLOCK WILL BE PRESERVED AS LONG AS THIS BLOCK REMAINS) # # ----------------------------------------------------------------------------------- # CO_SENSORS = [MultilevelSensorType.CARBON_MONOXIDE_LEVEL] CO2_SENSORS = [MultilevelSensorType.CARBON_DIOXIDE_LEVEL] CURRENT_SENSORS = [MultilevelSensorType.CURRENT] ENERGY_MEASUREMENT_SENSORS = [MultilevelSensorType.BASIS_METABOLIC_RATE] HUMIDITY_SENSORS = [MultilevelSensorType.HUMIDITY] ILLUMINANCE_SENSORS = [MultilevelSensorType.ILLUMINANCE] POWER_SENSORS = [MultilevelSensorType.POWER] PRESSURE_SENSORS = [ MultilevelSensorType.BLOOD_PRESSURE, MultilevelSensorType.WATER_PRESSURE, MultilevelSensorType.SUCTION_PRESSURE, MultilevelSensorType.DISCHARGE_PRESSURE, MultilevelSensorType.BAROMETRIC_PRESSURE, MultilevelSensorType.ATMOSPHERIC_PRESSURE, ] SIGNAL_STRENGTH_SENSORS = [MultilevelSensorType.RF_SIGNAL_STRENGTH] TEMPERATURE_SENSORS = [ MultilevelSensorType.AIR_TEMPERATURE, MultilevelSensorType.DEW_POINT, MultilevelSensorType.WATER_TEMPERATURE, MultilevelSensorType.SOIL_TEMPERATURE, MultilevelSensorType.TARGET_TEMPERATURE, MultilevelSensorType.BOILER_WATER_TEMPERATURE, MultilevelSensorType.DOMESTIC_HOT_WATER_TEMPERATURE, MultilevelSensorType.OUTSIDE_TEMPERATURE, MultilevelSensorType.EXHAUST_TEMPERATURE, MultilevelSensorType.RETURN_AIR_TEMPERATURE, MultilevelSensorType.SUPPLY_AIR_TEMPERATURE, MultilevelSensorType.CONDENSER_COIL_TEMPERATURE, MultilevelSensorType.EVAPORATOR_COIL_TEMPERATURE, MultilevelSensorType.LIQUID_LINE_TEMPERATURE, MultilevelSensorType.DISCHARGE_LINE_TEMPERATURE, MultilevelSensorType.DEFROST_TEMPERATURE, ] VOLTAGE_SENSORS = [ MultilevelSensorType.VOLTAGE, MultilevelSensorType.WATER_OXIDATION_REDUCTION_POTENTIAL, ] zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/multilevel_switch.py000066400000000000000000000011001500374325600314520ustar00rootroot00000000000000"""Constants for the Multilevel Switch CC.""" from __future__ import annotations from enum import IntEnum SET_TO_PREVIOUS_VALUE = 255 COVER_OPEN_PROPERTY = "Open" COVER_UP_PROPERTY = "Up" COVER_ON_PROPERTY = "On" COVER_CLOSE_PROPERTY = "Close" COVER_DOWN_PROPERTY = "Down" COVER_OFF_PROPERTY = "Off" class CoverStates(IntEnum): """Enum with all (known/used) Z-Wave Cover States.""" CLOSED = 0 OPEN = 99 class MultilevelSwitchCommand(IntEnum): """Enum for known multilevel switch notifications.""" START_LEVEL_CHANGE = 4 STOP_LEVEL_CHANGE = 5 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/notification.py000066400000000000000000001135261500374325600304150ustar00rootroot00000000000000# pylint: disable=line-too-long """Constants for the Notification CC.""" # ----------------------------------------------------------------------------------- # # **BEGINNING OF AUTOGENERATED CONTENT** (TO ADD ADDITIONAL MANUAL CONTENT, LOOK FOR # # THE "END OF AUTOGENERATED CONTENT" COMMENT BLOCK AND ADD YOUR CODE BELOW IT) # # ----------------------------------------------------------------------------------- # from __future__ import annotations from enum import IntEnum CC_SPECIFIC_NOTIFICATION_TYPE = "notificationType" class NotificationType(IntEnum): """Enum for known notification types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ACCESS_CONTROL = 6 APPLIANCE = 12 CLOCK = 11 CO_ALARM = 2 CO2_ALARM = 3 EMERGENCY_ALARM = 10 GAS_ALARM = 18 HEAT_ALARM = 4 HOME_HEALTH = 13 HOME_MONITORING = 22 HOME_SECURITY = 7 IRRIGATION = 17 LIGHT_SENSOR = 20 PEST_CONTROL = 19 POWER_MANAGEMENT = 8 SIREN = 14 SMOKE_ALARM = 1 SYSTEM = 9 WATER_ALARM = 5 WATER_QUALITY_MONITORING = 21 WATER_VALVE = 15 WEATHER_ALARM = 16 @classmethod def _missing_(cls: type, value: object) -> NotificationType: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return NotificationType.UNKNOWN class NotificationEvent(IntEnum): """Common base class for Notification CC states enums.""" class NotificationEventValue(IntEnum): """Common base class for Notification CC state value enums.""" class AccessControlNotificationEvent(NotificationEvent): """Enum for known access control notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALL_USER_CODES_DELETED = 12 ALL_USERS_DELETED = 37 AUTO_LOCK_LOCKED_OPERATION = 9 AUTO_LOCK_NOT_FULLY_LOCKED_OPERATION = 10 BARRIER_BATTERY_STATUS_BARRIER_SENSOR_LOW_BATTERY_WARNING = 74 BARRIER_CONTROL_STATUS_BARRIER_ASSOCIATED_WITH_NON_Z_WAVE_REMOTE_CONTROL = 76 BARRIER_FAILED_TO_PERFORM_REQUESTED_OPERATION_DEVICE_MALFUNCTION = 70 BARRIER_MOTOR_HAS_EXCEEDED_MANUFACTURER_S_OPERATIONAL_TIME_LIMIT = 66 BARRIER_OPERATION_OPEN_CLOSE_FORCE_HAS_BEEN_EXCEEDED = 65 BARRIER_OPERATION_HAS_EXCEEDED_PHYSICAL_MECHANICAL_LIMITS = 67 BARRIER_PERFORMING_INITIALIZATION_PROCESS = 64 BARRIER_SAFETY_BEAM_OBSTACLE = 72 BARRIER_SENSOR_STATUS_BARRIER_SENSOR_NOT_DETECTED_SUPERVISORY_ERROR = 73 BARRIER_SHORT_CIRCUIT_STATUS_BARRIER_DETECTED_SHORT_IN_WALL_STATION_WIRES = 75 BARRIER_UL_DISABLING_STATUS_BARRIER_UNATTENDED_OPERATION_HAS_BEEN_DISABLED_PER_UL_REQUIREMENTS = ( 69 ) BARRIER_UNABLE_TO_PERFORM_REQUESTED_OPERATION_DUE_TO_UL_REQUIREMENTS = 68 BARRIER_VACATION_MODE = 71 CREDENTIAL_ADDED = 43 CREDENTIAL_DELETED = 45 CREDENTIAL_LOCK_OPEN_OPERATION = 35 CREDENTIAL_MODIFIED = 44 CREDENTIAL_UNCHANGED = 46 CREDENTIAL_UNLOCK_CLOSE_OPERATION = 36 DOOR_HANDLE_STATE_WINDOW_DOOR_HANDLE_IS_CLOSED = 25 DOOR_HANDLE_STATE_WINDOW_DOOR_HANDLE_IS_OPEN = 24 DOOR_STATE_WINDOW_DOOR_IS_CLOSED = 23 DOOR_STATE_WINDOW_DOOR_IS_OPEN = 22 INVALID_CREDENTIAL_USED = 50 KEYPAD_LOCK_OPERATION = 5 KEYPAD_STATE_KEYPAD_BUSY = 17 KEYPAD_STATE_KEYPAD_TEMPORARY_DISABLED = 16 KEYPAD_UNLOCK_OPERATION = 6 LOCK_OPERATION_WITH_USER_CODE = 33 LOCK_STATE_LOCK_JAMMED = 11 LOCKED_BY_RF_WITH_INVALID_USER_CODE = 21 MANUAL_LOCK_OPERATION = 1 MANUAL_NOT_FULLY_LOCKED_OPERATION = 7 MANUAL_UNLOCK_OPERATION = 2 MANUALLY_ENTER_USER_ACCESS_CODE_EXCEEDS_CODE_LIMIT = 19 MESSAGING_USER_CODE_ENTERED_VIA_KEYPAD = 32 MULTIPLE_CREDENTIALS_DELETED = 38 NEW_PROGRAM_CODE_ENTERED_UNIQUE_CODE_FOR_LOCK_CONFIGURATION = 18 NEW_USER_CODE_ADDED = 14 NEW_USER_CODE_NOT_ADDED_DUE_TO_DUPLICATE_CODE = 15 NON_ACCESS_CREDENTIAL_ENTERED_VIA_LOCAL_INTERFACE = 51 RF_LOCK_OPERATION = 3 RF_NOT_FULLY_LOCKED_OPERATION = 8 RF_UNLOCK_OPERATION = 4 SINGLE_USER_CODE_DELETED = 13 UNLOCK_BY_RF_WITH_INVALID_USER_CODE = 20 UNLOCK_OPERATION_WITH_USER_CODE = 34 USER_ADDED = 39 USER_DELETED = 41 USER_MODIFIED = 40 USER_UNCHANGED = 42 VALID_CREDENTIAL_ACCESS_DENIED_NOT_ENOUGH_CREDENTIALS_ENTERED = 49 VALID_CREDENTIAL_ACCESS_DENIED_SCHEDULE_INACTIVE = 48 VALID_CREDENTIAL_ACCESS_DENIED_USER_ACTIVE_STATE_SET_TO_OCCUPIED_DISABLED = 47 @classmethod def _missing_( cls: type, value: object ) -> AccessControlNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return AccessControlNotificationEvent.UNKNOWN class BarrierPerformingInitializationProcessNotificationEventValue( NotificationEventValue ): """Enum for known barrier performing initialization process notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 PERFORMING_PROCESS = 255 PROCESS_COMPLETED = 0 @classmethod def _missing_( cls: type, value: object ) -> BarrierPerformingInitializationProcessNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return BarrierPerformingInitializationProcessNotificationEventValue.UNKNOWN class BarrierSafetyBeamObstacleNotificationEventValue(NotificationEventValue): """Enum for known barrier safety beam obstacle notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 NO_OBSTRUCTION = 0 OBSTRUCTION = 255 @classmethod def _missing_( cls: type, value: object ) -> BarrierSafetyBeamObstacleNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return BarrierSafetyBeamObstacleNotificationEventValue.UNKNOWN class BarrierVacationModeNotificationEventValue(NotificationEventValue): """Enum for known barrier vacation mode notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 MODE_DISABLED = 0 MODE_ENABLED = 255 @classmethod def _missing_( cls: type, value: object ) -> BarrierVacationModeNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return BarrierVacationModeNotificationEventValue.UNKNOWN class DoorStateWindowDoorIsOpenNotificationEventValue(NotificationEventValue): """Enum for known door state window/door is open notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 WINDOW_DOOR_IS_OPEN_IN_REGULAR_POSITION = 0 WINDOW_DOOR_IS_OPEN_IN_TILT_POSITION = 1 @classmethod def _missing_( cls: type, value: object ) -> DoorStateWindowDoorIsOpenNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return DoorStateWindowDoorIsOpenNotificationEventValue.UNKNOWN class ApplianceNotificationEvent(NotificationEvent): """Enum for known appliance notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 APPLIANCE_STATUS_BOILING = 8 APPLIANCE_STATUS_DRAINING = 14 APPLIANCE_STATUS_DRYING = 18 APPLIANCE_STATUS_RINSING = 12 APPLIANCE_STATUS_SPINNING = 16 APPLIANCE_STATUS_SUPPLYING_WATER = 6 APPLIANCE_STATUS_WASHING = 10 BOILING_FAILURE = 9 COMPRESSOR_FAILURE = 21 DRAINING_FAILURE = 15 DRYING_FAILURE = 19 FAN_FAILURE = 20 MAINTENANCE_STATUS_REPLACE_MAIN_FILTER = 4 PROGRAM_STATUS_PROGRAM_COMPLETED = 3 PROGRAM_STATUS_PROGRAM_IN_PROGRESS = 2 PROGRAM_STATUS_PROGRAM_STARTED = 1 RINSING_FAILURE = 13 SPINNING_FAILURE = 17 TARGET_TEMPERATURE_FAILURE_STATUS_FAILURE_TO_SET_TARGET_TEMPERATURE = 5 WASHING_FAILURE = 11 WATER_SUPPLY_FAILURE = 7 @classmethod def _missing_( cls: type, value: object ) -> ApplianceNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return ApplianceNotificationEvent.UNKNOWN class ClockNotificationEvent(NotificationEvent): """Enum for known clock notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 TIME_REMAINING = 3 TIMER_ENDED = 2 WAKE_UP_ALERT = 1 @classmethod def _missing_(cls: type, value: object) -> ClockNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return ClockNotificationEvent.UNKNOWN class CoAlarmNotificationEvent(NotificationEvent): """Enum for known co alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALARM_STATUS_ALARM_SILENCED = 6 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED = 4 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED_END_OF_LIFE = 5 PERIODIC_INSPECTION_STATUS_MAINTENANCE_REQUIRED_PLANNED_PERIODIC_INSPECTION = 7 SENSOR_STATUS_CARBON_MONOXIDE_DETECTED = 2 SENSOR_STATUS_CARBON_MONOXIDE_DETECTED_LOCATION_PROVIDED = 1 TEST_STATUS_CARBON_MONOXIDE_TEST = 3 @classmethod def _missing_(cls: type, value: object) -> CoAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return CoAlarmNotificationEvent.UNKNOWN class TestStatusCarbonMonoxideTestNotificationEventValue(NotificationEventValue): """Enum for known test status carbon monoxide test notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 TEST_FAILED = 2 TEST_OK = 1 @classmethod def _missing_( cls: type, value: object ) -> TestStatusCarbonMonoxideTestNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return TestStatusCarbonMonoxideTestNotificationEventValue.UNKNOWN class Co2AlarmNotificationEvent(NotificationEvent): """Enum for known co2 alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALARM_STATUS_ALARM_SILENCED = 6 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED = 4 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED_END_OF_LIFE = 5 PERIODIC_INSPECTION_STATUS_MAINTENANCE_REQUIRED_PLANNED_PERIODIC_INSPECTION = 7 SENSOR_STATUS_CARBON_DIOXIDE_DETECTED = 2 SENSOR_STATUS_CARBON_DIOXIDE_DETECTED_LOCATION_PROVIDED = 1 TEST_STATUS_CARBON_DIOXIDE_TEST = 3 @classmethod def _missing_( cls: type, value: object ) -> Co2AlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return Co2AlarmNotificationEvent.UNKNOWN class TestStatusCarbonDioxideTestNotificationEventValue(NotificationEventValue): """Enum for known test status carbon dioxide test notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 TEST_FAILED = 2 TEST_OK = 1 @classmethod def _missing_( cls: type, value: object ) -> TestStatusCarbonDioxideTestNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return TestStatusCarbonDioxideTestNotificationEventValue.UNKNOWN class EmergencyAlarmNotificationEvent(NotificationEvent): """Enum for known emergency alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 CONTACT_FIRE_SERVICE = 2 CONTACT_MEDICAL_SERVICE = 3 CONTACT_POLICE = 1 @classmethod def _missing_( cls: type, value: object ) -> EmergencyAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return EmergencyAlarmNotificationEvent.UNKNOWN class GasAlarmNotificationEvent(NotificationEvent): """Enum for known gas alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALARM_STATUS_GAS_ALARM_TEST = 5 COMBUSTIBLE_GAS_STATUS_COMBUSTIBLE_GAS_DETECTED = 2 COMBUSTIBLE_GAS_STATUS_COMBUSTIBLE_GAS_DETECTED_LOCATION_PROVIDED = 1 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED = 6 TOXIC_GAS_STATUS_TOXIC_GAS_DETECTED = 4 TOXIC_GAS_STATUS_TOXIC_GAS_DETECTED_LOCATION_PROVIDED = 3 @classmethod def _missing_( cls: type, value: object ) -> GasAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return GasAlarmNotificationEvent.UNKNOWN class HeatAlarmNotificationEvent(NotificationEvent): """Enum for known heat alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALARM_STATUS_ALARM_SILENCED = 9 ALARM_STATUS_HEAT_ALARM_TEST = 7 DUST_IN_DEVICE_STATUS_MAINTENANCE_REQUIRED_DUST_IN_DEVICE = 10 HEAT_SENSOR_STATUS_OVERHEAT_DETECTED = 2 HEAT_SENSOR_STATUS_OVERHEAT_DETECTED_LOCATION_PROVIDED = 1 HEAT_SENSOR_STATUS_UNDERHEAT_DETECTED = 6 HEAT_SENSOR_STATUS_UNDERHEAT_DETECTED_LOCATION_PROVIDED = 5 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED_END_OF_LIFE = 8 PERIODIC_INSPECTION_STATUS_MAINTENANCE_REQUIRED_PLANNED_PERIODIC_INSPECTION = 11 RAPID_TEMPERATURE_FALL = 13 RAPID_TEMPERATURE_FALL_LOCATION_PROVIDED = 12 RAPID_TEMPERATURE_RISE = 4 RAPID_TEMPERATURE_RISE_LOCATION_PROVIDED = 3 @classmethod def _missing_( cls: type, value: object ) -> HeatAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return HeatAlarmNotificationEvent.UNKNOWN class HomeHealthNotificationEvent(NotificationEvent): """Enum for known home health notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 FALL_DETECTED = 12 POSITION_STATUS_LEAVING_BED = 1 POSITION_STATUS_LYING_ON_BED = 3 POSITION_STATUS_SITTING_ON_BED = 2 POSITION_STATUS_SITTING_ON_BED_EDGE = 5 POSTURE_CHANGED = 4 SLEEP_APNEA_STATUS_SLEEP_APNEA_DETECTED = 7 SLEEP_STAGE_STATUS_SLEEP_STAGE_0_DETECTED_DREAMING_REM = 8 SLEEP_STAGE_STATUS_SLEEP_STAGE_1_DETECTED_LIGHT_SLEEP_NON_REM_1 = 9 SLEEP_STAGE_STATUS_SLEEP_STAGE_2_DETECTED_MEDIUM_SLEEP_NON_REM_2 = 10 SLEEP_STAGE_STATUS_SLEEP_STAGE_3_DETECTED_DEEP_SLEEP_NON_REM_3 = 11 VOC_LEVEL_STATUS_VOLATILE_ORGANIC_COMPOUND_LEVEL = 6 @classmethod def _missing_( cls: type, value: object ) -> HomeHealthNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return HomeHealthNotificationEvent.UNKNOWN class SleepApneaStatusSleepApneaDetectedNotificationEventValue(NotificationEventValue): """Enum for known sleep apnea status sleep apnea detected notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 LOW_BREATH = 1 NO_BREATH_AT_ALL = 2 @classmethod def _missing_( cls: type, value: object ) -> SleepApneaStatusSleepApneaDetectedNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return SleepApneaStatusSleepApneaDetectedNotificationEventValue.UNKNOWN class VocLevelStatusVolatileOrganicCompoundLevelNotificationEventValue( NotificationEventValue ): """Enum for known voc level status volatile organic compound level notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 CLEAN = 1 HIGHLY_POLLUTED = 4 MODERATELY_POLLUTED = 3 SLIGHTLY_POLLUTED = 2 @classmethod def _missing_( cls: type, value: object ) -> ( VocLevelStatusVolatileOrganicCompoundLevelNotificationEventValue ): # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return VocLevelStatusVolatileOrganicCompoundLevelNotificationEventValue.UNKNOWN class HomeMonitoringNotificationEvent(NotificationEvent): """Enum for known home monitoring notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 HOME_OCCUPANCY_STATUS_HOME_OCCUPIED = 2 HOME_OCCUPANCY_STATUS_HOME_OCCUPIED_LOCATION_PROVIDED = 1 @classmethod def _missing_( cls: type, value: object ) -> HomeMonitoringNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return HomeMonitoringNotificationEvent.UNKNOWN class HomeSecurityNotificationEvent(NotificationEvent): """Enum for known home security notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 COVER_STATUS_TAMPERING_PRODUCT_COVER_REMOVED = 3 GLASS_BREAKAGE = 6 GLASS_BREAKAGE_LOCATION_PROVIDED = 5 IMPACT_DETECTED = 10 MAGNETIC_INTERFERENCE_STATUS_MAGNETIC_FIELD_INTERFERENCE_DETECTED = 11 MOTION_SENSOR_STATUS_MOTION_DETECTION = 8 MOTION_SENSOR_STATUS_MOTION_DETECTION_LOCATION_PROVIDED = 7 RF_JAMMING_DETECTED = 12 SENSOR_STATUS_INTRUSION = 2 SENSOR_STATUS_INTRUSION_LOCATION_PROVIDED = 1 TAMPERING_INVALID_CODE = 4 TAMPERING_PRODUCT_MOVED = 9 @classmethod def _missing_( cls: type, value: object ) -> HomeSecurityNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return HomeSecurityNotificationEvent.UNKNOWN class IrrigationNotificationEvent(NotificationEvent): """Enum for known irrigation notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 DEVICE_CONFIGURATION_STATUS_DEVICE_IS_NOT_CONFIGURED = 5 SCHEDULE_ID_STATUS_SCHEDULE_FINISHED = 2 SCHEDULE_ID_STATUS_SCHEDULE_STARTED = 1 VALVE_ID_RUN_STATUS_VALVE_TABLE_RUN_FINISHED = 4 VALVE_ID_RUN_STATUS_VALVE_TABLE_RUN_STARTED = 3 @classmethod def _missing_( cls: type, value: object ) -> IrrigationNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return IrrigationNotificationEvent.UNKNOWN class LightSensorNotificationEvent(NotificationEvent): """Enum for known light sensor notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 LIGHT_COLOR_TRANSITION_DETECTED = 2 LIGHT_DETECTION_STATUS_LIGHT_DETECTED = 1 @classmethod def _missing_( cls: type, value: object ) -> LightSensorNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return LightSensorNotificationEvent.UNKNOWN class PestControlNotificationEvent(NotificationEvent): """Enum for known pest control notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 PEST_DETECTED = 6 PEST_DETECTED_LOCATION_PROVIDED = 5 PEST_EXTERMINATED = 8 PEST_EXTERMINATED_LOCATION_PROVIDED = 7 TRAP_STATUS_TRAP_ARMED = 2 TRAP_STATUS_TRAP_ARMED_LOCATION_PROVIDED = 1 TRAP_STATUS_TRAP_RE_ARM_REQUIRED = 4 TRAP_STATUS_TRAP_RE_ARM_REQUIRED_LOCATION_PROVIDED = 3 @classmethod def _missing_( cls: type, value: object ) -> PestControlNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return PestControlNotificationEvent.UNKNOWN class PowerManagementNotificationEvent(NotificationEvent): """Enum for known power management notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 BACKUP_BATTERY_LEVEL_STATUS_BACK_UP_BATTERY_DISCONNECTED = 18 BACKUP_BATTERY_LEVEL_STATUS_BACK_UP_BATTERY_IS_LOW = 16 BATTERY_LEVEL_STATUS_BATTERY_IS_FULLY_CHARGED = 13 BATTERY_LEVEL_STATUS_CHARGE_BATTERY_NOW = 15 BATTERY_LEVEL_STATUS_CHARGE_BATTERY_SOON = 14 BATTERY_LOAD_STATUS_BATTERY_IS_CHARGING = 12 BATTERY_MAINTENANCE_STATUS_BATTERY_FLUID_IS_LOW = 17 BATTERY_MAINTENANCE_STATUS_REPLACE_BATTERY_NOW = 11 BATTERY_MAINTENANCE_STATUS_REPLACE_BATTERY_SOON = 10 LOAD_ERROR = 9 MAINS_STATUS_AC_MAINS_DISCONNECTED = 2 MAINS_STATUS_AC_MAINS_RE_CONNECTED = 3 OVER_CURRENT_STATUS_OVER_CURRENT_DETECTED = 6 OVER_LOAD_STATUS_OVER_LOAD_DETECTED = 8 OVER_VOLTAGE_STATUS_OVER_VOLTAGE_DETECTED = 7 POWER_STATUS_POWER_HAS_BEEN_APPLIED = 1 SURGE_DETECTED = 4 VOLTAGE_DROP_DRIFT = 5 @classmethod def _missing_( cls: type, value: object ) -> PowerManagementNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return PowerManagementNotificationEvent.UNKNOWN class SirenNotificationEvent(NotificationEvent): """Enum for known siren notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 SIREN_STATUS_SIREN_ACTIVE = 1 @classmethod def _missing_(cls: type, value: object) -> SirenNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return SirenNotificationEvent.UNKNOWN class SmokeAlarmNotificationEvent(NotificationEvent): """Enum for known smoke alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ALARM_STATUS_ALARM_SILENCED = 6 ALARM_STATUS_SMOKE_ALARM_TEST = 3 DUST_IN_DEVICE_STATUS_MAINTENANCE_REQUIRED_DUST_IN_DEVICE = 8 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED = 4 MAINTENANCE_STATUS_REPLACEMENT_REQUIRED_END_OF_LIFE = 5 PERIODIC_INSPECTION_STATUS_MAINTENANCE_REQUIRED_PLANNED_PERIODIC_INSPECTION = 7 SENSOR_STATUS_SMOKE_DETECTED = 2 SENSOR_STATUS_SMOKE_DETECTED_LOCATION_PROVIDED = 1 @classmethod def _missing_( cls: type, value: object ) -> SmokeAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return SmokeAlarmNotificationEvent.UNKNOWN class SystemNotificationEvent(NotificationEvent): """Enum for known system notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 COVER_STATUS_TAMPERING_PRODUCT_COVER_REMOVED = 6 EMERGENCY_SHUTOFF = 7 HARDWARE_STATUS_SYSTEM_HARDWARE_FAILURE = 1 HARDWARE_STATUS_SYSTEM_HARDWARE_FAILURE_WITH_FAILURE_CODE = 3 HEARTBEAT = 5 SOFTWARE_STATUS_SYSTEM_SOFTWARE_FAILURE = 2 SOFTWARE_STATUS_SYSTEM_SOFTWARE_FAILURE_WITH_FAILURE_CODE = 4 @classmethod def _missing_(cls: type, value: object) -> SystemNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return SystemNotificationEvent.UNKNOWN class WaterAlarmNotificationEvent(NotificationEvent): """Enum for known water alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 MAINTENANCE_STATUS_REPLACE_WATER_FILTER = 5 PUMP_STATUS_SUMP_PUMP_ACTIVE = 10 PUMP_STATUS_SUMP_PUMP_FAILURE = 11 SENSOR_STATUS_WATER_LEAK_DETECTED = 2 SENSOR_STATUS_WATER_LEAK_DETECTED_LOCATION_PROVIDED = 1 WATER_FLOW_ALARM = 6 WATER_LEVEL_ALARM = 9 WATER_LEVEL_DROPPED = 4 WATER_LEVEL_DROPPED_LOCATION_PROVIDED = 3 WATER_PRESSURE_ALARM = 7 WATER_TEMPERATURE_ALARM = 8 @classmethod def _missing_( cls: type, value: object ) -> WaterAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterAlarmNotificationEvent.UNKNOWN class WaterFlowAlarmNotificationEventValue(NotificationEventValue): """Enum for known water flow alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 MAX = 4 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> WaterFlowAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterFlowAlarmNotificationEventValue.UNKNOWN class WaterLevelAlarmNotificationEventValue(NotificationEventValue): """Enum for known water level alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> WaterLevelAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterLevelAlarmNotificationEventValue.UNKNOWN class WaterPressureAlarmNotificationEventValue(NotificationEventValue): """Enum for known water pressure alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 MAX = 4 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> WaterPressureAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterPressureAlarmNotificationEventValue.UNKNOWN class WaterTemperatureAlarmNotificationEventValue(NotificationEventValue): """Enum for known water temperature alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> WaterTemperatureAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterTemperatureAlarmNotificationEventValue.UNKNOWN class WaterQualityMonitoringNotificationEvent(NotificationEvent): """Enum for known water quality monitoring notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ACIDITY_PH_SENSOR_STATUS_ACIDITY_PH_EMPTY = 5 ACIDITY_PH_STATUS_ACIDITY_PH_ALARM = 2 CHLORINE_ALARM = 1 CHLORINE_SENSOR_STATUS_CHLORINE_EMPTY = 4 COLLECTIVE_DISORDER = 17 DISINFECTION_SYSTEM_STATUS_DISINFECTION_SYSTEM_ERROR_DETECTED = 8 DRY_PROTECTION_STATUS_DRY_PROTECTION_OPERATION_ACTIVE = 13 FILTER_CLEANING_STATUS_FILTER_CLEANING_ONGOING = 9 FILTER_PUMP_STATUS_FILTER_PUMP_OPERATION_ONGOING = 11 FRESHWATER_FLOW_STATUS_FRESHWATER_OPERATION_ONGOING = 12 HEATING_STATUS_HEATING_OPERATION_ONGOING = 10 WATER_OXIDATION_ALARM = 3 WATER_TANK_STATUS_WATER_TANK_IS_EMPTY = 14 WATER_TANK_STATUS_WATER_TANK_IS_FULL = 16 WATER_TANK_STATUS_WATER_TANK_LEVEL_IS_UNKNOWN = 15 WATERFLOW_CLEAR_WATER_SENSOR_WATERFLOW_CLEAR_WATER_SHORTAGE_DETECTED = 7 WATERFLOW_MEASURING_STATION_SENSOR_WATERFLOW_MEASURING_STATION_SHORTAGE_DETECTED = 6 @classmethod def _missing_( cls: type, value: object ) -> WaterQualityMonitoringNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterQualityMonitoringNotificationEvent.UNKNOWN class AcidityStatusAcidityAlarmNotificationEventValue(NotificationEventValue): """Enum for known acidity (ph) status acidity (ph) alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 2 BELOW_LOW_THRESHOLD = 1 DECREASING_PH = 3 INCREASING_PH = 4 @classmethod def _missing_( cls: type, value: object ) -> AcidityStatusAcidityAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return AcidityStatusAcidityAlarmNotificationEventValue.UNKNOWN class ChlorineAlarmNotificationEventValue(NotificationEventValue): """Enum for known chlorine alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 2 BELOW_LOW_THRESHOLD = 1 @classmethod def _missing_( cls: type, value: object ) -> ChlorineAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return ChlorineAlarmNotificationEventValue.UNKNOWN class WaterOxidationAlarmNotificationEventValue(NotificationEventValue): """Enum for known water oxidation alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 2 BELOW_LOW_THRESHOLD = 1 @classmethod def _missing_( cls: type, value: object ) -> WaterOxidationAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterOxidationAlarmNotificationEventValue.UNKNOWN class WaterValveNotificationEvent(NotificationEvent): """Enum for known water valve notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 MASTER_VALVE_CURRENT_ALARM = 6 MASTER_VALVE_OPERATION = 2 MASTER_VALVE_SHORT_CIRCUIT = 4 VALVE_CURRENT_ALARM = 5 VALVE_JAMMED = 7 VALVE_OPERATION = 1 VALVE_SHORT_CIRCUIT = 3 @classmethod def _missing_( cls: type, value: object ) -> WaterValveNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WaterValveNotificationEvent.UNKNOWN class MasterValveCurrentAlarmNotificationEventValue(NotificationEventValue): """Enum for known master valve current alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 MAX = 4 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> MasterValveCurrentAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return MasterValveCurrentAlarmNotificationEventValue.UNKNOWN class MasterValveOperationNotificationEventValue(NotificationEventValue): """Enum for known master valve operation notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 OFF_CLOSED = 0 ON_OPEN = 1 @classmethod def _missing_( cls: type, value: object ) -> MasterValveOperationNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return MasterValveOperationNotificationEventValue.UNKNOWN class ValveCurrentAlarmNotificationEventValue(NotificationEventValue): """Enum for known valve current alarm notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 ABOVE_HIGH_THRESHOLD = 3 BELOW_LOW_THRESHOLD = 2 MAX = 4 NO_DATA = 1 @classmethod def _missing_( cls: type, value: object ) -> ValveCurrentAlarmNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return ValveCurrentAlarmNotificationEventValue.UNKNOWN class ValveOperationNotificationEventValue(NotificationEventValue): """Enum for known valve operation notification event value.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 OFF_CLOSED = 0 ON_OPEN = 1 @classmethod def _missing_( cls: type, value: object ) -> ValveOperationNotificationEventValue: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return ValveOperationNotificationEventValue.UNKNOWN class WeatherAlarmNotificationEvent(NotificationEvent): """Enum for known weather alarm notification event.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/registries/Notifications.ts UNKNOWN = -1 FREEZE_ALARM = 3 MOISTURE_ALARM = 2 RAIN_ALARM = 1 @classmethod def _missing_( cls: type, value: object ) -> WeatherAlarmNotificationEvent: # noqa: ARG003 """Set default enum member if an unknown value is provided.""" return WeatherAlarmNotificationEvent.UNKNOWN NOTIFICATION_TYPE_TO_EVENT_MAP: dict[NotificationType, type[NotificationEvent]] = { NotificationType.ACCESS_CONTROL: AccessControlNotificationEvent, NotificationType.APPLIANCE: ApplianceNotificationEvent, NotificationType.CLOCK: ClockNotificationEvent, NotificationType.CO_ALARM: CoAlarmNotificationEvent, NotificationType.CO2_ALARM: Co2AlarmNotificationEvent, NotificationType.EMERGENCY_ALARM: EmergencyAlarmNotificationEvent, NotificationType.GAS_ALARM: GasAlarmNotificationEvent, NotificationType.HEAT_ALARM: HeatAlarmNotificationEvent, NotificationType.HOME_HEALTH: HomeHealthNotificationEvent, NotificationType.HOME_MONITORING: HomeMonitoringNotificationEvent, NotificationType.HOME_SECURITY: HomeSecurityNotificationEvent, NotificationType.IRRIGATION: IrrigationNotificationEvent, NotificationType.LIGHT_SENSOR: LightSensorNotificationEvent, NotificationType.PEST_CONTROL: PestControlNotificationEvent, NotificationType.POWER_MANAGEMENT: PowerManagementNotificationEvent, NotificationType.SIREN: SirenNotificationEvent, NotificationType.SMOKE_ALARM: SmokeAlarmNotificationEvent, NotificationType.SYSTEM: SystemNotificationEvent, NotificationType.WATER_ALARM: WaterAlarmNotificationEvent, NotificationType.WATER_QUALITY_MONITORING: WaterQualityMonitoringNotificationEvent, NotificationType.WATER_VALVE: WaterValveNotificationEvent, NotificationType.WEATHER_ALARM: WeatherAlarmNotificationEvent, } NOTIFICATION_EVENT_TO_EVENT_VALUE_MAP: dict[ NotificationEvent, type[NotificationEventValue] ] = { AccessControlNotificationEvent.BARRIER_PERFORMING_INITIALIZATION_PROCESS: BarrierPerformingInitializationProcessNotificationEventValue, AccessControlNotificationEvent.BARRIER_SAFETY_BEAM_OBSTACLE: BarrierSafetyBeamObstacleNotificationEventValue, AccessControlNotificationEvent.BARRIER_VACATION_MODE: BarrierVacationModeNotificationEventValue, AccessControlNotificationEvent.DOOR_STATE_WINDOW_DOOR_IS_OPEN: DoorStateWindowDoorIsOpenNotificationEventValue, Co2AlarmNotificationEvent.TEST_STATUS_CARBON_DIOXIDE_TEST: TestStatusCarbonDioxideTestNotificationEventValue, CoAlarmNotificationEvent.TEST_STATUS_CARBON_MONOXIDE_TEST: TestStatusCarbonMonoxideTestNotificationEventValue, HomeHealthNotificationEvent.SLEEP_APNEA_STATUS_SLEEP_APNEA_DETECTED: SleepApneaStatusSleepApneaDetectedNotificationEventValue, HomeHealthNotificationEvent.VOC_LEVEL_STATUS_VOLATILE_ORGANIC_COMPOUND_LEVEL: VocLevelStatusVolatileOrganicCompoundLevelNotificationEventValue, WaterAlarmNotificationEvent.WATER_FLOW_ALARM: WaterFlowAlarmNotificationEventValue, WaterAlarmNotificationEvent.WATER_LEVEL_ALARM: WaterLevelAlarmNotificationEventValue, WaterAlarmNotificationEvent.WATER_PRESSURE_ALARM: WaterPressureAlarmNotificationEventValue, WaterAlarmNotificationEvent.WATER_TEMPERATURE_ALARM: WaterTemperatureAlarmNotificationEventValue, WaterQualityMonitoringNotificationEvent.ACIDITY_PH_STATUS_ACIDITY_PH_ALARM: AcidityStatusAcidityAlarmNotificationEventValue, WaterQualityMonitoringNotificationEvent.CHLORINE_ALARM: ChlorineAlarmNotificationEventValue, WaterQualityMonitoringNotificationEvent.WATER_OXIDATION_ALARM: WaterOxidationAlarmNotificationEventValue, WaterValveNotificationEvent.MASTER_VALVE_CURRENT_ALARM: MasterValveCurrentAlarmNotificationEventValue, WaterValveNotificationEvent.MASTER_VALVE_OPERATION: MasterValveOperationNotificationEventValue, WaterValveNotificationEvent.VALVE_CURRENT_ALARM: ValveCurrentAlarmNotificationEventValue, WaterValveNotificationEvent.VALVE_OPERATION: ValveOperationNotificationEventValue, } # ----------------------------------------------------------------------------------- # # **END OF AUTOGENERATED CONTENT** (DO NOT EDIT/REMOVE THIS COMMENT BLOCK AND DO NOT # # EDIT ANYTHING ABOVE IT. IF A NEW IMPORT IS NEEDED, ADD IT TO THE IMPORTS IN THE # # CORRESPONDING GENERATION SCRIPT THEN RE-RUN THE SCRIPT. LINES WRITTEN BELOW THIS # # BLOCK WILL BE PRESERVED AS LONG AS THIS BLOCK REMAINS) # # ----------------------------------------------------------------------------------- # zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/power_level.py000066400000000000000000000005741500374325600302500ustar00rootroot00000000000000"""Constants for the Power Level Command Class.""" from __future__ import annotations from enum import IntEnum class PowerLevelTestStatus(IntEnum): """Enum with all known power level test statuses.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/PowerlevelCC.ts#L52 FAILED = 0 SUCCESS = 1 IN_PROGRESS = 2 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/protection.py000066400000000000000000000001701500374325600301030ustar00rootroot00000000000000"""Constants for the Protection CC.""" from __future__ import annotations LOCAL_PROPERTY = "local" RF_PROPERTY = "rf" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/scene_activation.py000066400000000000000000000001601500374325600312320ustar00rootroot00000000000000"""Constants for the Scene Activation CC.""" from __future__ import annotations SCENE_ID_PROPERTY = "sceneId" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/sound_switch.py000066400000000000000000000007011500374325600304260ustar00rootroot00000000000000"""Constants for the Sound Switch CC.""" from __future__ import annotations from enum import IntEnum TONE_ID_PROPERTY = "toneId" DEFAULT_TONE_ID_PROPERTY = "defaultToneId" DEFAULT_VOLUME_PROPERTY = "defaultVolume" class ToneID(IntEnum): """Enum with all known Sound Switch CC tone IDs.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/SoundSwitchCC.ts#L71 OFF = 0 DEFAULT = 255 zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/thermostat.py000066400000000000000000000060321500374325600301120ustar00rootroot00000000000000""" Constants for the Thermostat CCs. Includes Thermostat Fan Mode, Thermostat Fan State, Thermostat Mode, Thermostat Operating State, Thermostat Setback, and Thermostat Setpoint CCs. """ from __future__ import annotations from enum import IntEnum THERMOSTAT_MODE_PROPERTY = "mode" THERMOSTAT_SETPOINT_PROPERTY = "setpoint" THERMOSTAT_OPERATING_STATE_PROPERTY = "state" THERMOSTAT_CURRENT_TEMP_PROPERTY = "Air temperature" THERMOSTAT_HUMIDITY_PROPERTY = "Humidity" THERMOSTAT_FAN_MODE_PROPERTY = "mode" THERMOSTAT_FAN_OFF_PROPERTY = "off" THERMOSTAT_FAN_STATE_PROPERTY = "state" class ThermostatMode(IntEnum): """Enum with all (known/used) Z-Wave ThermostatModes.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatModeCC.ts#L53-L70 OFF = 0 HEAT = 1 COOL = 2 AUTO = 3 AUXILIARY = 4 RESUME_ON = 5 FAN = 6 FURNACE = 7 DRY = 8 MOIST = 9 AUTO_CHANGE_OVER = 10 HEATING_ECON = 11 COOLING_ECON = 12 AWAY = 13 FULL_POWER = 15 MANUFACTURER_SPECIFIC = 31 class ThermostatOperatingState(IntEnum): """Enum with all (known/used) Z-Wave Thermostat OperatingStates.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatOperatingStateCC.ts#L38-L51 IDLE = 0 HEATING = 1 COOLING = 2 FAN_ONLY = 3 PENDING_HEAT = 4 PENDING_COOL = 5 VENT_ECONOMIZER = 6 AUX_HEATING = 7 SECOND_STAGE_HEATING = 8 SECOND_STAGE_COOLING = 9 SECOND_STAGE_AUX_HEAT = 10 THIRD_STAGE_AUX_HEAT = 11 class ThermostatSetpointType(IntEnum): """Enum with all (known/used) Z-Wave Thermostat Setpoint Types.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatSetpointCC.ts#L53-L66 NA = 0 HEATING = 1 COOLING = 2 FURNACE = 7 DRY_AIR = 8 MOIST_AIR = 9 AUTO_CHANGEOVER = 10 ENERGY_SAVE_HEATING = 11 ENERGY_SAVE_COOLING = 12 AWAY_HEATING = 13 AWAY_COOLING = 14 FULL_POWER = 15 THERMOSTAT_MODE_SETPOINT_MAP: dict[int, list[ThermostatSetpointType]] = { ThermostatMode.OFF: [], ThermostatMode.HEAT: [ThermostatSetpointType.HEATING], ThermostatMode.COOL: [ThermostatSetpointType.COOLING], ThermostatMode.AUTO: [ ThermostatSetpointType.HEATING, ThermostatSetpointType.COOLING, ], ThermostatMode.AUXILIARY: [ThermostatSetpointType.HEATING], ThermostatMode.FURNACE: [ThermostatSetpointType.FURNACE], ThermostatMode.DRY: [ThermostatSetpointType.DRY_AIR], ThermostatMode.MOIST: [ThermostatSetpointType.MOIST_AIR], ThermostatMode.AUTO_CHANGE_OVER: [ThermostatSetpointType.AUTO_CHANGEOVER], ThermostatMode.HEATING_ECON: [ThermostatSetpointType.ENERGY_SAVE_HEATING], ThermostatMode.COOLING_ECON: [ThermostatSetpointType.ENERGY_SAVE_COOLING], ThermostatMode.AWAY: [ ThermostatSetpointType.AWAY_HEATING, ThermostatSetpointType.AWAY_COOLING, ], ThermostatMode.FULL_POWER: [ThermostatSetpointType.FULL_POWER], } zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/wake_up.py000066400000000000000000000002571500374325600273560ustar00rootroot00000000000000"""Constants for the Wake Up CC.""" from __future__ import annotations WAKE_UP_INTERVAL_PROPERTY = "wakeUpInterval" WAKE_UP_CONTROLLER_NODE_ID_PROPERTY = "controllerNodeId" zwave-js-server-python-0.63.0/zwave_js_server/const/command_class/window_covering.py000066400000000000000000000040501500374325600311210ustar00rootroot00000000000000"""Constants for the Barrier Operator CC.""" from __future__ import annotations from enum import IntEnum NO_POSITION_SUFFIX = "(no position)" WINDOW_COVERING_LEVEL_CHANGE_DOWN_PROPERTY = "levelChangeDown" WINDOW_COVERING_LEVEL_CHANGE_UP_PROPERTY = "levelChangeUp" class WindowCoveringPropertyKey(IntEnum): """Enum of all known Window Covering CC property keys.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L1588 OUTBOUND_LEFT_NO_POSITION = 0 OUTBOUND_LEFT = 1 OUTBOUND_RIGHT_NO_POSITION = 2 OUTBOUND_RIGHT = 3 INBOUND_LEFT_NO_POSITION = 4 INBOUND_LEFT = 5 INBOUND_RIGHT_NO_POSITION = 6 INBOUND_RIGHT = 7 INBOUND_LEFT_RIGHT_NO_POSITION = 8 INBOUND_LEFT_RIGHT = 9 VERTICAL_SLATS_ANGLE_NO_POSITION = 10 VERTICAL_SLATS_ANGLE = 11 OUTBOUND_BOTTOM_NO_POSITION = 12 OUTBOUND_BOTTOM = 13 OUTBOUND_TOP_NO_POSITION = 14 OUTBOUND_TOP = 15 INBOUND_BOTTOM_NO_POSITION = 16 INBOUND_BOTTOM = 17 INBOUND_TOP_NO_POSITION = 18 INBOUND_TOP = 19 INBOUND_TOP_BOTTOM_NO_POSITION = 20 INBOUND_TOP_BOTTOM = 21 HORIZONTAL_SLATS_ANGLE_NO_POSITION = 22 HORIZONTAL_SLATS_ANGLE = 23 NO_POSITION_PROPERTY_KEYS = { WindowCoveringPropertyKey.OUTBOUND_LEFT_NO_POSITION, WindowCoveringPropertyKey.OUTBOUND_RIGHT_NO_POSITION, WindowCoveringPropertyKey.INBOUND_LEFT_NO_POSITION, WindowCoveringPropertyKey.INBOUND_RIGHT_NO_POSITION, WindowCoveringPropertyKey.INBOUND_LEFT_RIGHT_NO_POSITION, WindowCoveringPropertyKey.VERTICAL_SLATS_ANGLE_NO_POSITION, WindowCoveringPropertyKey.OUTBOUND_BOTTOM_NO_POSITION, WindowCoveringPropertyKey.OUTBOUND_TOP_NO_POSITION, WindowCoveringPropertyKey.INBOUND_BOTTOM_NO_POSITION, WindowCoveringPropertyKey.INBOUND_TOP_NO_POSITION, WindowCoveringPropertyKey.INBOUND_TOP_BOTTOM_NO_POSITION, WindowCoveringPropertyKey.HORIZONTAL_SLATS_ANGLE_NO_POSITION, } class SlatStates(IntEnum): """Enum with all (known/used) Z-Wave Slat States.""" CLOSED_1 = 0 OPEN = 50 CLOSED_2 = 99 zwave-js-server-python-0.63.0/zwave_js_server/dump.py000066400000000000000000000027631500374325600227430ustar00rootroot00000000000000"""Dump helper.""" from __future__ import annotations import asyncio import aiohttp from .client import INITIALIZE_MESSAGE_ID from .const import MAX_SERVER_SCHEMA_VERSION, PACKAGE_NAME, __version__ async def dump_msgs( url: str, session: aiohttp.ClientSession, additional_user_agent_components: dict[str, str] | None = None, timeout: float | None = None, ) -> list[dict]: """Dump server state.""" client = await session.ws_connect(url, compress=15, max_msg_size=0) msgs = [] version = await client.receive_json() msgs.append(version) for to_send in ( { "command": "initialize", "messageId": INITIALIZE_MESSAGE_ID, "schemaVersion": MAX_SERVER_SCHEMA_VERSION, "additionalUserAgentComponents": { PACKAGE_NAME: __version__, **(additional_user_agent_components or {}), }, }, {"command": "start_listening", "messageId": "start-listening"}, ): await client.send_json(to_send) msgs.append(await client.receive_json()) if timeout is None: await client.close() return msgs current_task = asyncio.current_task() assert current_task is not None asyncio.get_running_loop().call_later(timeout, current_task.cancel) while True: try: msg = await client.receive_json() msgs.append(msg) except asyncio.CancelledError: break await client.close() return msgs zwave-js-server-python-0.63.0/zwave_js_server/event.py000066400000000000000000000046031500374325600231120ustar00rootroot00000000000000"""Provide Event base classes for Z-Wave JS.""" from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass, field import logging from typing import Literal try: from pydantic.v1 import BaseModel except ImportError: from pydantic import BaseModel LOGGER = logging.getLogger(__package__) class BaseEventModel(BaseModel): """Base model for an event.""" source: Literal["controller", "driver", "node"] event: str @classmethod def from_dict(cls, data: dict) -> BaseEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], ) @dataclass class Event: """Represent an event.""" type: str data: dict = field(default_factory=dict) class EventBase: """Represent a Z-Wave JS base class for event handling models.""" def __init__(self) -> None: """Initialize event base.""" self._listeners: dict[str, list[Callable]] = {} def on(self, event_name: str, callback: Callable) -> Callable: """Register an event callback.""" listeners: list = self._listeners.setdefault(event_name, []) listeners.append(callback) def unsubscribe() -> None: """Unsubscribe listeners.""" if callback in listeners: listeners.remove(callback) return unsubscribe def once(self, event_name: str, callback: Callable) -> Callable: """Listen for an event exactly once.""" def event_listener(data: dict) -> None: unsub() callback(data) unsub = self.on(event_name, event_listener) return unsub def emit(self, event_name: str, data: dict) -> None: """Run all callbacks for an event.""" for listener in self._listeners.get(event_name, []).copy(): try: listener(data) except Exception: # pylint: disable=broad-exception-caught LOGGER.exception("Error handling event: %s", event_name) def _handle_event_protocol(self, event: Event) -> None: """Process an event based on event protocol.""" handler = getattr(self, f"handle_{event.type.replace(' ', '_')}", None) if handler is None: LOGGER.debug("Received unknown event: %s", event) return handler(event) # pylint: disable=not-callable zwave-js-server-python-0.63.0/zwave_js_server/exceptions.py000066400000000000000000000140041500374325600241460ustar00rootroot00000000000000"""Exceptions for zwave-js-server.""" from __future__ import annotations from typing import TYPE_CHECKING from .const import RssiError if TYPE_CHECKING: from .const import CommandClass from .model.value import Value from .model.version import VersionInfo class BaseZwaveJSServerError(Exception): """Base Zwave JS Server exception.""" class TransportError(BaseZwaveJSServerError): """Exception raised to represent transport errors.""" def __init__(self, message: str, error: Exception | None = None) -> None: """Initialize a transport error.""" super().__init__(message) self.error = error class ConnectionClosed(TransportError): """Exception raised when the connection is closed.""" class CannotConnect(TransportError): """Exception raised when failed to connect the client.""" def __init__(self, error: Exception) -> None: """Initialize a cannot connect error.""" super().__init__(f"{error}", error) class ConnectionFailed(TransportError): """Exception raised when an established connection fails.""" def __init__(self, error: Exception | None = None) -> None: """Initialize a connection failed error.""" if error is None: super().__init__("Connection failed.") return super().__init__(f"{error}", error) class NotFoundError(BaseZwaveJSServerError): """Exception that is raised when an entity can't be found.""" class NotConnected(BaseZwaveJSServerError): """Exception raised when not connected to client.""" class InvalidState(BaseZwaveJSServerError): """Exception raised when data gets in invalid state.""" class InvalidMessage(BaseZwaveJSServerError): """Exception raised when an invalid message is received.""" class InvalidServerVersion(BaseZwaveJSServerError): """Exception raised when connected to server with incompatible version.""" def __init__( self, version_info: VersionInfo, required_schema_version: int, message: str, ) -> None: """Initialize an invalid server version error.""" self.server_version = version_info.server_version self.server_max_schema_version = version_info.max_schema_version self.required_schema_version = required_schema_version super().__init__(message) class FailedCommand(BaseZwaveJSServerError): """When a command has failed.""" def __init__( self, message_id: str, error_code: str, msg: str | None = None ) -> None: """Initialize a failed command error.""" super().__init__( f"{error_code}: {msg}" if msg else f"Command failed: {error_code}" ) self.message_id = message_id self.error_code = error_code class FailedZWaveCommand(FailedCommand): """When a command has failed because of Z-Wave JS error.""" def __init__( self, message_id: str, zwave_error_code: int, zwave_error_message: str ): """Initialize a failed command error.""" super().__init__( message_id, "zwave_error", f"Z-Wave error {zwave_error_code} - {zwave_error_message}", ) self.zwave_error_code = zwave_error_code self.zwave_error_message = zwave_error_message class UnparseableValue(BaseZwaveJSServerError): """Exception raised when a value can't be parsed.""" class UnwriteableValue(BaseZwaveJSServerError): """Exception raised when trying to change a read only Value.""" class InvalidNewValue(BaseZwaveJSServerError): """Exception raised when target new value is invalid based on Value metadata.""" class ValueTypeError(BaseZwaveJSServerError): """Exception raised when target Zwave value is the wrong type.""" class SetValueFailed(BaseZwaveJSServerError): """ Exception raise when setting a value fails. Refer to https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for possible reasons. """ class BulkSetConfigParameterFailed(BaseZwaveJSServerError): """ Exception raised when bulk setting a config parameter fails. Derived from another exception. """ class InvalidCommandClass(BaseZwaveJSServerError): """Exception raised when Zwave Value has an invalid command class.""" def __init__(self, value: Value, command_class: CommandClass) -> None: """Initialize an invalid Command Class error.""" self.value = value self.command_class = command_class super().__init__( f"Value {value} does not match expected command class: {command_class}" ) class UnknownValueData(BaseZwaveJSServerError): """ Exception raised when Zwave Value has data that the library can't parse. This can be caused by an upstream issue with the driver, or missing support in the library. """ def __init__(self, value: Value, path: str) -> None: """Initialize an unknown data error.""" self.value = value self.path = path super().__init__( f"Value {value} has unknown data in the following location: {path}. " f"A reinterview of node {value.node} may correct this issue, but if it " "doesn't, please report this issue as it may be caused by either an " "upstream issue with the driver or missing support for this data in the " "library" ) class RssiErrorReceived(BaseZwaveJSServerError): """Exception raised when an RSSI error is received.""" def __init__(self, error: RssiError) -> None: """Initialize an RSSI error.""" self.error = error super().__init__() class RepeaterRssiErrorReceived(BaseZwaveJSServerError): """Exception raised when an RSSI error is received in list of RSSIs.""" def __init__(self, rssi_list: list[int]) -> None: """Initialize an RSSI error.""" self.rssi_list = rssi_list rssi_errors = [item.value for item in RssiError] self.error_list = [ RssiError(rssi_) if rssi_ in rssi_errors else None for rssi_ in rssi_list ] super().__init__() zwave-js-server-python-0.63.0/zwave_js_server/firmware.py000066400000000000000000000045151500374325600236070ustar00rootroot00000000000000"""Firmware update helper.""" from __future__ import annotations import asyncio import aiohttp from .client import Client from .model.controller.firmware import ( ControllerFirmwareUpdateData, ControllerFirmwareUpdateResult, ) from .model.node import Node from .model.node.firmware import NodeFirmwareUpdateData, NodeFirmwareUpdateResult async def update_firmware( url: str, node: Node, updates: list[NodeFirmwareUpdateData], session: aiohttp.ClientSession, additional_user_agent_components: dict[str, str] | None = None, ) -> NodeFirmwareUpdateResult: """Send updateFirmware command to Node.""" client = Client( url, session, additional_user_agent_components=additional_user_agent_components ) await client.connect() await client.initialize() receive_task = asyncio.get_running_loop().create_task(client.receive_until_closed()) cmd = { "command": "node.update_firmware", "nodeId": node.node_id, "updates": [update.to_dict() for update in updates], } data = await client.async_send_command(cmd, require_schema=29) await client.disconnect() if not receive_task.done(): receive_task.cancel() return NodeFirmwareUpdateResult(node, data["result"]) async def controller_firmware_update_otw( url: str, firmware_file: ControllerFirmwareUpdateData, session: aiohttp.ClientSession, additional_user_agent_components: dict[str, str] | None = None, ) -> ControllerFirmwareUpdateResult: """ Send firmwareUpdateOTW command to Controller. Sending the wrong firmware to a controller can brick it and make it unrecoverable. Consumers of this library should build mechanisms to ensure that users understand the risks. """ client = Client( url, session, additional_user_agent_components=additional_user_agent_components ) await client.connect() await client.initialize() receive_task = asyncio.get_running_loop().create_task(client.receive_until_closed()) data = await client.async_send_command( { "command": "controller.firmware_update_otw", **firmware_file.to_dict(), }, require_schema=29, ) await client.disconnect() if not receive_task.done(): receive_task.cancel() return ControllerFirmwareUpdateResult(data["result"]) zwave-js-server-python-0.63.0/zwave_js_server/model/000077500000000000000000000000001500374325600225145ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/model/__init__.py000066400000000000000000000001731500374325600246260ustar00rootroot00000000000000"""Provide a model based on Z-Wave JS. The model pieces here should map 1:1 with the model of Z-Wave JS upstream API. """ zwave-js-server-python-0.63.0/zwave_js_server/model/association.py000066400000000000000000000015561500374325600254110ustar00rootroot00000000000000"""Provide a model for the association.""" from __future__ import annotations from dataclasses import dataclass, field from typing import TYPE_CHECKING if TYPE_CHECKING: from .controller import Controller from .node import Node @dataclass class AssociationGroup: """Represent a association group dict type.""" max_nodes: int is_lifeline: bool multi_channel: bool label: str profile: int | None = None issued_commands: dict[int, list[int]] = field(default_factory=dict) @dataclass class AssociationAddress: """Represent a association dict type.""" controller: Controller node_id: int endpoint: int | None = None @property def node(self) -> Node | None: """Return the node.""" if self.node_id in self.controller.nodes: return self.controller.nodes[self.node_id] return None zwave-js-server-python-0.63.0/zwave_js_server/model/command_class.py000066400000000000000000000025621500374325600256760ustar00rootroot00000000000000""" Model for Zwave Command Class Info. https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=commandclasses """ from __future__ import annotations from typing import TypedDict from ..const import CommandClass class CommandClassInfoDataType(TypedDict): """Represent a command class info data dict type.""" id: int name: str version: int isSecure: bool class CommandClassInfo: """Model for a Zwave CommandClass Info.""" def __init__(self, data: CommandClassInfoDataType) -> None: """Initialize.""" self.data = data @property def id(self) -> int: """Return CommandClass ID.""" return self.data["id"] @property def command_class(self) -> CommandClass: """Return CommandClass.""" return CommandClass(self.id) @property def name(self) -> str: """Return friendly name for CommandClass.""" return self.data["name"] @property def version(self) -> int: """Return the CommandClass version used on this node/endpoint.""" return self.data["version"] @property def is_secure(self) -> bool: """Return if the CommandClass is used securely on this node/endpoint.""" return self.data["isSecure"] def to_dict(self) -> CommandClassInfoDataType: """Create a dictionary from itself.""" return self.data.copy() zwave-js-server-python-0.63.0/zwave_js_server/model/config_manager/000077500000000000000000000000001500374325600254535ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/model/config_manager/__init__.py000066400000000000000000000023361500374325600275700ustar00rootroot00000000000000""" Model for Z-Wave JS config manager. https://zwave-js.github.io/node-zwave-js/#/api/config-manager """ from __future__ import annotations from typing import TYPE_CHECKING, Any, Optional from ..device_config import DeviceConfig if TYPE_CHECKING: from ...client import Client class ConfigManager: """Model for the Z-Wave JS config manager.""" def __init__(self, client: Client) -> None: """Initialize.""" self._client = client async def lookup_device( self, manufacturer_id: int, product_type: int, product_id: int, firmware_version: Optional[str] = None, ) -> DeviceConfig | None: """Look up the definition of a given device in the configuration DB.""" cmd: dict[str, Any] = { "command": "config_manager.lookup_device", "manufacturerId": manufacturer_id, "productType": product_type, "productId": product_id, } if firmware_version is not None: cmd["firmwareVersion"] = firmware_version data = await self._client.async_send_command(cmd) if not data or not (config := data.get("config")): return None return DeviceConfig(config) zwave-js-server-python-0.63.0/zwave_js_server/model/controller/000077500000000000000000000000001500374325600246775ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/model/controller/__init__.py000066400000000000000000001116221500374325600270130ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS controller.""" from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Literal, cast from zwave_js_server.model.node.firmware import NodeFirmwareUpdateInfo from ...const import ( MINIMUM_QR_STRING_LENGTH, AssociationCheckResult, ControllerStatus, ExclusionStrategy, InclusionState, InclusionStrategy, NodeType, QRCodeVersion, RFRegion, RemoveNodeReason, ZwaveFeature, ) from ...event import Event, EventBase from ...util.helpers import convert_base64_to_bytes, convert_bytes_to_base64 from ..association import AssociationAddress, AssociationGroup from ..node import Node from ..node.firmware import NodeFirmwareUpdateResult from .data_model import ControllerDataType from .event_model import CONTROLLER_EVENT_MODEL_MAP from .firmware import ControllerFirmwareUpdateProgress, ControllerFirmwareUpdateResult from .inclusion_and_provisioning import ( InclusionGrant, ProvisioningEntry, QRProvisioningInformation, ) from .rebuild_routes import ( RebuildRoutesOptions, RebuildRoutesOptionsDataType, RebuildRoutesStatus, ) from .statistics import ( ControllerLifelineRoutes, ControllerStatistics, ControllerStatisticsDataType, ) if TYPE_CHECKING: from ...client import Client DEFAULT_CONTROLLER_STATISTICS = ControllerStatisticsDataType( messagesTX=0, messagesRX=0, messagesDroppedTX=0, messagesDroppedRX=0, NAK=0, CAN=0, timeoutACK=0, timeoutResponse=0, timeoutCallback=0, ) @dataclass class NVMProgress: """Class to represent an NVM backup/restore progress event.""" bytes_read_or_written: int total_bytes: int class Controller(EventBase): """Represent a Z-Wave JS controller.""" def __init__(self, client: Client, state: dict) -> None: """Initialize controller.""" super().__init__() self.client = client self.nodes: dict[int, Node] = {} self._rebuild_routes_progress: dict[Node, RebuildRoutesStatus] | None = None self._last_rebuild_routes_result: dict[Node, RebuildRoutesStatus] | None = None self._statistics = ControllerStatistics(DEFAULT_CONTROLLER_STATISTICS) self._firmware_update_progress: ControllerFirmwareUpdateProgress | None = None for node_state in state["nodes"]: node = Node(client, node_state) self.nodes[node.node_id] = node self.update(state["controller"]) def __repr__(self) -> str: """Return the representation.""" return f"{type(self).__name__}(home_id={self.home_id})" def __hash__(self) -> int: """Return the hash.""" return hash(self.home_id) def __eq__(self, other: object) -> bool: """Return whether this instance equals another.""" if not isinstance(other, Controller): return False return self.home_id == other.home_id def _generate_rebuild_routes_status( self, data: dict[str, str] ) -> dict[Node, RebuildRoutesStatus]: """Generate rebuild routes status.""" return { self.nodes[int(node_id)]: RebuildRoutesStatus(status) for node_id, status in data.items() } @property def sdk_version(self) -> str | None: """Return sdk_version.""" return self.data.get("sdkVersion") @property def controller_type(self) -> int | None: """Return controller_type.""" return self.data.get("type") @property def home_id(self) -> int | None: """Return home_id.""" return self.data.get("homeId") @property def own_node_id(self) -> int | None: """Return own_node_id.""" return self.data.get("ownNodeId") @property def own_node(self) -> Node | None: """Return own_node.""" if self.own_node_id is None: return None return self.nodes.get(self.own_node_id) @property def is_primary(self) -> bool | None: """Return is_primary.""" return self.data.get("isPrimary") @property def is_using_home_id_from_other_network(self) -> bool | None: """Return is_using_home_id_from_other_network.""" return self.data.get("isUsingHomeIdFromOtherNetwork") @property def is_SIS_present(self) -> bool | None: # pylint: disable=invalid-name """Return is_SIS_present.""" return self.data.get("isSISPresent") @property def was_real_primary(self) -> bool | None: """Return was_real_primary.""" return self.data.get("wasRealPrimary") @property def is_suc(self) -> bool | None: """Return is_suc.""" return self.data.get("isSUC") @property def node_type(self) -> NodeType | None: """Return node_type.""" if (node_type := self.data.get("nodeType")) is not None: return NodeType(node_type) return None @property def firmware_version(self) -> str | None: """Return firmware_version.""" return self.data.get("firmwareVersion") @property def manufacturer_id(self) -> int | None: """Return manufacturer_id.""" return self.data.get("manufacturerId") @property def product_type(self) -> int | None: """Return product_type.""" return self.data.get("productType") @property def product_id(self) -> int | None: """Return product_id.""" return self.data.get("productId") @property def supported_function_types(self) -> list[int]: """Return supported_function_types.""" return self.data.get("supportedFunctionTypes", []) @property def suc_node_id(self) -> int | None: """Return suc_node_id.""" return self.data.get("sucNodeId") @property def supports_timers(self) -> bool | None: """Return supports_timers.""" return self.data.get("supportsTimers") @property def is_rebuilding_routes(self) -> bool | None: """Return is_rebuilding_routes.""" return self.data.get("isRebuildingRoutes") @property def statistics(self) -> ControllerStatistics: """Return statistics property.""" return self._statistics @property def rebuild_routes_progress(self) -> dict[Node, RebuildRoutesStatus] | None: """Return rebuild routes progress state.""" return self._rebuild_routes_progress @property def last_rebuild_routes_result(self) -> dict[Node, RebuildRoutesStatus] | None: """Return the last rebuild routes result.""" return self._last_rebuild_routes_result @property def inclusion_state(self) -> InclusionState: """Return inclusion state.""" return InclusionState(self.data["inclusionState"]) @property def rf_region(self) -> RFRegion | None: """Return RF region of controller.""" if (rf_region := self.data.get("rfRegion")) is None: return None return RFRegion(rf_region) @property def firmware_update_progress(self) -> ControllerFirmwareUpdateProgress | None: """Return firmware update progress.""" return self._firmware_update_progress @property def status(self) -> ControllerStatus: """Return status.""" return ControllerStatus(self.data["status"]) @property def supports_long_range(self) -> bool | None: """Return whether controller supports long range or not.""" return self.data.get("supportsLongRange") def update(self, data: ControllerDataType) -> None: """Update controller data.""" self.data = data self._statistics = ControllerStatistics( self.data.get("statistics", DEFAULT_CONTROLLER_STATISTICS) ) if "rebuildRoutesProgress" in self.data: self._rebuild_routes_progress = self._generate_rebuild_routes_status( self.data["rebuildRoutesProgress"] ) async def async_begin_inclusion( self, inclusion_strategy: Literal[ InclusionStrategy.DEFAULT, InclusionStrategy.SECURITY_S0, InclusionStrategy.SECURITY_S2, InclusionStrategy.INSECURE, ], force_security: bool | None = None, provisioning: str | ProvisioningEntry | QRProvisioningInformation | None = None, dsk: str | None = None, ) -> bool: """Send beginInclusion command to Controller.""" # Most functionality was introduced in Schema 8 require_schema = 8 options: dict[str, Any] = {"strategy": inclusion_strategy} # forceSecurity can only be used with the default inclusion strategy if force_security is not None: if inclusion_strategy != InclusionStrategy.DEFAULT: raise ValueError( "`forceSecurity` option is only supported with inclusion_strategy=" "DEFAULT" ) options["forceSecurity"] = force_security # provisioning can only be used with the S2 inclusion strategy and may need # additional processing if provisioning is not None: if inclusion_strategy != InclusionStrategy.SECURITY_S2: raise ValueError( "`provisioning` option is only supported with inclusion_strategy=" "SECURITY_S2" ) if dsk is not None: raise ValueError("Only one of `provisioning` and `dsk` can be provided") # Provisioning option was introduced in Schema 11 require_schema = 11 # String is assumed to be the QR code string so we can pass as is if isinstance(provisioning, str): if len( provisioning ) < MINIMUM_QR_STRING_LENGTH or not provisioning.startswith("90"): raise ValueError( f"QR code string must be at least {MINIMUM_QR_STRING_LENGTH} " "characters long and start with `90`" ) options["provisioning"] = provisioning # If we get a Smart Start QR code, we provision the node and return because # inclusion is over elif ( isinstance(provisioning, QRProvisioningInformation) and provisioning.version == QRCodeVersion.SMART_START ): raise ValueError( "Smart Start QR codes can't use the normal inclusion process. Use " "the provision_smart_start_node command to provision this device." ) # Otherwise we assume the data is ProvisioningEntry or # QRProvisioningInformation that is not a Smart Start QR code else: options["provisioning"] = provisioning.to_dict() if dsk is not None: if inclusion_strategy != InclusionStrategy.SECURITY_S2: raise ValueError( "`dsk` option is only supported with inclusion_strategy=SECURITY_S2" ) require_schema = 25 options["dsk"] = dsk data = await self.client.async_send_command( { "command": "controller.begin_inclusion", "options": options, }, require_schema=require_schema, ) return cast(bool, data["success"]) async def async_provision_smart_start_node( self, provisioning_info: ProvisioningEntry | QRProvisioningInformation | str, ) -> None: """Send provisionSmartStartNode command to Controller.""" if ( isinstance(provisioning_info, QRProvisioningInformation) and provisioning_info.version == QRCodeVersion.S2 ): raise ValueError( "An S2 QR Code can't be used to pre-provision a Smart Start node" ) await self.client.async_send_command( { "command": "controller.provision_smart_start_node", "entry": ( provisioning_info if isinstance(provisioning_info, str) else provisioning_info.to_dict() ), }, require_schema=11, ) async def async_unprovision_smart_start_node( self, dsk_or_node_id: int | str ) -> None: """Send unprovisionSmartStartNode command to Controller.""" await self.client.async_send_command( { "command": "controller.unprovision_smart_start_node", "dskOrNodeId": dsk_or_node_id, }, require_schema=11, ) async def async_get_provisioning_entry( self, dsk_or_node_id: int | str ) -> ProvisioningEntry | None: """Send getProvisioningEntry command to Controller.""" data = await self.client.async_send_command( { "command": "controller.get_provisioning_entry", "dskOrNodeId": dsk_or_node_id, }, require_schema=17, ) if "entry" in data: return ProvisioningEntry.from_dict(data["entry"]) return None async def async_get_provisioning_entries(self) -> list[ProvisioningEntry]: """Send getProvisioningEntries command to Controller.""" data = await self.client.async_send_command( { "command": "controller.get_provisioning_entries", }, require_schema=11, ) return [ProvisioningEntry.from_dict(entry) for entry in data.get("entries", [])] async def async_stop_inclusion(self) -> bool: """Send stopInclusion command to Controller.""" data = await self.client.async_send_command( {"command": "controller.stop_inclusion"} ) return cast(bool, data["success"]) async def async_cancel_secure_bootstrap_s2(self) -> None: """Send cancelSecureBootstrapS2 command to Controller.""" await self.client.async_send_command( {"command": "controller.cancel_secure_bootstrap_s2"}, require_schema=40 ) async def async_begin_exclusion( self, strategy: ExclusionStrategy | None = None ) -> bool: """Send beginExclusion command to Controller.""" payload: dict[str, str | dict[str, ExclusionStrategy]] = { "command": "controller.begin_exclusion" } if strategy is not None: payload["options"] = {"strategy": strategy} data = await self.client.async_send_command(payload, require_schema=22) return cast(bool, data["success"]) async def async_stop_exclusion(self) -> bool: """Send stopExclusion command to Controller.""" data = await self.client.async_send_command( {"command": "controller.stop_exclusion"} ) return cast(bool, data["success"]) async def async_remove_failed_node(self, node: Node) -> None: """Send removeFailedNode command to Controller.""" await self.client.async_send_command( {"command": "controller.remove_failed_node", "nodeId": node.node_id} ) async def async_replace_failed_node( self, node: Node, inclusion_strategy: Literal[ InclusionStrategy.DEFAULT, InclusionStrategy.SECURITY_S0, InclusionStrategy.SECURITY_S2, InclusionStrategy.INSECURE, ], force_security: bool | None = None, provisioning: str | ProvisioningEntry | QRProvisioningInformation | None = None, ) -> bool: """Send replaceFailedNode command to Controller.""" # Most functionality was introduced in Schema 8 require_schema = 8 options: dict[str, Any] = {"strategy": inclusion_strategy} # forceSecurity can only be used with the default inclusion strategy if force_security is not None: if inclusion_strategy != InclusionStrategy.DEFAULT: raise ValueError( "`forceSecurity` option is only supported with inclusion_strategy=" "DEFAULT" ) options["forceSecurity"] = force_security # provisioning can only be used with the S2 inclusion strategy and may need # additional processing if provisioning is not None: if inclusion_strategy != InclusionStrategy.SECURITY_S2: raise ValueError( "`provisioning` option is only supported with inclusion_strategy=" "SECURITY_S2" ) # Provisioning option was introduced in Schema 11 require_schema = 11 # String is assumed to be the QR code string so we can pass as is if isinstance(provisioning, str): if len( provisioning ) < MINIMUM_QR_STRING_LENGTH or not provisioning.startswith("90"): raise ValueError( f"QR code string must be at least {MINIMUM_QR_STRING_LENGTH} " "characters long and start with `90`" ) options["provisioning"] = provisioning # Otherwise we assume the data is ProvisioningEntry or # QRProvisioningInformation else: options["provisioning"] = provisioning.to_dict() data = await self.client.async_send_command( { "command": "controller.replace_failed_node", "nodeId": node.node_id, "options": options, }, require_schema=require_schema, ) return cast(bool, data["success"]) async def async_rebuild_node_routes(self, node: Node) -> bool: """Send rebuildNodeRoutes command to Controller.""" data = await self.client.async_send_command( {"command": "controller.rebuild_node_routes", "nodeId": node.node_id}, require_schema=32, ) return cast(bool, data["success"]) async def async_begin_rebuilding_routes( self, options: RebuildRoutesOptions | None = None ) -> bool: """Send beginRebuildingRoutes command to Controller.""" msg: dict[str, str | RebuildRoutesOptionsDataType] = { "command": "controller.begin_rebuilding_routes" } if options: msg["options"] = options.to_dict() data = await self.client.async_send_command(msg, require_schema=32) return cast(bool, data["success"]) async def async_stop_rebuilding_routes(self) -> bool: """Send stopRebuildingRoutes command to Controller.""" data = await self.client.async_send_command( {"command": "controller.stop_rebuilding_routes"}, require_schema=32 ) success = cast(bool, data["success"]) if success: self._rebuild_routes_progress = None self.data["isRebuildingRoutes"] = False return success async def async_is_failed_node(self, node: Node) -> bool: """Send isFailedNode command to Controller.""" data = await self.client.async_send_command( {"command": "controller.is_failed_node", "nodeId": node.node_id} ) return cast(bool, data["failed"]) async def async_get_association_groups( self, source: AssociationAddress ) -> dict[int, AssociationGroup]: """Send getAssociationGroups command to Controller.""" source_data = {"nodeId": source.node_id} if source.endpoint is not None: source_data["endpoint"] = source.endpoint data = await self.client.async_send_command( { "command": "controller.get_association_groups", **source_data, } ) groups = {} for key, group in data["groups"].items(): groups[int(key)] = AssociationGroup( max_nodes=group["maxNodes"], is_lifeline=group["isLifeline"], multi_channel=group["multiChannel"], label=group["label"], profile=group.get("profile"), issued_commands=group.get("issuedCommands", {}), ) return groups async def async_get_associations( self, source: AssociationAddress ) -> dict[int, list[AssociationAddress]]: """Send getAssociations command to Controller.""" source_data = {"nodeId": source.node_id} if source.endpoint is not None: source_data["endpoint"] = source.endpoint data = await self.client.async_send_command( { "command": "controller.get_associations", **source_data, } ) associations = {} for key, association_addresses in data["associations"].items(): associations[int(key)] = [ AssociationAddress( self, node_id=association_address["nodeId"], endpoint=association_address.get("endpoint"), ) for association_address in association_addresses ] return associations async def async_check_association( self, source: AssociationAddress, group: int, association: AssociationAddress ) -> AssociationCheckResult: """Send checkAssociation command to Controller.""" source_data = {"nodeId": source.node_id} if source.endpoint is not None: source_data["endpoint"] = source.endpoint association_data = {"nodeId": association.node_id} if association.endpoint is not None: association_data["endpoint"] = association.endpoint data = await self.client.async_send_command( { "command": "controller.check_association", **source_data, "group": group, "association": association_data, }, require_schema=37, ) return AssociationCheckResult(data["result"]) async def async_add_associations( self, source: AssociationAddress, group: int, associations: list[AssociationAddress], wait_for_result: bool = False, ) -> None: """Send addAssociations command to Controller.""" source_data = {"nodeId": source.node_id} if source.endpoint is not None: source_data["endpoint"] = source.endpoint associations_data = [] for association in associations: association_data = {"nodeId": association.node_id} if association.endpoint is not None: association_data["endpoint"] = association.endpoint associations_data.append(association_data) cmd = { "command": "controller.add_associations", **source_data, "group": group, "associations": associations_data, } if wait_for_result: await self.client.async_send_command(cmd) else: await self.client.async_send_command_no_wait(cmd) async def async_remove_associations( self, source: AssociationAddress, group: int, associations: list[AssociationAddress], wait_for_result: bool = False, ) -> None: """Send removeAssociations command to Controller.""" source_data = {"nodeId": source.node_id} if source.endpoint is not None: source_data["endpoint"] = source.endpoint associations_data = [] for association in associations: association_data = {"nodeId": association.node_id} if association.endpoint is not None: association_data["endpoint"] = association.endpoint associations_data.append(association_data) cmd = { "command": "controller.remove_associations", **source_data, "group": group, "associations": associations_data, } if wait_for_result: await self.client.async_send_command(cmd) else: await self.client.async_send_command_no_wait(cmd) async def async_remove_node_from_all_associations( self, node: Node, wait_for_result: bool = False, ) -> None: """Send removeNodeFromAllAssociations command to Controller.""" cmd = { "command": "controller.remove_node_from_all_associations", "nodeId": node.node_id, } if wait_for_result: await self.client.async_send_command(cmd) else: await self.client.async_send_command_no_wait(cmd) async def async_get_node_neighbors(self, node: Node) -> list[int]: """Send getNodeNeighbors command to Controller to get node's neighbors.""" data = await self.client.async_send_command( { "command": "controller.get_node_neighbors", "nodeId": node.node_id, } ) return cast(list[int], data["neighbors"]) async def async_grant_security_classes( self, inclusion_grant: InclusionGrant ) -> None: """Send grantSecurityClasses command to Controller.""" await self.client.async_send_command( { "command": "controller.grant_security_classes", "inclusionGrant": inclusion_grant.to_dict(), } ) async def async_validate_dsk_and_enter_pin(self, pin: str) -> None: """Send validateDSKAndEnterPIN command to Controller.""" await self.client.async_send_command( { "command": "controller.validate_dsk_and_enter_pin", "pin": pin, } ) async def async_supports_feature(self, feature: ZwaveFeature) -> bool | None: """ Send supportsFeature command to Controller. When None is returned it means the driver does not yet know whether the controller supports the input feature. """ data = await self.client.async_send_command( {"command": "controller.supports_feature", "feature": feature.value}, require_schema=12, ) return cast(bool | None, data.get("supported")) async def async_get_state(self) -> ControllerDataType: """Get controller state.""" data = await self.client.async_send_command( {"command": "controller.get_state"}, require_schema=14 ) return cast(ControllerDataType, data["state"]) async def async_backup_nvm_raw(self) -> bytes: """Send backupNVMRaw command to Controller.""" data = await self.client.async_send_command( {"command": "controller.backup_nvm_raw"}, require_schema=14 ) return convert_base64_to_bytes(data["nvmData"]) async def async_restore_nvm(self, file: bytes) -> None: """Send restoreNVM command to Controller.""" await self.client.async_send_command( { "command": "controller.restore_nvm", "nvmData": convert_bytes_to_base64(file), }, require_schema=14, ) async def async_backup_nvm_raw_base64(self) -> str: """Send backupNVMRaw command to Controller and return base64 string directly.""" data = await self.client.async_send_command( {"command": "controller.backup_nvm_raw"}, require_schema=14 ) return data["nvmData"] async def async_restore_nvm_base64(self, base64_data: str) -> None: """Send restoreNVM command to Controller with base64 data directly.""" await self.client.async_send_command( { "command": "controller.restore_nvm", "nvmData": base64_data, }, require_schema=14, ) async def async_get_power_level(self) -> dict[str, int]: """Send getPowerlevel command to Controller.""" data = await self.client.async_send_command( {"command": "controller.get_powerlevel"}, require_schema=14 ) return { "power_level": data["powerlevel"], "measured_0_dbm": data["measured0dBm"], } async def async_set_power_level( self, power_level: int, measured_0_dbm: int ) -> bool: """Send setPowerlevel command to Controller.""" data = await self.client.async_send_command( { "command": "controller.set_powerlevel", "powerlevel": power_level, "measured0dBm": measured_0_dbm, }, require_schema=14, ) return cast(bool, data["success"]) async def async_get_rf_region(self) -> RFRegion: """Send getRFRegion command to Controller.""" data = await self.client.async_send_command( {"command": "controller.get_rf_region"}, require_schema=14 ) return RFRegion(data["region"]) async def async_set_rf_region(self, rf_region: RFRegion) -> bool: """Send setRFRegion command to Controller.""" data = await self.client.async_send_command( { "command": "controller.set_rf_region", "region": rf_region.value, }, require_schema=14, ) return cast(bool, data["success"]) async def async_get_known_lifeline_routes( self, ) -> dict[Node, ControllerLifelineRoutes]: """Send getKnownLifelineRoutes command to Controller.""" data = await self.client.async_send_command( {"command": "controller.get_known_lifeline_routes"}, require_schema=16 ) return { self.nodes[int(node_id)]: ControllerLifelineRoutes( self.client, lifeline_routes ) for node_id, lifeline_routes in data["routes"].items() } async def async_is_any_ota_firmware_update_in_progress(self) -> bool: """ Send isAnyOTAFirmwareUpdateInProgress command to Controller. If `True`, a firmware update is in progress on at least one node. """ data = await self.client.async_send_command( {"command": "controller.is_any_ota_firmware_update_in_progress"}, require_schema=21, ) assert data return cast(bool, data["progress"]) async def async_get_available_firmware_updates( self, node: Node, api_key: str, include_prereleases: bool = True ) -> list[NodeFirmwareUpdateInfo]: """Send getAvailableFirmwareUpdates command to Controller.""" data = await self.client.async_send_command( { "command": "controller.get_available_firmware_updates", "nodeId": node.node_id, "apiKey": api_key, "includePrereleases": include_prereleases, }, require_schema=32, ) assert data return [NodeFirmwareUpdateInfo.from_dict(update) for update in data["updates"]] async def async_firmware_update_ota( self, node: Node, update_info: NodeFirmwareUpdateInfo ) -> NodeFirmwareUpdateResult: """Send firmwareUpdateOTA command to Controller.""" data = await self.client.async_send_command( { "command": "controller.firmware_update_ota", "nodeId": node.node_id, "updateInfo": update_info.to_dict(), }, require_schema=32, ) return NodeFirmwareUpdateResult(node, data["result"]) async def async_is_firmware_update_in_progress(self) -> bool: """Send isFirmwareUpdateInProgress command to Controller.""" data = await self.client.async_send_command( {"command": "controller.is_firmware_update_in_progress"}, require_schema=26 ) return cast(bool, data["progress"]) def receive_event(self, event: Event) -> None: """Receive an event.""" if event.data["source"] == "node": node = self.nodes.get(event.data["nodeId"]) if node is None: # TODO handle event for unknown node pass else: node.receive_event(event) return if event.data["source"] != "controller": # TODO decide what to do here print( "Controller doesn't know how to handle/forward this event: " f"{event.data}" ) CONTROLLER_EVENT_MODEL_MAP[event.type].from_dict(event.data) self._handle_event_protocol(event) event.data["controller"] = self self.emit(event.type, event.data) def handle_firmware_update_progress(self, event: Event) -> None: """Process a firmware update progress event.""" self._firmware_update_progress = event.data["firmware_update_progress"] = ( ControllerFirmwareUpdateProgress(event.data["progress"]) ) def handle_firmware_update_finished(self, event: Event) -> None: """Process a firmware update finished event.""" self._firmware_update_progress = None event.data["firmware_update_finished"] = ControllerFirmwareUpdateResult( event.data["result"] ) def handle_inclusion_failed(self, event: Event) -> None: """Process an inclusion failed event.""" def handle_exclusion_failed(self, event: Event) -> None: """Process an exclusion failed event.""" def handle_inclusion_started(self, event: Event) -> None: """Process an inclusion started event.""" def handle_inclusion_state_changed(self, event: Event) -> None: """Process an inclusion state changed event.""" self.data["inclusionState"] = event.data["state"] def handle_exclusion_started(self, event: Event) -> None: """Process an exclusion started event.""" def handle_inclusion_stopped(self, event: Event) -> None: """Process an inclusion stopped event.""" def handle_exclusion_stopped(self, event: Event) -> None: """Process an exclusion stopped event.""" def handle_node_found(self, event: Event) -> None: """Process a node found event.""" def handle_node_added(self, event: Event) -> None: """Process a node added event.""" node = event.data["node"] = Node(self.client, event.data["node"]) self.nodes[node.node_id] = node def handle_node_removed(self, event: Event) -> None: """Process a node removed event.""" event.data["reason"] = RemoveNodeReason(event.data["reason"]) event.data["node"] = self.nodes.pop(event.data["node"]["nodeId"]) # Remove client from node since it's no longer connected to the controller event.data["node"].client = None def handle_rebuild_routes_progress(self, event: Event) -> None: """Process a rebuild routes progress event.""" self._rebuild_routes_progress = self._generate_rebuild_routes_status( event.data["progress"] ) self.data["isRebuildingRoutes"] = True def handle_rebuild_routes_done(self, event: Event) -> None: """Process a rebuild routes done event.""" self._last_rebuild_routes_result = self._generate_rebuild_routes_status( event.data["result"] ) self._rebuild_routes_progress = None self.data["isRebuildingRoutes"] = False def handle_statistics_updated(self, event: Event) -> None: """Process a statistics updated event.""" self.data["statistics"] = statistics = event.data["statistics"] self._statistics = event.data["statistics_updated"] = ControllerStatistics( statistics ) def handle_grant_security_classes(self, event: Event) -> None: """Process a grant security classes event.""" event.data["requested_grant"] = InclusionGrant.from_dict( event.data["requested"] ) def handle_validate_dsk_and_enter_pin(self, event: Event) -> None: """Process a validate dsk and enter pin event.""" def handle_inclusion_aborted(self, event: Event) -> None: """Process an inclusion aborted event.""" def handle_nvm_backup_progress(self, event: Event) -> None: """Process a nvm backup progress event.""" event.data["nvm_backup_progress"] = NVMProgress( event.data["bytesRead"], event.data["total"] ) def handle_nvm_convert_progress(self, event: Event) -> None: """Process a nvm convert progress event.""" event.data["nvm_convert_progress"] = NVMProgress( event.data["bytesRead"], event.data["total"] ) def handle_nvm_restore_progress(self, event: Event) -> None: """Process a nvm restore progress event.""" event.data["nvm_restore_progress"] = NVMProgress( event.data["bytesWritten"], event.data["total"] ) def handle_identify(self, event: Event) -> None: """Process an identify event.""" # TODO handle event for unknown node if node := self.nodes.get(event.data["nodeId"]): event.data["node"] = node def handle_status_changed(self, event: Event) -> None: """Process a status changed event.""" self.data["status"] = event.data["status"] event.data["status"] = ControllerStatus(event.data["status"]) zwave-js-server-python-0.63.0/zwave_js_server/model/controller/data_model.py000066400000000000000000000015231500374325600273430ustar00rootroot00000000000000"""Data model for a Z-Wave JS controller.""" from __future__ import annotations from typing import TypedDict from .statistics import ControllerStatisticsDataType class ControllerDataType(TypedDict, total=False): """Represent a controller data dict type.""" sdkVersion: str type: int homeId: int ownNodeId: int isPrimary: bool isSUC: bool nodeType: int isUsingHomeIdFromOtherNetwork: bool isSISPresent: bool wasRealPrimary: bool firmwareVersion: str manufacturerId: int productType: int productId: int supportedFunctionTypes: list[int] sucNodeId: int supportsTimers: bool isRebuildingRoutes: bool statistics: ControllerStatisticsDataType inclusionState: int rfRegion: int status: int rebuildRoutesProgress: dict[str, str] supportsLongRange: bool zwave-js-server-python-0.63.0/zwave_js_server/model/controller/event_model.py000066400000000000000000000247701500374325600275640ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS controller's events.""" from __future__ import annotations from typing import Literal, TypedDict from ...const import InclusionState, InclusionStrategy, RemoveNodeReason from ...event import BaseEventModel from ..node.data_model import FoundNodeDataType, NodeDataType from .firmware import ( ControllerFirmwareUpdateProgressDataType, ControllerFirmwareUpdateResultDataType, ) from .inclusion_and_provisioning import InclusionGrantDataType from .statistics import ControllerStatisticsDataType class InclusionResultDataType(TypedDict, total=False): """Represent an inclusion result data dict type.""" lowSecurity: bool # required lowSecurityReason: int class BaseControllerEventModel(BaseEventModel): """Base model for a controller event.""" source: Literal["controller"] class ExclusionFailedEventModel(BaseControllerEventModel): """Model for `exclusion failed` event data.""" event: Literal["exclusion failed"] class ExclusionStartedEventModel(BaseControllerEventModel): """Model for `exclusion started` event data.""" event: Literal["exclusion started"] class ExclusionStoppedEventModel(BaseControllerEventModel): """Model for `exclusion stopped` event data.""" event: Literal["exclusion stopped"] class FirmwareUpdateFinishedEventModel(BaseControllerEventModel): """Model for `firmware update finished` event data.""" event: Literal["firmware update finished"] result: ControllerFirmwareUpdateResultDataType @classmethod def from_dict(cls, data: dict) -> FirmwareUpdateFinishedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], result=data["result"], ) class FirmwareUpdateProgressEventModel(BaseControllerEventModel): """Model for `firmware update progress` event data.""" event: Literal["firmware update progress"] progress: ControllerFirmwareUpdateProgressDataType @classmethod def from_dict(cls, data: dict) -> FirmwareUpdateProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], progress=data["progress"], ) class GrantSecurityClassesEventModel(BaseControllerEventModel): """Model for `grant security classes` event data.""" event: Literal["grant security classes"] requested: InclusionGrantDataType @classmethod def from_dict(cls, data: dict) -> GrantSecurityClassesEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], requested=data["requested"], ) class RebuildRoutesDoneEventModel(BaseControllerEventModel): """Model for `rebuild routes done` event data.""" event: Literal["rebuild routes done"] result: dict[str, str] @classmethod def from_dict(cls, data: dict) -> RebuildRoutesDoneEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], result=data["result"], ) class RebuildRoutesProgressEventModel(BaseControllerEventModel): """Model for `rebuild routes progress` event data.""" event: Literal["rebuild routes progress"] progress: dict[str, str] @classmethod def from_dict(cls, data: dict) -> RebuildRoutesProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], progress=data["progress"], ) class InclusionAbortedEventModel(BaseControllerEventModel): """Model for `inclusion aborted` event data.""" event: Literal["inclusion aborted"] class InclusionFailedEventModel(BaseControllerEventModel): """Model for `inclusion failed` event data.""" event: Literal["inclusion failed"] class InclusionStartedEventModel(BaseControllerEventModel): """Model for `inclusion started` event data.""" event: Literal["inclusion started"] strategy: InclusionStrategy @classmethod def from_dict(cls, data: dict) -> InclusionStartedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], strategy=data["strategy"], ) class InclusionStateChangedEventModel(BaseControllerEventModel): """Model for `inclusion state changed` event data.""" event: Literal["inclusion state changed"] state: InclusionState @classmethod def from_dict(cls, data: dict) -> InclusionStateChangedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], state=data["state"], ) class InclusionStoppedEventModel(BaseControllerEventModel): """Model for `inclusion stopped` event data.""" event: Literal["inclusion stopped"] class NodeAddedEventModel(BaseControllerEventModel): """Model for `node added` event data.""" event: Literal["node added"] node: NodeDataType result: InclusionResultDataType @classmethod def from_dict(cls, data: dict) -> NodeAddedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], node=data["node"], result=data["result"], ) class NodeFoundEventModel(BaseControllerEventModel): """Model for `node found` event data.""" event: Literal["node found"] node: FoundNodeDataType @classmethod def from_dict(cls, data: dict) -> NodeFoundEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], node=data["node"], ) class NodeRemovedEventModel(BaseControllerEventModel): """Model for `node removed` event data.""" event: Literal["node removed"] node: NodeDataType reason: RemoveNodeReason @classmethod def from_dict(cls, data: dict) -> NodeRemovedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], node=data["node"], reason=data["reason"], ) class NVMBackupAndConvertProgressEventModel(BaseControllerEventModel): """Base model for `nvm backup progress` and `nvm convert progress` event data.""" bytesRead: int total: int @classmethod def from_dict(cls, data: dict) -> NVMBackupAndConvertProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], bytesRead=data["bytesRead"], total=data["total"], ) class NVMBackupProgressEventModel(NVMBackupAndConvertProgressEventModel): """Model for `nvm backup progress` event data.""" event: Literal["nvm backup progress"] class NVMConvertProgressEventModel(NVMBackupAndConvertProgressEventModel): """Model for `nvm convert progress` event data.""" event: Literal["nvm convert progress"] class NVMRestoreProgressEventModel(BaseControllerEventModel): """Model for `nvm restore progress` event data.""" event: Literal["nvm restore progress"] bytesWritten: int total: int @classmethod def from_dict(cls, data: dict) -> NVMRestoreProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], bytesWritten=data["bytesWritten"], total=data["total"], ) class StatisticsUpdatedEventModel(BaseControllerEventModel): """Model for `statistics updated` event data.""" event: Literal["statistics updated"] statistics: ControllerStatisticsDataType @classmethod def from_dict(cls, data: dict) -> StatisticsUpdatedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], statistics=data["statistics"], ) class ValidateDSKAndEnterPINEventModel(BaseControllerEventModel): """Model for `validate dsk and enter pin` event data.""" event: Literal["validate dsk and enter pin"] dsk: str @classmethod def from_dict(cls, data: dict) -> ValidateDSKAndEnterPINEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], dsk=data["dsk"], ) class IdentifyEventModel(BaseControllerEventModel): """Model for `identify` event data.""" event: Literal["identify"] nodeId: int @classmethod def from_dict(cls, data: dict) -> IdentifyEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], ) class StatusChangedEventModel(BaseControllerEventModel): """Model for `status changed` event data.""" event: Literal["status changed"] status: int @classmethod def from_dict(cls, data: dict) -> StatusChangedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], status=data["status"], ) CONTROLLER_EVENT_MODEL_MAP: dict[str, type[BaseControllerEventModel]] = { "exclusion failed": ExclusionFailedEventModel, "exclusion started": ExclusionStartedEventModel, "exclusion stopped": ExclusionStoppedEventModel, "firmware update finished": FirmwareUpdateFinishedEventModel, "firmware update progress": FirmwareUpdateProgressEventModel, "grant security classes": GrantSecurityClassesEventModel, "rebuild routes done": RebuildRoutesDoneEventModel, "rebuild routes progress": RebuildRoutesProgressEventModel, "identify": IdentifyEventModel, "inclusion aborted": InclusionAbortedEventModel, "inclusion failed": InclusionFailedEventModel, "inclusion started": InclusionStartedEventModel, "inclusion state changed": InclusionStateChangedEventModel, "inclusion stopped": InclusionStoppedEventModel, "node added": NodeAddedEventModel, "node found": NodeFoundEventModel, "node removed": NodeRemovedEventModel, "nvm backup progress": NVMBackupProgressEventModel, "nvm convert progress": NVMConvertProgressEventModel, "nvm restore progress": NVMRestoreProgressEventModel, "statistics updated": StatisticsUpdatedEventModel, "status changed": StatusChangedEventModel, "validate dsk and enter pin": ValidateDSKAndEnterPINEventModel, } zwave-js-server-python-0.63.0/zwave_js_server/model/controller/firmware.py000066400000000000000000000055331500374325600270730ustar00rootroot00000000000000"""Provide a model for Z-Wave controller firmware.""" from __future__ import annotations from dataclasses import dataclass, field from enum import IntEnum from typing import TypedDict from ...util.helpers import convert_bytes_to_base64 class ControllerFirmwareUpdateDataDataType(TypedDict, total=False): """Represent a controller firmware update data dict type.""" filename: str # required file: str # required fileFormat: str @dataclass class ControllerFirmwareUpdateData: """Controller firmware update data.""" filename: str file: bytes file_format: str | None = None def to_dict(self) -> ControllerFirmwareUpdateDataDataType: """Convert firmware update data to dict.""" data: ControllerFirmwareUpdateDataDataType = { "filename": self.filename, "file": convert_bytes_to_base64(self.file), } if self.file_format is not None: data["fileFormat"] = self.file_format return data class ControllerFirmwareUpdateStatus(IntEnum): """Enum with all controller firmware update status values. https://zwave-js.github.io/node-zwave-js/#/api/controller?id=quotfirmware-update-finishedquot """ ERROR_TIMEOUT = 0 # The maximum number of retry attempts for a firmware fragments were reached ERROR_RETRY_LIMIT_REACHED = 1 # The update was aborted by the bootloader ERROR_ABORTED = 2 # This controller does not support firmware updates ERROR_NOT_SUPPORTED = 3 OK = 255 class ControllerFirmwareUpdateProgressDataType(TypedDict): """Represent a controller firmware update progress dict type.""" sentFragments: int totalFragments: int progress: float @dataclass class ControllerFirmwareUpdateProgress: """Model for a controller firmware update progress data.""" data: ControllerFirmwareUpdateProgressDataType = field(repr=False) sent_fragments: int = field(init=False) total_fragments: int = field(init=False) progress: float = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.sent_fragments = self.data["sentFragments"] self.total_fragments = self.data["totalFragments"] self.progress = float(self.data["progress"]) class ControllerFirmwareUpdateResultDataType(TypedDict): """Represent a controller firmware update result dict type.""" status: int success: bool @dataclass class ControllerFirmwareUpdateResult: """Model for controller firmware update result data.""" data: ControllerFirmwareUpdateResultDataType = field(repr=False) status: ControllerFirmwareUpdateStatus = field(init=False) success: bool = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.status = ControllerFirmwareUpdateStatus(self.data["status"]) self.success = self.data["success"] zwave-js-server-python-0.63.0/zwave_js_server/model/controller/inclusion_and_provisioning.py000066400000000000000000000167631500374325600327210ustar00rootroot00000000000000"""Provide a model for inclusion and provisioning.""" from __future__ import annotations from dataclasses import dataclass from typing import Any, TypedDict from ...const import Protocols, ProvisioningEntryStatus, QRCodeVersion, SecurityClass class InclusionGrantDataType(TypedDict): """Representation of an inclusion grant data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L48-L56 securityClasses: list[int] clientSideAuth: bool @dataclass class InclusionGrant: """Representation of an inclusion grant.""" security_classes: list[SecurityClass] client_side_auth: bool def to_dict(self) -> InclusionGrantDataType: """Return InclusionGrantDataType dict from self.""" return { "securityClasses": [sec_cls.value for sec_cls in self.security_classes], "clientSideAuth": self.client_side_auth, } @classmethod def from_dict(cls, data: InclusionGrantDataType) -> InclusionGrant: """Return InclusionGrant from InclusionGrantDataType dict.""" return cls( security_classes=[ SecurityClass(sec_cls) for sec_cls in data["securityClasses"] ], client_side_auth=data["clientSideAuth"], ) @dataclass class ProvisioningEntry: """Class to represent the base fields of a provisioning entry.""" dsk: str security_classes: list[SecurityClass] requested_security_classes: list[SecurityClass] | None = None status: ProvisioningEntryStatus = ProvisioningEntryStatus.ACTIVE protocol: Protocols | None = None additional_properties: dict[str, Any] | None = None def to_dict(self) -> dict[str, Any]: """Return PlannedProvisioning data dict from self.""" data = { "dsk": self.dsk, "securityClasses": [sec_cls.value for sec_cls in self.security_classes], "status": self.status.value, **(self.additional_properties or {}), } if self.requested_security_classes: data["requestedSecurityClasses"] = [ sec_cls.value for sec_cls in self.requested_security_classes ] if self.protocol is not None: data["protocol"] = self.protocol.value return data @classmethod def from_dict(cls, data: dict[str, Any]) -> ProvisioningEntry: """Return ProvisioningEntry from data dict.""" cls_instance = cls( dsk=data["dsk"], security_classes=[ SecurityClass(sec_cls) for sec_cls in data["securityClasses"] ], ) if additional_properties := { k: v for k, v in data.items() if k not in ("dsk", "securityClasses", "requestedSecurityClasses", "status") }: cls_instance.additional_properties = additional_properties if "requestedSecurityClasses" in data: cls_instance.requested_security_classes = [ SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"] ] if "status" in data: cls_instance.status = ProvisioningEntryStatus(data["status"]) if "protocol" in data: cls_instance.protocol = Protocols(data["protocol"]) return cls_instance @dataclass class QRProvisioningInformationMixin: """Mixin class to represent the base fields of a QR provisioning information.""" version: QRCodeVersion generic_device_class: int specific_device_class: int installer_icon_type: int manufacturer_id: int product_type: int product_id: int application_version: str max_inclusion_request_interval: int | None uuid: str | None supported_protocols: list[Protocols] | None @dataclass class QRProvisioningInformation(ProvisioningEntry, QRProvisioningInformationMixin): """Representation of provisioning information retrieved from a QR code.""" def to_dict(self) -> dict[str, Any]: """Return QRProvisioningInformation data dict from self.""" data = { "version": self.version.value, "securityClasses": [sec_cls.value for sec_cls in self.security_classes], "dsk": self.dsk, "status": self.status.value, "genericDeviceClass": self.generic_device_class, "specificDeviceClass": self.specific_device_class, "installerIconType": self.installer_icon_type, "manufacturerId": self.manufacturer_id, "productType": self.product_type, "productId": self.product_id, "applicationVersion": self.application_version, **(self.additional_properties or {}), } if self.requested_security_classes: data["requestedSecurityClasses"] = [ sec_cls.value for sec_cls in self.requested_security_classes ] if self.max_inclusion_request_interval is not None: data["maxInclusionRequestInterval"] = self.max_inclusion_request_interval if self.uuid is not None: data["uuid"] = self.uuid if self.supported_protocols is not None: data["supportedProtocols"] = [ protocol.value for protocol in self.supported_protocols ] return data @classmethod def from_dict(cls, data: dict[str, Any]) -> QRProvisioningInformation: """Return QRProvisioningInformation from data dict.""" supported_protocols: list[Protocols] | None = None if "supportedProtocols" in data: supported_protocols = [ Protocols(supported_protocol) for supported_protocol in data["supportedProtocols"] ] cls_instance = cls( version=QRCodeVersion(data["version"]), security_classes=[ SecurityClass(sec_cls) for sec_cls in data["securityClasses"] ], dsk=data["dsk"], generic_device_class=data["genericDeviceClass"], specific_device_class=data["specificDeviceClass"], installer_icon_type=data["installerIconType"], manufacturer_id=data["manufacturerId"], product_type=data["productType"], product_id=data["productId"], application_version=data["applicationVersion"], max_inclusion_request_interval=data.get("maxInclusionRequestInterval"), uuid=data.get("uuid"), supported_protocols=supported_protocols, ) if additional_properties := { k: v for k, v in data.items() if k not in ( "version", "securityClasses", "requestedSecurityClasses", "dsk", "genericDeviceClass", "specificDeviceClass", "installerIconType", "manufacturerId", "productType", "productId", "applicationVersion", "maxInclusionRequestInterval", "uuid", "supportedProtocols", "status", ) }: cls_instance.additional_properties = additional_properties if "requestedSecurityClasses" in data: cls_instance.requested_security_classes = [ SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"] ] if "status" in data: cls_instance.status = ProvisioningEntryStatus(data["status"]) return cls_instance zwave-js-server-python-0.63.0/zwave_js_server/model/controller/rebuild_routes.py000066400000000000000000000020611500374325600302770ustar00rootroot00000000000000"""Provide models for rebuilding routes.""" from __future__ import annotations from dataclasses import dataclass from enum import StrEnum from typing import TypedDict class RebuildRoutesOptionsDataType(TypedDict, total=False): """Represent a rebuild routes options data dict type.""" includeSleeping: bool @dataclass class RebuildRoutesOptions: """Represent options for rebuilding routes.""" include_sleeping: bool | None = None @classmethod def from_dict(cls, data: RebuildRoutesOptionsDataType) -> RebuildRoutesOptions: """Return options from data.""" return cls(include_sleeping=data.get("includeSleeping")) def to_dict(self) -> RebuildRoutesOptionsDataType: """Return dict representation of data.""" if self.include_sleeping is None: return {} return {"includeSleeping": self.include_sleeping} class RebuildRoutesStatus(StrEnum): """Enum of all known rebuild routes status values.""" PENDING = "pending" DONE = "done" FAILED = "failed" SKIPPED = "skipped" zwave-js-server-python-0.63.0/zwave_js_server/model/controller/statistics.py000066400000000000000000000111001500374325600274340ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS controller's statistics.""" from __future__ import annotations from contextlib import suppress from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict from ..statistics import RouteStatistics, RouteStatisticsDataType if TYPE_CHECKING: from ...client import Client class ControllerLifelineRoutesDataType(TypedDict): """Represent a controller lifeline routes data dict type.""" lwr: RouteStatisticsDataType nlwr: RouteStatisticsDataType @dataclass class ControllerLifelineRoutes: """Represent controller lifeline routes.""" client: Client = field(repr=False) data: ControllerLifelineRoutesDataType = field(repr=False) lwr: RouteStatistics | None = field(init=False, default=None) nlwr: RouteStatistics | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialize.""" if lwr := self.data.get("lwr"): with suppress(ValueError): self.lwr = RouteStatistics(self.client, lwr) if nlwr := self.data.get("nlwr"): with suppress(ValueError): self.nlwr = RouteStatistics(self.client, nlwr) class ChannelRSSIDataType(TypedDict): """Represent a channel RSSI data dict type.""" average: int current: int class BackgroundRSSIDataType(TypedDict, total=False): """Represent a background RSSI data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/ControllerStatistics.ts#L40 timestamp: int # required channel0: ChannelRSSIDataType # required channel1: ChannelRSSIDataType # required channel2: ChannelRSSIDataType class ControllerStatisticsDataType(TypedDict, total=False): """Represent a controller statistics data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/ControllerStatistics.ts#L20-L39 messagesTX: int # required messagesRX: int # required messagesDroppedTX: int # required messagesDroppedRX: int # required NAK: int # required CAN: int # required timeoutACK: int # required timeoutResponse: int # required timeoutCallback: int # required backgroundRSSI: BackgroundRSSIDataType @dataclass class ChannelRSSI: """Represent a channel RSSI.""" data: ChannelRSSIDataType = field(repr=False) average: int = field(init=False) current: int = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.average = self.data["average"] self.current = self.data["current"] @dataclass class BackgroundRSSI: """Represent a background RSSI update.""" data: BackgroundRSSIDataType = field(repr=False) timestamp: int = field(init=False) channel_0: ChannelRSSI = field(init=False) channel_1: ChannelRSSI = field(init=False) channel_2: ChannelRSSI | None = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.timestamp = self.data["timestamp"] self.channel_0 = ChannelRSSI(self.data["channel0"]) self.channel_1 = ChannelRSSI(self.data["channel1"]) if not (channel_2 := self.data.get("channel2")): self.channel_2 = None return self.channel_2 = ChannelRSSI(channel_2) @dataclass class ControllerStatistics: """Represent a controller statistics update.""" data: ControllerStatisticsDataType = field(repr=False) messages_tx: int = field(init=False) messages_rx: int = field(init=False) messages_dropped_rx: int = field(init=False) messages_dropped_tx: int = field(init=False) nak: int = field(init=False) can: int = field(init=False) timeout_ack: int = field(init=False) timeout_response: int = field(init=False) timeout_callback: int = field(init=False) background_rssi: BackgroundRSSI | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialize.""" self.messages_tx = self.data["messagesTX"] self.messages_rx = self.data["messagesRX"] self.messages_dropped_rx = self.data["messagesDroppedRX"] self.messages_dropped_tx = self.data["messagesDroppedTX"] self.nak = self.data["NAK"] self.can = self.data["CAN"] self.timeout_ack = self.data["timeoutACK"] self.timeout_response = self.data["timeoutResponse"] self.timeout_callback = self.data["timeoutCallback"] if background_rssi := self.data.get("backgroundRSSI"): self.background_rssi = BackgroundRSSI(background_rssi) zwave-js-server-python-0.63.0/zwave_js_server/model/device_class.py000066400000000000000000000031111500374325600255060ustar00rootroot00000000000000""" Model for a Zwave Node's device class. https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceclass """ from __future__ import annotations from dataclasses import dataclass from typing import TypedDict class DeviceClassItemDataType(TypedDict): """Represent a device class data dict type.""" key: int label: str class DeviceClassDataType(TypedDict): """Represent a device class data dict type.""" basic: DeviceClassItemDataType generic: DeviceClassItemDataType specific: DeviceClassItemDataType @dataclass class DeviceClassItem: """Model for a DeviceClass item (e.g. basic or generic).""" key: int label: str class DeviceClass: """Model for a Zwave Node's device class.""" def __init__(self, data: DeviceClassDataType) -> None: """Initialize.""" self._basic = DeviceClassItem( key=data["basic"]["key"], label=data["basic"]["label"], ) self._generic = DeviceClassItem( key=data["generic"]["key"], label=data["generic"]["label"], ) self._specific = DeviceClassItem( key=data["specific"]["key"], label=data["specific"]["label"], ) @property def basic(self) -> DeviceClassItem: """Return basic DeviceClass.""" return self._basic @property def generic(self) -> DeviceClassItem: """Return generic DeviceClass.""" return self._generic @property def specific(self) -> DeviceClassItem: """Return specific DeviceClass.""" return self._specific zwave-js-server-python-0.63.0/zwave_js_server/model/device_config.py000066400000000000000000000146421500374325600256610ustar00rootroot00000000000000""" Model for a Zwave Node's device config. https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig """ from __future__ import annotations from typing import Any, Literal, TypedDict class DeviceDeviceDataType(TypedDict, total=False): """Represent a device device data dict type.""" productType: str productId: str class DeviceDevice: """Model for a Zwave Node's device config's device.""" def __init__(self, data: DeviceDeviceDataType) -> None: """Initialize.""" self.data = data @property def product_type(self) -> str | None: """Return product type.""" return self.data.get("productType") @property def product_id(self) -> str | None: """Return product id.""" return self.data.get("productId") class DeviceFirmwareVersionRangeDataType(TypedDict, total=False): """Represent a device firmware version range data dict type.""" min: str max: str class DeviceFirmwareVersionRange: """Model for a Zwave Node's device config's firmware version range.""" def __init__(self, data: DeviceFirmwareVersionRangeDataType) -> None: """Initialize.""" self.data = data @property def min(self) -> str | None: """Return min version.""" return self.data.get("min") @property def max(self) -> str | None: """Return max version.""" return self.data.get("max") class CommentDataType(TypedDict): """Represent a device config's comment data dict type.""" # See PR for suggested meanings of each level: # https://github.com/zwave-js/node-zwave-js/pull/3947 level: Literal["info", "warning", "error"] text: str class DeviceMetadataDataType(TypedDict, total=False): """Represent a device metadata data dict type.""" wakeup: str inclusion: str exclusion: str reset: str manual: str comments: CommentDataType | list[CommentDataType] class DeviceMetadata: """Model for a Zwave Node's device config's metadata.""" def __init__(self, data: DeviceMetadataDataType) -> None: """Initialize.""" self.data = data @property def wakeup(self) -> str | None: """Return wakeup instructions.""" return self.data.get("wakeup") @property def inclusion(self) -> str | None: """Return inclusion instructions.""" return self.data.get("inclusion") @property def exclusion(self) -> str | None: """Return exclusion instructions.""" return self.data.get("exclusion") @property def reset(self) -> str | None: """Return reset instructions.""" return self.data.get("reset") @property def manual(self) -> str | None: """Return manual instructions.""" return self.data.get("manual") @property def comments(self) -> list[CommentDataType]: """Return list of comments about device.""" comments = self.data.get("comments", []) if isinstance(comments, dict): return [comments] return comments class DeviceConfigDataType(TypedDict, total=False): """Represent a device config data dict type.""" filename: str manufacturer: str manufacturerId: str label: str description: str devices: list[DeviceDeviceDataType] firmwareVersion: DeviceFirmwareVersionRangeDataType associations: dict[str, dict] paramInformation: dict[str, dict] supportsZWavePlus: bool proprietary: dict compat: dict[str, Any] metadata: DeviceMetadataDataType isEmbedded: bool class DeviceConfig: """Model for a Zwave Node's device config.""" def __init__(self, data: DeviceConfigDataType) -> None: """Initialize.""" self.data = data self._devices = [ DeviceDevice(device) for device in self.data.get("devices", []) ] self._firmware_version = DeviceFirmwareVersionRange( self.data.get("firmwareVersion", {}) ) self._metadata = DeviceMetadata(self.data.get("metadata", {})) @property def filename(self) -> str | None: """Return config filename.""" return self.data.get("filename") @property def manufacturer(self) -> str | None: """Return name of the manufacturer.""" return self.data.get("manufacturer") @property def manufacturer_id(self) -> str | None: # TODO: In the dump this is an int. """Return manufacturer id (as defined in specs) as a 4-digit hex string.""" return self.data.get("manufacturerId") @property def label(self) -> str | None: """Return short label for the device.""" return self.data.get("label") @property def description(self) -> str | None: """Return longer description of the device, usually the full name.""" return self.data.get("description") @property def devices(self) -> list[DeviceDevice]: """Return list of product type and product ID combinations.""" return self._devices @property def firmware_version(self) -> DeviceFirmwareVersionRange: """Return firmware version range this config is valid for.""" return self._firmware_version @property def associations(self) -> dict[str, dict]: """Return dict of association groups the device supports.""" return self.data.get("associations", {}) @property def param_information(self) -> dict[str, dict]: """Return dictionary of configuration parameters the device supports.""" return self.data.get("paramInformation", {}) @property def supports_zwave_plus(self) -> bool | None: """Return if the device complies with the Z-Wave+ standard.""" return self.data.get("supportsZWavePlus") @property def proprietary(self) -> dict: """Return dictionary of settings for the proprietary CC.""" return self.data.get("proprietary", {}) @property def compat(self) -> dict[str, dict]: """Return compatibility flags.""" return self.data.get("compat", {}) @property def metadata(self) -> DeviceMetadata: """Return metadata.""" return self._metadata @property def is_embedded(self) -> bool | None: """Return whether device config is embedded in zwave-js-server.""" return self.data.get("isEmbedded") def to_dict(self) -> DeviceConfigDataType: """Return dict representation of device config.""" return self.data.copy() zwave-js-server-python-0.63.0/zwave_js_server/model/driver.py000066400000000000000000000157621500374325600243740ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS Driver.""" from __future__ import annotations from typing import TYPE_CHECKING, Any, Literal, cast from ..event import BaseEventModel, Event, EventBase from .config_manager import ConfigManager from .controller import Controller from .log_config import LogConfig, LogConfigDataType from .log_message import LogMessage, LogMessageDataType try: from pydantic.v1 import create_model_from_typeddict except ImportError: from pydantic import create_model_from_typeddict if TYPE_CHECKING: from ..client import Client class BaseDriverEventModel(BaseEventModel): """Base model for a driver event.""" source: Literal["driver"] class LogConfigUpdatedEventModel(BaseDriverEventModel): """Model for `log config updated` event data.""" event: Literal["log config updated"] config: LogConfigDataType @classmethod def from_dict(cls, data: dict) -> LogConfigUpdatedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], config=data["config"], ) class AllNodesReadyEventModel(BaseDriverEventModel): """Model for `all nodes ready` event data.""" event: Literal["all nodes ready"] LoggingEventModel = create_model_from_typeddict( LogMessageDataType, __base__=BaseDriverEventModel ) class DriverReadyEventModel(BaseDriverEventModel): """Model for `driver ready` event data.""" event: Literal["driver ready"] DRIVER_EVENT_MODEL_MAP: dict[str, type[BaseDriverEventModel]] = { "all nodes ready": AllNodesReadyEventModel, "log config updated": LogConfigUpdatedEventModel, "logging": LoggingEventModel, "driver ready": DriverReadyEventModel, } class CheckConfigUpdates: """Represent config updates check.""" def __init__(self, data: dict) -> None: """Initialize class.""" self.installed_version: str = data["installedVersion"] self.update_available: bool = data["updateAvailable"] self.new_version: str | None = data.get("newVersion") class Driver(EventBase): """Represent a Z-Wave JS driver.""" def __init__( self, client: Client, state: dict, log_config: LogConfigDataType ) -> None: """Initialize driver.""" super().__init__() self.client = client self.controller = Controller(client, state) self.log_config = LogConfig.from_dict(log_config) self.config_manager = ConfigManager(client) def __hash__(self) -> int: """Return the hash.""" return hash(self.controller) def __eq__(self, other: object) -> bool: """Return whether this instance equals another.""" if not isinstance(other, Driver): return False return self.controller == other.controller def receive_event(self, event: Event) -> None: """Receive an event.""" if event.data["source"] != "driver": self.controller.receive_event(event) return DRIVER_EVENT_MODEL_MAP[event.type].from_dict(event.data) self._handle_event_protocol(event) self.emit(event.type, event.data) async def _async_send_command( self, command: str, require_schema: int | None = None, **kwargs: Any ) -> dict: """Send a driver command. For internal use only.""" return await self.client.async_send_command( { "command": f"driver.{command}", **kwargs, }, require_schema, ) async def async_update_log_config(self, log_config: LogConfig) -> None: """Update log config for driver.""" await self._async_send_command( "update_log_config", config=log_config.to_dict(), require_schema=4 ) async def async_get_log_config(self) -> LogConfig: """Return current log config for driver.""" result = await self._async_send_command("get_log_config", require_schema=4) return LogConfig.from_dict(result["config"]) async def async_enable_statistics( self, application_name: str, application_version: str ) -> None: """Send command to enable data collection.""" await self._async_send_command( "enable_statistics", applicationName=application_name, applicationVersion=application_version, require_schema=4, ) async def async_disable_statistics(self) -> None: """Send command to stop listening to log events.""" await self._async_send_command("disable_statistics", require_schema=4) async def async_is_statistics_enabled(self) -> bool: """Send command to start listening to log events.""" result = await self._async_send_command( "is_statistics_enabled", require_schema=4 ) return cast(bool, result["statisticsEnabled"]) async def async_check_for_config_updates(self) -> CheckConfigUpdates: """Send command to check for config updates.""" result = await self._async_send_command( "check_for_config_updates", require_schema=5 ) return CheckConfigUpdates(result) async def async_install_config_update(self) -> bool: """Send command to install config update.""" result = await self._async_send_command( "install_config_update", require_schema=5 ) return cast(bool, result["success"]) async def async_set_preferred_scales( self, scales: dict[str | int, str | int] ) -> None: """Send command to set preferred sensor scales.""" await self._async_send_command( "set_preferred_scales", scales=scales, require_schema=6 ) async def async_hard_reset(self) -> None: """Send command to hard reset controller.""" await self._async_send_command("hard_reset", require_schema=25) async def async_try_soft_reset(self) -> None: """Send command to try to soft reset controller.""" await self._async_send_command("try_soft_reset", require_schema=25) async def async_soft_reset(self) -> None: """Send command to soft reset controller.""" await self._async_send_command("soft_reset", require_schema=25) async def async_shutdown(self) -> bool: """Send command to shutdown controller.""" data = await self._async_send_command("shutdown", require_schema=27) return cast(bool, data["success"]) def handle_logging(self, event: Event) -> None: """Process a driver logging event.""" event.data["log_message"] = LogMessage(cast(LogMessageDataType, event.data)) def handle_log_config_updated(self, event: Event) -> None: """Process a driver log config updated event.""" event.data["log_config"] = self.log_config = LogConfig.from_dict( event.data["config"] ) def handle_all_nodes_ready(self, event: Event) -> None: """Process a driver all nodes ready event.""" def handle_driver_ready(self, event: Event) -> None: """Process a driver ready event.""" zwave-js-server-python-0.63.0/zwave_js_server/model/duration.py000066400000000000000000000022011500374325600247060ustar00rootroot00000000000000"""Provide a model for Z-Wave JS Duration.""" from __future__ import annotations from dataclasses import dataclass, field from typing import Literal, TypedDict class DurationDataType(TypedDict, total=False): """Represent a Duration data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/v11-dev/packages/core/src/values/Duration.ts#L11 unit: Literal["seconds", "minutes"] # required value: int | float @dataclass class Duration: """Duration class.""" data: DurationDataType | Literal["unknown", "default"] = field(repr=False) unit: Literal["seconds", "minutes", "unknown", "default"] = field(init=False) value: int | float | None = field(init=False) def __post_init__(self) -> None: """Post init.""" if isinstance(self.data, str): self.unit = self.data self.value = None return self.unit = self.data["unit"] self.value = self.data.get("value") def __repr__(self) -> str: """Return the representation.""" if self.value: return f"{self.value} {self.unit}" return f"{self.unit} duration" zwave-js-server-python-0.63.0/zwave_js_server/model/endpoint.py000066400000000000000000000272071500374325600247160ustar00rootroot00000000000000""" Model for a Zwave Node's endpoints. https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=endpoint-properties """ from __future__ import annotations import asyncio from typing import TYPE_CHECKING, Any, Literal, TypedDict, cast from ..const import NodeStatus from ..event import EventBase from ..exceptions import FailedCommand, NotFoundError from .command_class import CommandClass, CommandClassInfo, CommandClassInfoDataType from .device_class import DeviceClass, DeviceClassDataType from .value import ( CommandStatus, ConfigurationValue, ConfigurationValueFormat, SetConfigParameterResult, SupervisionResult, Value, ) if TYPE_CHECKING: from ..client import Client from .node import Node from .node.data_model import NodeDataType class EndpointDataType(TypedDict, total=False): """Represent an endpoint data dict type.""" nodeId: int # required index: int # required deviceClass: DeviceClassDataType | None installerIcon: int userIcon: int endpointLabel: str commandClasses: list[CommandClassInfoDataType] # required class Endpoint(EventBase): """Model for a Zwave Node's endpoint.""" def __init__( self, client: Client, node: Node, data: EndpointDataType, values: dict[str, ConfigurationValue | Value], ) -> None: """Initialize.""" super().__init__() self.client = client self.node = node self.data: EndpointDataType = data self.values: dict[str, ConfigurationValue | Value] = {} self._device_class: DeviceClass | None = None self.update(data, values) def __repr__(self) -> str: """Return the representation.""" return f"{type(self).__name__}(node_id={self.node_id}, index={self.index})" def __hash__(self) -> int: """Return the hash.""" return hash((self.client.driver, self.node_id, self.index)) def __eq__(self, other: object) -> bool: """Return whether this instance equals another.""" if not isinstance(other, Endpoint): return False return ( self.client.driver == other.client.driver and self.node_id == other.node_id and self.index == other.index ) @property def node_id(self) -> int: """Return node ID property.""" return self.data["nodeId"] @property def index(self) -> int: """Return index property.""" return self.data["index"] @property def device_class(self) -> DeviceClass | None: """Return the device_class.""" return self._device_class @property def installer_icon(self) -> int | None: """Return installer icon property.""" return self.data.get("installerIcon") @property def user_icon(self) -> int | None: """Return user icon property.""" return self.data.get("userIcon") @property def command_classes(self) -> list[CommandClassInfo]: """Return all CommandClasses supported on this node.""" return [CommandClassInfo(cc) for cc in self.data["commandClasses"]] @property def endpoint_label(self) -> str | None: """Return endpoint label property.""" return self.data.get("endpointLabel") def update( self, data: EndpointDataType, values: dict[str, ConfigurationValue | Value] ) -> None: """Update the endpoint data.""" self.data = data if (device_class := self.data.get("deviceClass")) is None: self._device_class = None else: self._device_class = DeviceClass(device_class) # Remove stale values self.values = { value_id: val for value_id, val in self.values.items() if value_id in values } # Populate new values for value_id, value in values.items(): if value_id not in self.values: self.values[value_id] = value def get_command_class_values( self, command_class: CommandClass ) -> dict[str, ConfigurationValue | Value]: """Return all values for a given command class.""" return { value_id: value for value_id, value in self.values.items() if value.command_class == command_class } def get_configuration_values(self) -> dict[str, ConfigurationValue]: """Return all configuration values for an endpoint.""" return cast( dict[str, ConfigurationValue], self.get_command_class_values(CommandClass.CONFIGURATION), ) async def async_send_command( self, cmd: str, require_schema: int | None = None, wait_for_result: bool | None = None, **cmd_kwargs: Any, ) -> dict[str, Any] | None: """ Send an endpoint command. For internal use only. If wait_for_result is not None, it will take precedence, otherwise we will decide to wait or not based on the node status. """ if self.client.driver is None: raise FailedCommand( "Command failed", "failed_command", "The client is not connected" ) kwargs = {} message = { "command": f"endpoint.{cmd}", "nodeId": self.node_id, "endpoint": self.index, **cmd_kwargs, } if require_schema is not None: kwargs["require_schema"] = require_schema if wait_for_result: result = await self.client.async_send_command(message, **kwargs) return result if wait_for_result is None and self.node.status not in ( NodeStatus.ASLEEP, NodeStatus.DEAD, ): result_task = asyncio.create_task( self.client.async_send_command(message, **kwargs) ) status_task = asyncio.create_task(self.node.status_event.wait()) await asyncio.wait( [result_task, status_task], return_when=asyncio.FIRST_COMPLETED, ) status_task.cancel() if self.node.status_event.is_set() and not result_task.done(): result_task.cancel() return None return result_task.result() await self.client.async_send_command_no_wait(message, **kwargs) return None async def async_invoke_cc_api( self, command_class: CommandClass, method_name: str, *args: Any, wait_for_result: bool | None = None, ) -> Any: """Call endpoint.invoke_cc_api command.""" if not any(cc.id == command_class.value for cc in self.command_classes): raise NotFoundError( f"Command class {command_class} not found on endpoint {self}" ) result = await self.async_send_command( "invoke_cc_api", commandClass=command_class.value, methodName=method_name, args=list(args), require_schema=7, wait_for_result=wait_for_result, ) if not result: return None return result["response"] async def async_supports_cc_api(self, command_class: CommandClass) -> bool: """Call endpoint.supports_cc_api command.""" result = await self.async_send_command( "supports_cc_api", commandClass=command_class.value, require_schema=7, wait_for_result=True, ) assert result return cast(bool, result["supported"]) async def async_supports_cc(self, command_class: CommandClass) -> bool: """Call endpoint.supports_cc command.""" result = await self.async_send_command( "supports_cc", commandClass=command_class.value, require_schema=23, wait_for_result=True, ) assert result return cast(bool, result["supported"]) async def async_controls_cc(self, command_class: CommandClass) -> bool: """Call endpoint.controls_cc command.""" result = await self.async_send_command( "controls_cc", commandClass=command_class.value, require_schema=23, wait_for_result=True, ) assert result return cast(bool, result["controlled"]) async def async_is_cc_secure(self, command_class: CommandClass) -> bool: """Call endpoint.is_cc_secure command.""" result = await self.async_send_command( "is_cc_secure", commandClass=command_class.value, require_schema=23, wait_for_result=True, ) assert result return cast(bool, result["secure"]) async def async_get_cc_version(self, command_class: CommandClass) -> bool: """Call endpoint.get_cc_version command.""" result = await self.async_send_command( "get_cc_version", commandClass=command_class.value, require_schema=23, wait_for_result=True, ) assert result return cast(bool, result["version"]) async def async_get_node_unsafe(self) -> NodeDataType: """Call endpoint.get_node_unsafe command.""" result = await self.async_send_command( "get_node_unsafe", require_schema=23, wait_for_result=True, ) assert result return cast("NodeDataType", result["node"]) async def async_set_raw_config_parameter_value( self, new_value: int, property_: int | str, property_key: int | None = None, value_size: Literal[1, 2, 4] | None = None, value_format: ConfigurationValueFormat | None = None, ) -> SetConfigParameterResult: """Send setRawConfigParameterValue.""" if (value_size is not None and value_format is None) or ( value_size is None and value_format is not None ): raise ValueError( "value_size and value_format must either both be included or not " "included" ) if value_size is not None and property_key is not None: raise ValueError( "property_key can only be included when value_size and value_format " "are not included" ) options = { "value": new_value, "parameter": property_, "bitMask": property_key, "valueSize": value_size, "valueFormat": value_format, } data = await self.async_send_command( "set_raw_config_parameter_value", require_schema=33, wait_for_result=None, **{k: v for k, v in options.items() if v is not None}, ) if data is None: return SetConfigParameterResult(CommandStatus.QUEUED) if (result := data.get("result")) is None: return SetConfigParameterResult(CommandStatus.ACCEPTED) return SetConfigParameterResult( CommandStatus.ACCEPTED, SupervisionResult(result) ) async def async_get_raw_config_parameter_value( self, property_: int, property_key: int | None = None, allow_unexpected_response: bool | None = None, ) -> Any: """Call getRawConfigParameterValue.""" options = { "parameter": property_, "bitMask": property_key, "allowUnexpectedResponse": allow_unexpected_response, } result = await self.async_send_command( "get_raw_config_parameter_value", require_schema=39, wait_for_result=True, **{k: v for k, v in options.items() if v is not None}, ) assert result return result["value"] zwave-js-server-python-0.63.0/zwave_js_server/model/log_config.py000066400000000000000000000030461500374325600251770ustar00rootroot00000000000000"""Provide a model for the log config.""" from __future__ import annotations from dataclasses import dataclass from typing import TypedDict, cast from ..const import LogLevel class LogConfigDataType(TypedDict, total=False): """Represent a log config data dict type.""" enabled: bool level: str logToFile: bool filename: str forceConsole: bool @dataclass class LogConfig: """Represent a log config dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/log/shared.ts#L85 # Must include at least one key enabled: bool | None = None level: LogLevel | None = None log_to_file: bool | None = None filename: str | None = None force_console: bool | None = None def to_dict(self) -> LogConfigDataType: """Return LogConfigDataType dict from self.""" data = { "enabled": self.enabled, "level": self.level.value if self.level else None, "logToFile": self.log_to_file, "filename": self.filename, "forceConsole": self.force_console, } return cast(LogConfigDataType, {k: v for k, v in data.items() if v is not None}) @classmethod def from_dict(cls, data: LogConfigDataType) -> LogConfig: """Return LogConfig from LogConfigDataType dict.""" return cls( data.get("enabled"), LogLevel(data["level"]) if "level" in data else None, data.get("logToFile"), data.get("filename"), data.get("forceConsole"), ) zwave-js-server-python-0.63.0/zwave_js_server/model/log_message.py000066400000000000000000000105421500374325600253550ustar00rootroot00000000000000"""Provide a model for a log message event.""" from __future__ import annotations from dataclasses import dataclass, field from typing import Literal, TypedDict from ..const import CommandClass class LogMessageContextDataType(TypedDict, total=False): """Represent a log message context data dict type.""" source: Literal["config", "serial", "controller", "driver"] # required type: Literal["controller", "value", "node"] nodeId: int header: str direction: Literal["inbound", "outbound", "none"] change: Literal["added", "removed", "updated", "notification"] internal: bool endpoint: int commandClass: int property: int | str propertyKey: int | str @dataclass class LogMessageContext: """Represent log message context information.""" data: LogMessageContextDataType = field(repr=False) source: Literal["config", "serial", "controller", "driver"] = field(init=False) type: Literal["controller", "value", "node"] | None = field(init=False) node_id: int | None = field(init=False) header: str | None = field(init=False) direction: Literal["inbound", "outbound", "none"] | None = field(init=False) change: Literal["added", "removed", "updated", "notification"] | None = field( init=False ) internal: bool | None = field(init=False) endpoint: int | None = field(init=False) command_class: CommandClass | None = field(init=False, default=None) property_: int | str | None = field(init=False) property_key: int | str | None = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.source = self.data["source"] self.type = self.data.get("type") self.node_id = self.data.get("nodeId") self.header = self.data.get("header") self.direction = self.data.get("direction") self.change = self.data.get("change") self.internal = self.data.get("internal") self.endpoint = self.data.get("endpoint") if (command_class := self.data.get("commandClass")) is not None: self.command_class = CommandClass(command_class) self.property_ = self.data.get("property") self.property_key = self.data.get("propertyKey") class LogMessageDataType(TypedDict, total=False): """Represent a log message data dict type.""" source: Literal["driver"] # required event: Literal["logging"] # required message: str | list[str] # required formattedMessage: str | list[str] # required direction: str # required level: str # required context: LogMessageContextDataType # required primaryTags: str secondaryTags: str secondaryTagPadding: int multiline: bool timestamp: str label: str def _process_message(message: str | list[str]) -> list[str]: """Process a message and always return a list.""" if isinstance(message, str): return str(message).splitlines() # We will assume each item in the array is on a separate line so we can # remove trailing line breaks return [message.rstrip("\n") for message in message] @dataclass class LogMessage: """Represent a log message.""" data: LogMessageDataType = field(repr=False) message: list[str] = field(init=False) formatted_message: list[str] = field(init=False) direction: str = field(init=False) level: str = field(init=False) context: LogMessageContext = field(init=False) primary_tags: str | None = field(init=False) secondary_tags: str | None = field(init=False) secondary_tag_padding: int | None = field(init=False) multiline: bool | None = field(init=False) timestamp: str | None = field(init=False) label: str | None = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.message = _process_message(self.data["message"]) self.formatted_message = _process_message(self.data["formattedMessage"]) self.direction = self.data["direction"] self.level = self.data["level"] self.context = LogMessageContext(self.data["context"]) self.primary_tags = self.data.get("primaryTags") self.secondary_tags = self.data.get("secondaryTags") self.secondary_tag_padding = self.data.get("secondaryTagPadding") self.multiline = self.data.get("multiline") self.timestamp = self.data.get("timestamp") self.label = self.data.get("label") zwave-js-server-python-0.63.0/zwave_js_server/model/node/000077500000000000000000000000001500374325600234415ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/model/node/__init__.py000066400000000000000000001210211500374325600255470ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS node.""" from __future__ import annotations import asyncio import copy from datetime import datetime import logging from typing import TYPE_CHECKING, Any, Literal, cast from ...const import ( INTERVIEW_FAILED, NOT_INTERVIEWED, CommandClass, DateAndTime, NodeStatus, PowerLevel, Protocols, SecurityClass, ) from ...event import Event, EventBase from ...exceptions import NotFoundError, UnparseableValue, UnwriteableValue from ..command_class import CommandClassInfo from ..device_class import DeviceClass from ..device_config import DeviceConfig from ..endpoint import Endpoint, EndpointDataType from ..notification import ( EntryControlNotification, EntryControlNotificationDataType, MultilevelSwitchNotification, MultilevelSwitchNotificationDataType, NotificationNotification, NotificationNotificationDataType, PowerLevelNotification, PowerLevelNotificationDataType, ) from ..value import ( ConfigurationValue, ConfigurationValueFormat, MetaDataType, SetConfigParameterResult, SetValueResult, Value, ValueDataType, ValueMetadata, ValueNotification, _get_value_id_str_from_dict, ) from .data_model import NodeDataType from .event_model import NODE_EVENT_MODEL_MAP from .firmware import ( NodeFirmwareUpdateCapabilities, NodeFirmwareUpdateCapabilitiesDataType, NodeFirmwareUpdateProgress, NodeFirmwareUpdateProgressDataType, NodeFirmwareUpdateResult, NodeFirmwareUpdateResultDataType, ) from .health_check import ( CheckHealthProgress, LifelineHealthCheckResult, LifelineHealthCheckSummary, RouteHealthCheckResult, RouteHealthCheckSummary, TestPowerLevelProgress, ) from .statistics import NodeStatistics, NodeStatisticsDataType if TYPE_CHECKING: from ...client import Client # pylint: disable=too-many-lines _LOGGER = logging.getLogger(__package__) DEFAULT_NODE_STATISTICS = NodeStatisticsDataType( commandsTX=0, commandsRX=0, commandsDroppedTX=0, commandsDroppedRX=0, timeoutResponse=0, ) def _get_value_id_dict_from_value_data(value_data: ValueDataType) -> dict[str, Any]: """Return a value ID dict from ValueDataType.""" data = { "commandClass": value_data["commandClass"], "property": value_data["property"], } if (endpoint := value_data.get("endpoint")) is not None: data["endpoint"] = endpoint if (property_key := value_data.get("propertyKey")) is not None: data["propertyKey"] = property_key return data class Node(EventBase): """Represent a Z-Wave JS node.""" def __init__(self, client: Client, data: NodeDataType) -> None: """Initialize the node.""" super().__init__() self.client = client self.data: NodeDataType = {} self._device_config = DeviceConfig({}) self._statistics = NodeStatistics( client, data.get("statistics", DEFAULT_NODE_STATISTICS) ) self._firmware_update_progress: NodeFirmwareUpdateProgress | None = None self._device_class: DeviceClass | None = None self._last_seen: datetime | None = None self.values: dict[str, ConfigurationValue | Value] = {} self.endpoints: dict[int, Endpoint] = {} self.status_event = asyncio.Event() self.update(data) def __repr__(self) -> str: """Return the representation.""" return f"{type(self).__name__}(node_id={self.node_id})" def __hash__(self) -> int: """Return the hash.""" return hash((self.client.driver, self.node_id)) def __eq__(self, other: object) -> bool: """Return whether this instance equals another.""" if not isinstance(other, Node): return False return ( self.client.driver == other.client.driver and self.node_id == other.node_id ) def _init_value(self, val: ValueDataType) -> Value | ConfigurationValue: """Initialize a Value object from ValueDataType.""" if val["commandClass"] == CommandClass.CONFIGURATION: return ConfigurationValue(self, val) return Value(self, val) @property def node_id(self) -> int: """Return node ID property.""" return self.data["nodeId"] @property def index(self) -> int: """Return index property.""" return self.data["index"] @property def device_class(self) -> DeviceClass | None: """Return the device_class.""" return self._device_class @property def installer_icon(self) -> int | None: """Return installer icon property.""" return self.data.get("installerIcon") @property def user_icon(self) -> int | None: """Return user icon property.""" return self.data.get("userIcon") @property def status(self) -> NodeStatus: """Return the status.""" return NodeStatus(self.data["status"]) @property def ready(self) -> bool | None: """Return the ready.""" return self.data.get("ready") @property def is_listening(self) -> bool | None: """Return the is_listening.""" return self.data.get("isListening") @property def is_frequent_listening(self) -> bool | str | None: """Return the is_frequent_listening.""" return self.data.get("isFrequentListening") @property def is_routing(self) -> bool | None: """Return the is_routing.""" return self.data.get("isRouting") @property def max_data_rate(self) -> int | None: """Return the max_data_rate.""" return self.data.get("maxDataRate") @property def supported_data_rates(self) -> list[int]: """Return the supported_data_rates.""" return self.data.get("supportedDataRates", []) @property def is_secure(self) -> bool | None: """Return the is_secure.""" if (is_secure := self.data.get("isSecure")) is not None: return is_secure return None @property def protocol_version(self) -> int | None: """Return the protocol_version.""" return self.data.get("protocolVersion") @property def supports_beaming(self) -> bool | None: """Return the supports_beaming.""" return self.data.get("supportsBeaming") @property def supports_security(self) -> bool | None: """Return the supports_security.""" return self.data.get("supportsSecurity") @property def manufacturer_id(self) -> int | None: """Return the manufacturer_id.""" return self.data.get("manufacturerId") @property def product_id(self) -> int | None: """Return the product_id.""" return self.data.get("productId") @property def product_type(self) -> int | None: """Return the product_type.""" return self.data.get("productType") @property def firmware_version(self) -> str | None: """Return the firmware_version.""" return self.data.get("firmwareVersion") @property def zwave_plus_version(self) -> int | None: """Return the zwave_plus_version.""" return self.data.get("zwavePlusVersion") @property def zwave_plus_node_type(self) -> int | None: """Return the zwave_plus_node_type.""" return self.data.get("zwavePlusNodeType") @property def zwave_plus_role_type(self) -> int | None: """Return the zwave_plus_role_type.""" return self.data.get("zwavePlusRoleType") @property def name(self) -> str | None: """Return the name.""" return self.data.get("name") @property def location(self) -> str | None: """Return the location.""" return self.data.get("location") @property def device_config(self) -> DeviceConfig: """Return the device_config.""" return self._device_config @property def label(self) -> str | None: """Return the label.""" return self.data.get("label") @property def device_database_url(self) -> str | None: """Return the device database URL.""" return self.data.get("deviceDatabaseUrl") @property def endpoint_count_is_dynamic(self) -> bool | None: """Return the endpoint_count_is_dynamic.""" return self.data.get("endpointCountIsDynamic") @property def endpoints_have_identical_capabilities(self) -> bool | None: """Return the endpoints_have_identical_capabilities.""" return self.data.get("endpointsHaveIdenticalCapabilities") @property def individual_endpoint_count(self) -> int | None: """Return the individual_endpoint_count.""" return self.data.get("individualEndpointCount") @property def aggregated_endpoint_count(self) -> int | None: """Return the aggregated_endpoint_count.""" return self.data.get("aggregatedEndpointCount") @property def interview_attempts(self) -> int | None: """Return the interview_attempts.""" return self.data.get("interviewAttempts") @property def interview_stage(self) -> int | str | None: """Return the interview_stage.""" return self.data.get("interviewStage") @property def in_interview(self) -> bool: """Return whether node is currently being interviewed.""" return ( not self.ready and not self.awaiting_manual_interview and self.interview_stage != INTERVIEW_FAILED ) @property def awaiting_manual_interview(self) -> bool: """Return whether node requires a manual interview.""" return self.interview_stage in (None, NOT_INTERVIEWED) @property def command_classes(self) -> list[CommandClassInfo]: """Return all CommandClasses supported on this node.""" return self.endpoints[0].command_classes @property def statistics(self) -> NodeStatistics: """Return statistics property.""" return self._statistics @property def firmware_update_progress(self) -> NodeFirmwareUpdateProgress | None: """Return firmware update progress.""" return self._firmware_update_progress @property def highest_security_class(self) -> SecurityClass | None: """Return highest security class configured on the node.""" if (security_class := self.data.get("highestSecurityClass")) is None: return None return SecurityClass(security_class) @property def is_controller_node(self) -> bool: """Return whether the node is a controller node.""" return self.data["isControllerNode"] @property def keep_awake(self) -> bool: """Return whether the node is set to keep awake.""" return self.data["keepAwake"] @property def last_seen(self) -> datetime | None: """Return when the node was last seen.""" return self._last_seen @property def default_volume(self) -> int | float | None: """Return the default volume.""" return self.data.get("defaultVolume") @property def default_transition_duration(self) -> int | float | None: """Return the default transition duration.""" return self.data.get("defaultTransitionDuration") @property def protocol(self) -> Protocols | None: """Return the protocol used to communicate with this node.""" if "protocol" in self.data: return Protocols(self.data["protocol"]) return None def _update_endpoints(self, endpoints: list[EndpointDataType]) -> None: """Update the endpoints data.""" new_endpoints_data = {endpoint["index"]: endpoint for endpoint in endpoints} new_endpoint_idxs = set(new_endpoints_data) stale_endpoint_idxs = set(self.endpoints) - new_endpoint_idxs # Remove stale endpoints for endpoint_idx in stale_endpoint_idxs: self.endpoints.pop(endpoint_idx) # Add new endpoints or update existing ones for endpoint_idx in new_endpoint_idxs: endpoint = new_endpoints_data[endpoint_idx] values = { value_id: value for value_id, value in self.values.items() if self.index == value.endpoint } if endpoint_idx in self.endpoints: self.endpoints[endpoint_idx].update(endpoint, values) else: self.endpoints[endpoint_idx] = Endpoint( self.client, self, endpoint, values ) def _update_values(self, values: list[ValueDataType]) -> None: """Update the values data.""" new_values_data = { _get_value_id_str_from_dict(self, val): val for val in values } new_value_ids = set(new_values_data) stale_value_ids = set(self.values) - new_value_ids # Remove stale values for value_id in stale_value_ids: self.values.pop(value_id) # Updating existing values and populate new values. Preserve value order if # initializing values for the node for the first time by using the key order # which is deterministic for value_id in ( new_value_ids - stale_value_ids if stale_value_ids else list(new_values_data) ): val = new_values_data[value_id] try: if value_id in self.values: self.values[value_id].update(val) else: self.values[value_id] = self._init_value(val) except UnparseableValue: # If we can't parse the value, don't store it pass def update(self, data: NodeDataType) -> None: """Update the internal state data.""" self.data = copy.deepcopy(data) self._device_config = DeviceConfig(self.data.get("deviceConfig", {})) if (device_class := self.data.get("deviceClass")) is None: self._device_class = None else: self._device_class = DeviceClass(device_class) self._statistics = NodeStatistics( self.client, self.data.get("statistics", DEFAULT_NODE_STATISTICS) ) if last_seen := data.get("lastSeen"): self._last_seen = datetime.fromisoformat(last_seen) if not self._statistics.last_seen and self.last_seen: self._statistics.last_seen = self.last_seen self._statistics.data["lastSeen"] = self.last_seen.isoformat() self._update_values(self.data.pop("values")) self._update_endpoints(self.data.pop("endpoints")) def get_command_class_values( self, command_class: CommandClass, endpoint: int | None = None ) -> dict[str, ConfigurationValue | Value]: """Return all values for a given command class.""" return { value_id: value for value_id, value in self.values.items() if value.command_class == command_class and (endpoint is None or value.endpoint == endpoint) } def get_configuration_values(self) -> dict[str, ConfigurationValue]: """Return all configuration values for a node.""" return cast( dict[str, ConfigurationValue], self.get_command_class_values(CommandClass.CONFIGURATION), ) def receive_event(self, event: Event) -> None: """Receive an event.""" NODE_EVENT_MODEL_MAP[event.type].from_dict(event.data) self._handle_event_protocol(event) event.data["node"] = self self.emit(event.type, event.data) async def async_send_command( self, cmd: str, require_schema: int | None = None, wait_for_result: bool | None = None, **cmd_kwargs: Any, ) -> dict[str, Any] | None: """ Send a node command. For internal use only. If wait_for_result is not None, it will take precedence, otherwise we will decide to wait or not based on the node status. """ kwargs = {} message = {"command": f"node.{cmd}", "nodeId": self.node_id, **cmd_kwargs} if require_schema is not None: kwargs["require_schema"] = require_schema if wait_for_result: result = await self.client.async_send_command(message, **kwargs) return result if wait_for_result is None and self.status not in ( NodeStatus.ASLEEP, NodeStatus.DEAD, ): result_task = asyncio.create_task( self.client.async_send_command(message, **kwargs) ) status_task = asyncio.create_task(self.status_event.wait()) await asyncio.wait( [result_task, status_task], return_when=asyncio.FIRST_COMPLETED, ) status_task.cancel() if self.status_event.is_set() and not result_task.done(): result_task.cancel() return None return result_task.result() await self.client.async_send_command_no_wait(message, **kwargs) return None async def async_set_value( self, val: Value | str, new_value: Any, options: dict | None = None, wait_for_result: bool | None = None, ) -> SetValueResult | None: """Send setValue command to Node for given value (or value_id).""" # a value may be specified as value_id or the value itself if not isinstance(val, Value): if val not in self.values: raise NotFoundError(f"Value {val} not found on node {self}") val = self.values[val] if val.metadata.writeable is False: raise UnwriteableValue cmd_args = { "valueId": _get_value_id_dict_from_value_data(val.data), "value": new_value, } if options: option = next( ( option for option in options if option not in val.metadata.value_change_options ), None, ) if option is not None: raise NotFoundError( f"Option {option} not found on value {val} on node {self}" ) cmd_args["options"] = options # the value object needs to be send to the server result = await self.async_send_command( "set_value", **cmd_args, require_schema=29, wait_for_result=wait_for_result ) if result is None: return None return SetValueResult(result["result"]) async def async_refresh_info(self) -> None: """Send refreshInfo command to Node.""" await self.async_send_command("refresh_info", wait_for_result=False) async def async_refresh_values(self) -> None: """Send refreshValues command to Node.""" await self.async_send_command( "refresh_values", wait_for_result=False, require_schema=4 ) async def async_refresh_cc_values(self, command_class: CommandClass) -> None: """Send refreshCCValues command to Node.""" await self.async_send_command( "refresh_cc_values", commandClass=command_class, wait_for_result=False, require_schema=4, ) async def async_get_defined_value_ids(self) -> list[Value]: """Send getDefinedValueIDs command to Node.""" data = await self.async_send_command( "get_defined_value_ids", wait_for_result=True ) assert data return [ self._init_value(cast(ValueDataType, value_id)) for value_id in data["valueIds"] ] async def async_get_value_metadata(self, val: Value | str) -> ValueMetadata: """Send getValueMetadata command to Node.""" # a value may be specified as value_id or the value itself if not isinstance(val, Value): val = self.values[val] # the value object needs to be send to the server data = await self.async_send_command( "get_value_metadata", valueId=_get_value_id_dict_from_value_data(val.data), wait_for_result=True, ) return ValueMetadata(cast(MetaDataType, data)) async def async_get_firmware_update_capabilities( self, ) -> NodeFirmwareUpdateCapabilities: """Send getFirmwareUpdateCapabilities command to Node.""" data = await self.async_send_command( "get_firmware_update_capabilities", require_schema=7, wait_for_result=True, ) assert data return NodeFirmwareUpdateCapabilities( cast(NodeFirmwareUpdateCapabilitiesDataType, data["capabilities"]) ) async def async_get_firmware_update_capabilities_cached( self, ) -> NodeFirmwareUpdateCapabilities: """Send getFirmwareUpdateCapabilitiesCached command to Node.""" data = await self.async_send_command( "get_firmware_update_capabilities_cached", require_schema=21, wait_for_result=True, ) assert data return NodeFirmwareUpdateCapabilities( cast(NodeFirmwareUpdateCapabilitiesDataType, data["capabilities"]) ) async def async_abort_firmware_update(self) -> None: """Send abortFirmwareUpdate command to Node.""" await self.async_send_command("abort_firmware_update", wait_for_result=False) async def async_poll_value(self, val: Value | str) -> None: """Send pollValue command to Node for given value (or value_id).""" # a value may be specified as value_id or the value itself if not isinstance(val, Value): val = self.values[val] await self.async_send_command( "poll_value", valueId=_get_value_id_dict_from_value_data(val.data), require_schema=1, ) async def async_ping(self) -> bool: """Send ping command to Node.""" data = ( await self.async_send_command( "ping", require_schema=5, wait_for_result=True ) or {} ) return cast(bool, data.get("responded", False)) async def async_invoke_cc_api( self, command_class: CommandClass, method_name: str, *args: Any, wait_for_result: bool | None = None, ) -> Any: """Call endpoint.invoke_cc_api command.""" return await self.endpoints[0].async_invoke_cc_api( command_class, method_name, *args, wait_for_result=wait_for_result ) async def async_supports_cc_api(self, command_class: CommandClass) -> bool: """Call endpoint.supports_cc_api command.""" return await self.endpoints[0].async_supports_cc_api(command_class) async def async_supports_cc(self, command_class: CommandClass) -> bool: """Call endpoint.supports_cc command.""" return await self.endpoints[0].async_supports_cc(command_class) async def async_controls_cc(self, command_class: CommandClass) -> bool: """Call endpoint.controls_cc command.""" return await self.endpoints[0].async_controls_cc(command_class) async def async_is_cc_secure(self, command_class: CommandClass) -> bool: """Call endpoint.is_cc_secure command.""" return await self.endpoints[0].async_is_cc_secure(command_class) async def async_get_cc_version(self, command_class: CommandClass) -> bool: """Call endpoint.get_cc_version command.""" return await self.endpoints[0].async_get_cc_version(command_class) async def async_get_node_unsafe(self) -> NodeDataType: """Call endpoint.get_node_unsafe command.""" return await self.endpoints[0].async_get_node_unsafe() async def async_has_security_class( self, security_class: SecurityClass ) -> bool | None: """Return whether node has the given security class.""" data = await self.async_send_command( "has_security_class", securityClass=security_class, require_schema=8, wait_for_result=True, ) if data and (has_security_class := data.get("hasSecurityClass")) is not None: return cast(bool, has_security_class) return None async def async_get_highest_security_class(self) -> SecurityClass | None: """Get the highest security class that a node supports.""" data = await self.async_send_command( "get_highest_security_class", require_schema=8, wait_for_result=True ) if data and (security_class := data.get("highestSecurityClass")) is not None: return SecurityClass(security_class) return None async def async_test_power_level( self, test_node: Node, power_level: PowerLevel, test_frame_count: int ) -> int: """Send testPowerLevel command to Node.""" data = await self.async_send_command( "test_powerlevel", testNodeId=test_node.node_id, powerlevel=power_level, testFrameCount=test_frame_count, require_schema=13, wait_for_result=True, ) assert data return cast(int, data["framesAcked"]) async def async_check_lifeline_health( self, rounds: int | None = None ) -> LifelineHealthCheckSummary: """Send checkLifelineHealth command to Node.""" kwargs = {} if rounds is not None: kwargs["rounds"] = rounds data = await self.async_send_command( "check_lifeline_health", require_schema=13, wait_for_result=True, **kwargs, ) assert data return LifelineHealthCheckSummary(data["summary"]) async def async_check_route_health( self, target_node: Node, rounds: int | None = None ) -> RouteHealthCheckSummary: """Send checkRouteHealth command to Node.""" kwargs = {"targetNodeId": target_node.node_id} if rounds is not None: kwargs["rounds"] = rounds data = await self.async_send_command( "check_route_health", require_schema=13, wait_for_result=True, **kwargs, ) assert data return RouteHealthCheckSummary(data["summary"]) async def async_get_state(self) -> NodeDataType: """Get node state.""" data = await self.async_send_command( "get_state", require_schema=14, wait_for_result=True ) assert data return cast(NodeDataType, data["state"]) async def async_set_name( self, name: str, update_cc: bool = True, wait_for_result: bool | None = None ) -> None: """Set node name.""" # If we may not potentially update the name CC, we should just wait for the # result because the change is local to the driver if not update_cc: wait_for_result = True await self.async_send_command( "set_name", name=name, updateCC=update_cc, wait_for_result=wait_for_result, require_schema=14, ) self.data["name"] = name async def async_set_location( self, location: str, update_cc: bool = True, wait_for_result: bool | None = None, ) -> None: """Set node location.""" # If we may not potentially update the location CC, we should just wait for the # result because the change is local to the driver if not update_cc: wait_for_result = True await self.async_send_command( "set_location", location=location, updateCC=update_cc, wait_for_result=wait_for_result, require_schema=14, ) self.data["location"] = location async def async_is_firmware_update_in_progress(self) -> bool: """ Send isFirmwareUpdateInProgress command to Node. If `True`, a firmware update for this node is in progress. """ data = await self.async_send_command( "is_firmware_update_in_progress", require_schema=21, wait_for_result=True ) assert data return cast(bool, data["progress"]) async def async_set_keep_awake(self, keep_awake: bool) -> None: """Set node keep awake state.""" await self.async_send_command( "set_keep_awake", keepAwake=keep_awake, wait_for_result=True, require_schema=14, ) self.data["keepAwake"] = keep_awake async def async_interview(self) -> None: """Interview node.""" await self.async_send_command( "interview", wait_for_result=False, require_schema=22, ) async def async_get_value_timestamp(self, val: Value | str) -> int: """Send getValueTimestamp command to Node for given value (or value_id).""" # a value may be specified as value_id or the value itself if not isinstance(val, Value): val = self.values[val] data = await self.async_send_command( "get_value_timestamp", valueId=_get_value_id_dict_from_value_data(val.data), require_schema=27, wait_for_result=True, ) assert data return cast(int, data["timestamp"]) async def async_manually_idle_notification_value(self, val: Value | str) -> None: """Send manuallyIdleNotificationValue cmd to Node for value (or value_id).""" # a value may be specified as value_id or the value itself if not isinstance(val, Value): val = self.values[val] if val.command_class != CommandClass.NOTIFICATION: raise ValueError( "Value must be of CommandClass.NOTIFICATION to manually idle it" ) await self.async_send_command( "manually_idle_notification_value", valueId=_get_value_id_dict_from_value_data(val.data), require_schema=28, wait_for_result=False, ) async def async_set_date_and_time( self, datetime_: datetime | None = None, wait_for_result: bool | None = None ) -> bool | None: """Send setDateAndTime command to Node.""" args = {} if datetime_: args["date"] = datetime_.isoformat() data = await self.async_send_command( "set_date_and_time", **args, require_schema=28, wait_for_result=wait_for_result, ) if data: return cast(bool, data["success"]) return None async def async_get_date_and_time(self) -> DateAndTime: """Send getDateAndTime command to Node.""" data = await self.async_send_command( "get_date_and_time", require_schema=31, wait_for_result=True, ) assert data return DateAndTime(data["dateAndTime"]) async def async_is_health_check_in_progress(self) -> bool: """Send isHealthCheckInProgress command to Node.""" data = await self.async_send_command( "is_health_check_in_progress", require_schema=31, wait_for_result=True, ) assert data return cast(bool, data["progress"]) async def async_abort_health_check(self) -> None: """Send abortHealthCheck command to Node.""" await self.async_send_command( "abort_health_check", require_schema=31, wait_for_result=False, ) async def async_set_default_volume( self, default_volume: int | float | None ) -> None: """Send setDefaultVolume command to Node.""" cmd_kwargs = {} self.data["defaultVolume"] = default_volume if default_volume is not None: cmd_kwargs["defaultVolume"] = default_volume await self.async_send_command( "set_default_volume", require_schema=31, wait_for_result=None, **cmd_kwargs, ) async def async_set_default_transition_duration( self, default_duration_transition: int | float | None ) -> None: """Send setDefaultTransitionDuration command to Node.""" cmd_kwargs = {} self.data["defaultTransitionDuration"] = default_duration_transition if default_duration_transition is not None: cmd_kwargs["defaultTransitionDuration"] = default_duration_transition await self.async_send_command( "set_default_transition_duration", require_schema=31, wait_for_result=None, **cmd_kwargs, ) async def async_has_device_config_changed(self) -> bool | None: """Send hasDeviceConfigChanged command to Node.""" data = await self.async_send_command( "has_device_config_changed", require_schema=31, wait_for_result=True, ) if data and (changed := data.get("changed")) is not None: return cast(bool, changed) return None async def async_set_raw_config_parameter_value( self, new_value: int, property_: int | str, property_key: int | None = None, value_size: Literal[1, 2, 4] | None = None, value_format: ConfigurationValueFormat | None = None, ) -> SetConfigParameterResult: """Send setRawConfigParameterValue.""" return await self.endpoints[0].async_set_raw_config_parameter_value( new_value, property_, property_key, value_size, value_format ) async def async_get_raw_config_parameter_value( self, property_: int, property_key: int | None = None, allow_unexpected_response: bool | None = None, ) -> int: """Call getRawConfigParameterValue.""" return await self.endpoints[0].async_get_raw_config_parameter_value( property_, property_key, allow_unexpected_response ) def handle_test_powerlevel_progress(self, event: Event) -> None: """Process a test power level progress event.""" event.data["test_power_level_progress"] = TestPowerLevelProgress( event.data["acknowledged"], event.data["total"] ) def handle_check_lifeline_health_progress(self, event: Event) -> None: """Process a check lifeline health progress event.""" event.data["check_lifeline_health_progress"] = CheckHealthProgress( event.data["rounds"], event.data["totalRounds"], event.data["lastRating"], LifelineHealthCheckResult(event.data["lastResult"]), ) def handle_check_route_health_progress(self, event: Event) -> None: """Process a check route health progress event.""" event.data["check_route_health_progress"] = CheckHealthProgress( event.data["rounds"], event.data["totalRounds"], event.data["lastRating"], RouteHealthCheckResult(event.data["lastResult"]), ) def handle_wake_up(self, event: Event) -> None: """Process a node wake up event.""" # pylint: disable=unused-argument self.status_event.clear() self.data["status"] = NodeStatus.AWAKE def handle_sleep(self, event: Event) -> None: """Process a node sleep event.""" # pylint: disable=unused-argument self.status_event.set() self.data["status"] = NodeStatus.ASLEEP def handle_dead(self, event: Event) -> None: """Process a node dead event.""" # pylint: disable=unused-argument self.status_event.set() self.data["status"] = NodeStatus.DEAD def handle_alive(self, event: Event) -> None: """Process a node alive event.""" # pylint: disable=unused-argument self.status_event.clear() self.data["status"] = NodeStatus.ALIVE def handle_interview_started(self, event: Event) -> None: """Process a node interview started event.""" # pylint: disable=unused-argument self.data["ready"] = False self.data["interviewStage"] = None def handle_interview_stage_completed(self, event: Event) -> None: """Process a node interview stage completed event.""" self.data["interviewStage"] = event.data["stageName"] def handle_interview_failed(self, event: Event) -> None: """Process a node interview failed event.""" # pylint: disable=unused-argument self.data["interviewStage"] = INTERVIEW_FAILED def handle_interview_completed(self, event: Event) -> None: """Process a node interview completed event.""" # pylint: disable=unused-argument self.data["ready"] = True def handle_ready(self, event: Event) -> None: """Process a node ready event.""" # the event contains a full dump of the node self.update(event.data["nodeState"]) def handle_value_added(self, event: Event) -> None: """Process a node value added event.""" self.handle_value_updated(event) def handle_value_updated(self, event: Event) -> None: """Process a node value updated event.""" evt_val_data: ValueDataType = event.data["args"] value_id = _get_value_id_str_from_dict(self, evt_val_data) value = self.values.get(value_id) if value is None: value = self._init_value(evt_val_data) self.values[value.value_id] = event.data["value"] = value else: value.receive_event(event) event.data["value"] = value def handle_value_removed(self, event: Event) -> None: """Process a node value removed event.""" value_id = _get_value_id_str_from_dict(self, event.data["args"]) event.data["value"] = self.values.pop(value_id) def handle_value_notification(self, event: Event) -> None: """Process a node value notification event.""" # if value is found, use value data as base and update what is provided # in the event, otherwise use the event data event_data = event.data["args"] if value := self.values.get(_get_value_id_str_from_dict(self, event_data)): value_notification = ValueNotification( self, cast(ValueDataType, dict(value.data)) ) value_notification.update(event_data) else: value_notification = ValueNotification(self, event_data) event.data["value_notification"] = value_notification def handle_metadata_updated(self, event: Event) -> None: """Process a node metadata updated event.""" # handle metadata updated as value updated (as its a value object with # included metadata) self.handle_value_updated(event) def handle_notification(self, event: Event) -> None: """Process a node notification event.""" match command_class := CommandClass(event.data["ccId"]): case CommandClass.NOTIFICATION: event.data["notification"] = NotificationNotification( self, cast(NotificationNotificationDataType, event.data) ) case CommandClass.SWITCH_MULTILEVEL: event.data["notification"] = MultilevelSwitchNotification( self, cast(MultilevelSwitchNotificationDataType, event.data) ) case CommandClass.ENTRY_CONTROL: event.data["notification"] = EntryControlNotification( self, cast(EntryControlNotificationDataType, event.data) ) case CommandClass.POWERLEVEL: event.data["notification"] = PowerLevelNotification( self, cast(PowerLevelNotificationDataType, event.data) ) case _: _LOGGER.info( "Unhandled notification command class: %s", command_class.name ) def handle_firmware_update_progress(self, event: Event) -> None: """Process a node firmware update progress event.""" self._firmware_update_progress = event.data["firmware_update_progress"] = ( NodeFirmwareUpdateProgress( self, cast(NodeFirmwareUpdateProgressDataType, event.data["progress"]) ) ) def handle_firmware_update_finished(self, event: Event) -> None: """Process a node firmware update finished event.""" self._firmware_update_progress = None event.data["firmware_update_finished"] = NodeFirmwareUpdateResult( self, cast(NodeFirmwareUpdateResultDataType, event.data["result"]) ) def handle_statistics_updated(self, event: Event) -> None: """Process a statistics updated event.""" self.data["statistics"] = statistics = event.data["statistics"] event.data["statistics_updated"] = self._statistics = NodeStatistics( self.client, statistics ) if self._statistics.last_seen: self._last_seen = self._statistics.last_seen zwave-js-server-python-0.63.0/zwave_js_server/model/node/data_model.py000066400000000000000000000034651500374325600261140ustar00rootroot00000000000000"""Data model for a Z-Wave JS node.""" from __future__ import annotations from typing import TypedDict from ..device_class import DeviceClassDataType from ..device_config import DeviceConfigDataType from ..endpoint import EndpointDataType from ..value import ValueDataType from .statistics import NodeStatisticsDataType class FoundNodeDataType(TypedDict, total=False): """Represent a found node data dict type.""" nodeId: int deviceClass: DeviceClassDataType supportedCCs: list[int] controlledCCs: list[int] class NodeDataType(TypedDict, total=False): """Represent a node data dict type.""" nodeId: int # required index: int # required deviceClass: DeviceClassDataType | None installerIcon: int userIcon: int name: str location: str status: int # 0-4 # required zwavePlusVersion: int zwavePlusNodeType: int zwavePlusRoleType: int isListening: bool isFrequentListening: bool | str isRouting: bool maxDataRate: int supportedDataRates: list[int] isSecure: bool supportsBeaming: bool supportsSecurity: bool protocolVersion: int firmwareVersion: str manufacturerId: int productId: int productType: int deviceConfig: DeviceConfigDataType deviceDatabaseUrl: str keepAwake: bool ready: bool label: str endpoints: list[EndpointDataType] endpointCountIsDynamic: bool endpointsHaveIdenticalCapabilities: bool individualEndpointCount: int aggregatedEndpointCount: int interviewAttempts: int interviewStage: int | str | None values: list[ValueDataType] statistics: NodeStatisticsDataType highestSecurityClass: int isControllerNode: bool lastSeen: str defaultVolume: int | float | None defaultTransitionDuration: int | float | None protocol: int zwave-js-server-python-0.63.0/zwave_js_server/model/node/event_model.py000066400000000000000000000235071500374325600263230ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS node's events.""" from __future__ import annotations from typing import Literal from ...const import CommandClass from ...event import BaseEventModel from ..notification import ( EntryControlNotificationArgsDataType, MultilevelSwitchNotificationArgsDataType, NotificationNotificationArgsDataType, PowerLevelNotificationArgsDataType, ) from ..value import ValueDataType from .data_model import NodeDataType from .firmware import ( NodeFirmwareUpdateProgressDataType, NodeFirmwareUpdateResultDataType, ) from .statistics import NodeStatisticsDataType try: from pydantic.v1 import BaseModel except ImportError: from pydantic import BaseModel class BaseNodeEventModel(BaseEventModel): """Base model for a node event.""" source: Literal["node"] nodeId: int @classmethod def from_dict(cls, data: dict) -> BaseNodeEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], ) class AliveEventModel(BaseNodeEventModel): """Model for `alive` event data.""" event: Literal["alive"] class CheckHealthProgressEventModel(BaseNodeEventModel): """ Model for `check health progress` type events data. Includes `check lifeline health progress` and `check route health progress` events. """ rounds: int totalRounds: int lastRating: int @classmethod def from_dict(cls, data: dict) -> CheckHealthProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], rounds=data["rounds"], totalRounds=data["totalRounds"], lastRating=data["lastRating"], ) class CheckLifelineHealthProgressEventModel(CheckHealthProgressEventModel): """Model for `check lifeline health progress` event data.""" event: Literal["check lifeline health progress"] class CheckRouteHealthProgressEventModel(CheckHealthProgressEventModel): """Model for `check route health progress` event data.""" event: Literal["check route health progress"] class DeadEventModel(BaseNodeEventModel): """Model for `dead` event data.""" event: Literal["dead"] class InterviewCompletedEventModel(BaseNodeEventModel): """Model for `interview completed` event data.""" event: Literal["interview completed"] class InterviewFailedEventArgsModel(BaseModel): """Model for `interview failed` event args.""" errorMessage: str isFinal: bool attempt: int | None maxAttempts: int | None @classmethod def from_dict(cls, data: dict) -> InterviewFailedEventArgsModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], errorMessage=data["errorMessage"], isFinal=data["isFinal"], attempt=data["attempt"], maxAttempts=data["maxAttempts"], ) class InterviewFailedEventModel(BaseNodeEventModel): """Model for `interview failed` event data.""" event: Literal["interview failed"] args: InterviewFailedEventArgsModel @classmethod def from_dict(cls, data: dict) -> InterviewFailedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], args=data["args"], ) class InterviewStageCompletedEventModel(BaseNodeEventModel): """Model for `interview stage completed` event data.""" event: Literal["interview stage completed"] stageName: str @classmethod def from_dict(cls, data: dict) -> InterviewStageCompletedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], stageName=data["stageName"], ) class InterviewStartedEventModel(BaseNodeEventModel): """Model for `interview started` event data.""" event: Literal["interview started"] class NotificationEventModel(BaseNodeEventModel): """Model for `notification` event data.""" event: Literal["notification"] nodeId: int endpointIndex: int ccId: CommandClass args: ( NotificationNotificationArgsDataType | EntryControlNotificationArgsDataType | PowerLevelNotificationArgsDataType | MultilevelSwitchNotificationArgsDataType ) @classmethod def from_dict(cls, data: dict) -> NotificationEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], endpointIndex=data["endpointIndex"], ccId=data["ccId"], args=data["args"], ) class ReadyEventModel(BaseNodeEventModel): """Model for `ready` event data.""" event: Literal["ready"] nodeState: NodeDataType @classmethod def from_dict(cls, data: dict) -> ReadyEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], nodeState=data["nodeState"], ) class SleepEventModel(BaseNodeEventModel): """Model for `sleep` event data.""" event: Literal["sleep"] class StatisticsUpdatedEventModel(BaseNodeEventModel): """Model for `statistics updated` event data.""" event: Literal["statistics updated"] statistics: NodeStatisticsDataType @classmethod def from_dict(cls, data: dict) -> StatisticsUpdatedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], statistics=data["statistics"], ) class TestPowerLevelProgressEventModel(BaseNodeEventModel): """Model for `test powerlevel progress` event data.""" event: Literal["test powerlevel progress"] acknowledged: int total: int @classmethod def from_dict(cls, data: dict) -> TestPowerLevelProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], acknowledged=data["acknowledged"], total=data["total"], ) class ValueEventModel(BaseNodeEventModel): """ Model for `value` events data. Subclass for event models for `metadata updated`, `value added`, `value notification`, `value removed`, and `value updated`. """ args: ValueDataType @classmethod def from_dict(cls, data: dict) -> ValueEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], args=data["args"], ) class MetadataUpdatedEventModel(ValueEventModel): """Model for `metadata updated` event data.""" event: Literal["metadata updated"] class ValueAddedEventModel(ValueEventModel): """Model for `value added` event data.""" event: Literal["value added"] class ValueNotificationEventModel(ValueEventModel): """Model for `value notification` event data.""" event: Literal["value notification"] class ValueRemovedEventModel(ValueEventModel): """Model for `value removed` event data.""" event: Literal["value removed"] class ValueUpdatedEventModel(ValueEventModel): """Model for `value updated` event data.""" event: Literal["value updated"] class WakeUpEventModel(BaseNodeEventModel): """Model for `wake up` event data.""" event: Literal["wake up"] class FirmwareUpdateFinishedEventModel(BaseNodeEventModel): """Model for `firmware update finished` event data.""" event: Literal["firmware update finished"] result: NodeFirmwareUpdateResultDataType @classmethod def from_dict(cls, data: dict) -> FirmwareUpdateFinishedEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], result=data["result"], ) class FirmwareUpdateProgressEventModel(BaseNodeEventModel): """Model for `firmware update progress` event data.""" event: Literal["firmware update progress"] progress: NodeFirmwareUpdateProgressDataType @classmethod def from_dict(cls, data: dict) -> FirmwareUpdateProgressEventModel: """Initialize from dict.""" return cls( source=data["source"], event=data["event"], nodeId=data["nodeId"], progress=data["progress"], ) NODE_EVENT_MODEL_MAP: dict[str, type[BaseNodeEventModel]] = { "alive": AliveEventModel, "check lifeline health progress": CheckLifelineHealthProgressEventModel, "check route health progress": CheckRouteHealthProgressEventModel, "dead": DeadEventModel, "firmware update finished": FirmwareUpdateFinishedEventModel, "firmware update progress": FirmwareUpdateProgressEventModel, "interview completed": InterviewCompletedEventModel, "interview failed": InterviewFailedEventModel, "interview stage completed": InterviewStageCompletedEventModel, "interview started": InterviewStartedEventModel, "metadata updated": MetadataUpdatedEventModel, "notification": NotificationEventModel, "ready": ReadyEventModel, "sleep": SleepEventModel, "statistics updated": StatisticsUpdatedEventModel, "test powerlevel progress": TestPowerLevelProgressEventModel, "value added": ValueAddedEventModel, "value notification": ValueNotificationEventModel, "value removed": ValueRemovedEventModel, "value updated": ValueUpdatedEventModel, "wake up": WakeUpEventModel, } zwave-js-server-python-0.63.0/zwave_js_server/model/node/firmware.py000066400000000000000000000237461500374325600256430ustar00rootroot00000000000000"""Provide a model for Z-Wave firmware.""" from __future__ import annotations from dataclasses import asdict, dataclass, field from enum import IntEnum from typing import TYPE_CHECKING, Literal, TypedDict, cast from ...const import VALUE_UNKNOWN, RFRegion from ...util.helpers import convert_bytes_to_base64 if TYPE_CHECKING: from . import Node class NodeFirmwareUpdateDataDataType(TypedDict, total=False): """Represent a firmware update data dict type.""" filename: str # required file: str # required fileFormat: str firmwareTarget: int @dataclass class NodeFirmwareUpdateData: """Firmware update data.""" filename: str file: bytes file_format: str | None = None firmware_target: int | None = None def to_dict(self) -> NodeFirmwareUpdateDataDataType: """Convert firmware update data to dict.""" data: NodeFirmwareUpdateDataDataType = { "filename": self.filename, "file": convert_bytes_to_base64(self.file), } if self.file_format is not None: data["fileFormat"] = self.file_format if self.firmware_target is not None: data["firmwareTarget"] = self.firmware_target return data class NodeFirmwareUpdateCapabilitiesDataType(TypedDict, total=False): """Represent a firmware update capabilities dict type.""" firmwareUpgradable: bool # required firmwareTargets: list[int] continuesToFunction: bool | str supportsActivation: bool | str class NodeFirmwareUpdateCapabilitiesDict(TypedDict, total=False): """Represent a dict from FirmwareUpdateCapabilities.""" firmware_upgradable: bool # required firmware_targets: list[int] continues_to_function: bool | None supports_activation: bool | None @dataclass class NodeFirmwareUpdateCapabilities: """Model for firmware update capabilities.""" data: NodeFirmwareUpdateCapabilitiesDataType = field(repr=False) firmware_upgradable: bool = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.firmware_upgradable = self.data["firmwareUpgradable"] @property def firmware_targets(self) -> list[int]: """Return firmware targets.""" if not self.firmware_upgradable: raise TypeError("Firmware is not upgradeable.") return self.data["firmwareTargets"] @property def continues_to_function(self) -> bool | None: """Return whether node continues to function during update.""" if not self.firmware_upgradable: raise TypeError("Firmware is not upgradeable.") if (val := self.data["continuesToFunction"]) == VALUE_UNKNOWN: return None assert isinstance(val, bool) return val @property def supports_activation(self) -> bool | None: """Return whether node supports delayed activation of the new firmware.""" if not self.firmware_upgradable: raise TypeError("Firmware is not upgradeable.") if (val := self.data["supportsActivation"]) == VALUE_UNKNOWN: return None assert isinstance(val, bool) return val def to_dict(self) -> NodeFirmwareUpdateCapabilitiesDict: """Return dict representation of the object.""" if not self.firmware_upgradable: return {"firmware_upgradable": self.firmware_upgradable} return { "firmware_upgradable": self.firmware_upgradable, "firmware_targets": self.firmware_targets, "continues_to_function": self.continues_to_function, "supports_activation": self.supports_activation, } class NodeFirmwareUpdateStatus(IntEnum): """Enum with all node firmware update status values. https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotfirmware-update-finishedquot """ ERROR_TIMEOUT = -1 ERROR_CHECKSUM = 0 ERROR_TRANSMISSION_FAILED = 1 ERROR_INVALID_MANUFACTURER_ID = 2 ERROR_INVALID_FIRMWARE_ID = 3 ERROR_INVALID_FIRMWARE_TARGET = 4 ERROR_INVALID_HEADER_INFORMATION = 5 ERROR_INVALID_HEADER_FORMAT = 6 ERROR_INSUFFICIENT_MEMORY = 7 ERROR_INVALID_HARDWARE_VERSION = 8 OK_WAITING_FOR_ACTIVATION = 253 OK_NO_RESTART = 254 OK_RESTART_PENDING = 255 class NodeFirmwareUpdateProgressDataType(TypedDict): """Represent a node firmware update progress dict type.""" currentFile: int totalFiles: int sentFragments: int totalFragments: int progress: float @dataclass class NodeFirmwareUpdateProgress: """Model for a node firmware update progress data.""" node: Node data: NodeFirmwareUpdateProgressDataType = field(repr=False) current_file: int = field(init=False) total_files: int = field(init=False) sent_fragments: int = field(init=False) total_fragments: int = field(init=False) progress: float = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.current_file = self.data["currentFile"] self.total_files = self.data["totalFiles"] self.sent_fragments = self.data["sentFragments"] self.total_fragments = self.data["totalFragments"] self.progress = float(self.data["progress"]) class NodeFirmwareUpdateResultDataType(TypedDict, total=False): """Represent a node firmware update result dict type.""" status: int # required success: bool # required waitTime: int reInterview: bool # required @dataclass class NodeFirmwareUpdateResult: """Model for node firmware update result data.""" node: Node data: NodeFirmwareUpdateResultDataType = field(repr=False) status: NodeFirmwareUpdateStatus = field(init=False) success: bool = field(init=False) wait_time: int | None = field(init=False) reinterview: bool = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.status = NodeFirmwareUpdateStatus(self.data["status"]) self.success = self.data["success"] self.wait_time = self.data.get("waitTime") self.reinterview = self.data["reInterview"] class NodeFirmwareUpdateFileInfoDataType(TypedDict): """Represent a firmware update file info data dict type.""" target: int url: str integrity: str # sha256 @dataclass class NodeFirmwareUpdateFileInfo: """Represent a firmware update file info.""" target: int url: str integrity: str @classmethod def from_dict( cls, data: NodeFirmwareUpdateFileInfoDataType ) -> NodeFirmwareUpdateFileInfo: """Initialize from dict.""" return cls( target=data["target"], url=data["url"], integrity=data["integrity"], ) def to_dict(self) -> NodeFirmwareUpdateFileInfoDataType: """Return dict representation of the object.""" return cast(NodeFirmwareUpdateFileInfoDataType, asdict(self)) class NodeFirmwareUpdateDeviceIDDataType(TypedDict, total=False): """Represent a firmware update device ID dict type.""" manufacturerId: int # required productType: int # required productId: int # required firmwareVersion: str # required rfRegion: int @dataclass class NodeFirmwareUpdateDeviceID: """Represent a firmware update device ID.""" manufacturer_id: int product_type: int product_id: int firmware_version: str rf_region: RFRegion | None @classmethod def from_dict( cls, data: NodeFirmwareUpdateDeviceIDDataType ) -> NodeFirmwareUpdateDeviceID: """Initialize from dict.""" return cls( manufacturer_id=data["manufacturerId"], product_type=data["productType"], product_id=data["productId"], firmware_version=data["firmwareVersion"], rf_region=RFRegion(data["rfRegion"]) if "rfRegion" in data else None, ) def to_dict(self) -> NodeFirmwareUpdateDeviceIDDataType: """Return dict representation of the object.""" data = { "manufacturerId": self.manufacturer_id, "productType": self.product_type, "productId": self.product_id, "firmwareVersion": self.firmware_version, } if self.rf_region is not None: data["rfRegion"] = self.rf_region return cast(NodeFirmwareUpdateDeviceIDDataType, data) class NodeFirmwareUpdateInfoDataType(TypedDict, total=False): """Represent a firmware update info data dict type.""" version: str changelog: str channel: Literal["stable", "beta"] files: list[NodeFirmwareUpdateFileInfoDataType] downgrade: bool normalizedVersion: str device: NodeFirmwareUpdateDeviceIDDataType @dataclass class NodeFirmwareUpdateInfo: """Represent a firmware update info.""" version: str changelog: str channel: Literal["stable", "beta"] files: list[NodeFirmwareUpdateFileInfo] downgrade: bool normalized_version: str device: NodeFirmwareUpdateDeviceID @classmethod def from_dict(cls, data: NodeFirmwareUpdateInfoDataType) -> NodeFirmwareUpdateInfo: """Initialize from dict.""" return cls( version=data["version"], changelog=data["changelog"], channel=data["channel"], files=[ NodeFirmwareUpdateFileInfo.from_dict(file) for file in data["files"] ], downgrade=data["downgrade"], normalized_version=data["normalizedVersion"], device=NodeFirmwareUpdateDeviceID.from_dict(data["device"]), ) def to_dict(self) -> NodeFirmwareUpdateInfoDataType: """Return dict representation of the object.""" return cast( NodeFirmwareUpdateInfoDataType, { "version": self.version, "changelog": self.changelog, "channel": self.channel, "files": [file.to_dict() for file in self.files], "downgrade": self.downgrade, "normalizedVersion": self.normalized_version, "device": self.device.to_dict(), }, ) zwave-js-server-python-0.63.0/zwave_js_server/model/node/health_check.py000066400000000000000000000123351500374325600264210ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS node's health checks and power tests.""" from __future__ import annotations from dataclasses import dataclass, field from typing import TypedDict from ...const import PowerLevel class LifelineHealthCheckResultDataType(TypedDict, total=False): """Represent a lifeline health check result data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/Types.ts#L171 latency: int # required numNeighbors: int # required failedPingsNode: int # required rating: int # required routeChanges: int minPowerlevel: int failedPingsController: int snrMargin: int class LifelineHealthCheckSummaryDataType(TypedDict): """Represent a lifeline health check summary data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/_Types.ts#L254 results: list[LifelineHealthCheckResultDataType] rating: int @dataclass class LifelineHealthCheckResult: """Represent a lifeline health check result.""" data: LifelineHealthCheckResultDataType = field(repr=False) latency: int = field(init=False) num_neighbors: int = field(init=False) failed_pings_node: int = field(init=False) rating: int = field(init=False) route_changes: int | None = field(init=False) min_power_level: PowerLevel | None = field(init=False, default=None) failed_pings_controller: int | None = field(init=False) snr_margin: int | None = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.latency = self.data["latency"] self.num_neighbors = self.data["numNeighbors"] self.failed_pings_node = self.data["failedPingsNode"] self.rating = self.data["rating"] self.route_changes = self.data.get("routeChanges") if (min_power_level := self.data.get("minPowerlevel")) is not None: self.min_power_level = PowerLevel(min_power_level) self.failed_pings_controller = self.data.get("failedPingsController") self.snr_margin = self.data.get("snrMargin") @dataclass class LifelineHealthCheckSummary: """Represent a lifeline health check summary update.""" data: LifelineHealthCheckSummaryDataType = field(repr=False) rating: int = field(init=False) results: list[LifelineHealthCheckResult] = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.rating = self.data["rating"] self.results = [ LifelineHealthCheckResult(r) for r in self.data.get("results", []) ] class RouteHealthCheckResultDataType(TypedDict, total=False): """Represent a route health check result data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/_Types.ts#L285 numNeighbors: int # required rating: int # required failedPingsToTarget: int failedPingsToSource: int minPowerlevelSource: int minPowerlevelTarget: int class RouteHealthCheckSummaryDataType(TypedDict): """Represent a route health check summary data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/_Types.ts#L317 results: list[RouteHealthCheckResultDataType] rating: int @dataclass class RouteHealthCheckResult: """Represent a route health check result.""" data: RouteHealthCheckResultDataType = field(repr=False) num_neighbors: int = field(init=False) rating: int = field(init=False) failed_pings_to_target: int | None = field(init=False) failed_pings_to_source: int | None = field(init=False) min_power_level_source: PowerLevel | None = field(init=False, default=None) min_power_level_target: PowerLevel | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialize.""" self.num_neighbors = self.data["numNeighbors"] self.rating = self.data["rating"] self.failed_pings_to_target = self.data.get("failedPingsToTarget") self.failed_pings_to_source = self.data.get("failedPingsToSource") if (min_power_level_source := self.data.get("minPowerlevelSource")) is not None: self.min_power_level_source = PowerLevel(min_power_level_source) if (min_power_level_target := self.data.get("minPowerlevelTarget")) is not None: self.min_power_level_target = PowerLevel(min_power_level_target) @dataclass class RouteHealthCheckSummary: """Represent a route health check summary update.""" data: RouteHealthCheckSummaryDataType = field(repr=False) rating: int = field(init=False) results: list[RouteHealthCheckResult] = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.rating = self.data["rating"] self.results = [RouteHealthCheckResult(r) for r in self.data.get("results", [])] @dataclass class TestPowerLevelProgress: """Class to represent a test power level progress update.""" acknowledged: int total: int @dataclass class CheckHealthProgress: """Represent a check lifeline/route health progress update.""" rounds: int total_rounds: int last_rating: int last_result: LifelineHealthCheckResult | RouteHealthCheckResult zwave-js-server-python-0.63.0/zwave_js_server/model/node/statistics.py000066400000000000000000000054671500374325600262210ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS node's statistics.""" from __future__ import annotations from contextlib import suppress from dataclasses import dataclass, field from datetime import datetime from typing import TYPE_CHECKING, TypedDict from zwave_js_server.exceptions import RssiErrorReceived from ...const import RssiError from ..statistics import RouteStatistics, RouteStatisticsDataType if TYPE_CHECKING: from ...client import Client class NodeStatisticsDataType(TypedDict, total=False): """Represent a node statistics data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/NodeStatistics.ts#L21-L33 commandsTX: int # required commandsRX: int # required commandsDroppedTX: int # required commandsDroppedRX: int # required timeoutResponse: int # required rtt: int rssi: int lwr: RouteStatisticsDataType nlwr: RouteStatisticsDataType lastSeen: str @dataclass class NodeStatistics: """Represent a node statistics update.""" client: Client = field(repr=False) data: NodeStatisticsDataType = field(repr=False) commands_tx: int = field(init=False) commands_rx: int = field(init=False) commands_dropped_rx: int = field(init=False) commands_dropped_tx: int = field(init=False) timeout_response: int = field(init=False) rtt: int | None = field(init=False) lwr: RouteStatistics | None = field(init=False, default=None) nlwr: RouteStatistics | None = field(init=False, default=None) last_seen: datetime | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialize.""" self.commands_tx = self.data["commandsTX"] self.commands_rx = self.data["commandsRX"] self.commands_dropped_rx = self.data["commandsDroppedRX"] self.commands_dropped_tx = self.data["commandsDroppedTX"] self.timeout_response = self.data["timeoutResponse"] self.rtt = self.data.get("rtt") if last_seen := self.data.get("lastSeen"): self.last_seen = datetime.fromisoformat(last_seen) if lwr := self.data.get("lwr"): with suppress(ValueError): self.lwr = RouteStatistics(self.client, lwr) if nlwr := self.data.get("nlwr"): with suppress(ValueError): self.nlwr = RouteStatistics(self.client, nlwr) @property def rssi(self) -> int | None: """ Return average RSSI of frames received by this node. Consecutive non-error measurements are combined using an exponential moving average. """ if not self.data or (rssi_ := self.data.get("rssi")) is None: return None if rssi_ in [item.value for item in RssiError]: raise RssiErrorReceived(RssiError(rssi_)) return rssi_ zwave-js-server-python-0.63.0/zwave_js_server/model/notification.py000066400000000000000000000140251500374325600255560ustar00rootroot00000000000000""" Model for a Zwave Node's Notification Event. https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotnotificationquot """ from __future__ import annotations from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any, Literal, TypedDict from ..const.command_class.multilevel_switch import MultilevelSwitchCommand from ..const.command_class.power_level import PowerLevelTestStatus from ..util.helpers import parse_buffer if TYPE_CHECKING: from .node import Node class BaseNotificationDataType(TypedDict): """Represent a base notification event data dict type.""" source: Literal["node"] # required event: Literal["notification"] # required nodeId: int # required endpointIndex: int # required ccId: int # required @dataclass class BaseNotification: """Model for a Zwave Node's notification event.""" node: Node data: BaseNotificationDataType = field(repr=False) node_id: int = field(init=False, repr=False) endpoint_idx: int = field(init=False) command_class: int = field(init=False) def __post_init__(self) -> None: """Post initialization.""" self.node_id = self.data["nodeId"] self.endpoint_idx = self.data["endpointIndex"] self.command_class = self.data["ccId"] class EntryControlNotificationArgsDataType(TypedDict, total=False): """Represent args for a Entry Control CC notification event data dict type.""" eventType: int # required eventTypeLabel: str # required dataType: int # required dataTypeLabel: str # required eventData: str | dict[str, Any] class EntryControlNotificationDataType(BaseNotificationDataType): """Represent an Entry Control CC notification event data dict type.""" args: EntryControlNotificationArgsDataType # required @dataclass class EntryControlNotification(BaseNotification): """Model for a Zwave Node's Entry Control CC notification event.""" data: EntryControlNotificationDataType = field(repr=False) event_type: int = field(init=False) event_type_label: str = field(init=False) data_type: int = field(init=False) data_type_label: str = field(init=False) event_data: str | dict[str, Any] | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialize.""" super().__post_init__() self.event_type = self.data["args"]["eventType"] self.event_type_label = self.data["args"]["eventTypeLabel"] self.data_type = self.data["args"]["dataType"] self.data_type_label = self.data["args"]["dataTypeLabel"] if event_data := self.data["args"].get("eventData"): self.event_data = parse_buffer(event_data) class NotificationNotificationArgsDataType(TypedDict, total=False): """Represent args for a Notification CC notification event data dict type.""" type: int # required label: str # required event: int # required eventLabel: str # required parameters: dict[str, Any] class NotificationNotificationDataType(BaseNotificationDataType): """Represent a Notification CC notification event data dict type.""" args: NotificationNotificationArgsDataType # required @dataclass class NotificationNotification(BaseNotification): """Model for a Zwave Node's Notification CC notification event.""" data: NotificationNotificationDataType = field(repr=False) type_: int = field(init=False) label: str = field(init=False) event: int = field(init=False) event_label: str = field(init=False) parameters: dict[str, Any] = field(init=False) def __post_init__(self) -> None: """Post initialize.""" super().__post_init__() self.type_ = self.data["args"]["type"] self.label = self.data["args"]["label"] self.event = self.data["args"]["event"] self.event_label = self.data["args"]["eventLabel"] self.parameters = self.data["args"].get("parameters", {}) class PowerLevelNotificationArgsDataType(TypedDict): """Represent args for a Power Level CC notification event data dict type.""" testNodeId: int status: int acknowledgedFrames: int class PowerLevelNotificationDataType(BaseNotificationDataType): """Represent a Power Level CC notification event data dict type.""" args: PowerLevelNotificationArgsDataType # required @dataclass class PowerLevelNotification(BaseNotification): """Model for a Zwave Node's Power Level CC notification event.""" data: PowerLevelNotificationDataType = field(repr=False) test_node_id: int = field(init=False) status: PowerLevelTestStatus = field(init=False) acknowledged_frames: int = field(init=False) def __post_init__(self) -> None: """Post initialize.""" super().__post_init__() self.test_node_id = self.data["args"]["testNodeId"] self.status = PowerLevelTestStatus(self.data["args"]["status"]) self.acknowledged_frames = self.data["args"]["acknowledgedFrames"] class MultilevelSwitchNotificationArgsDataType(TypedDict, total=False): """Represent args for a Multi Level Switch CC notification event data dict type.""" eventType: int # required eventTypeLabel: str # required direction: str class MultilevelSwitchNotificationDataType(BaseNotificationDataType): """Represent a Multi Level Switch CC notification event data dict type.""" args: MultilevelSwitchNotificationArgsDataType # required @dataclass class MultilevelSwitchNotification(BaseNotification): """Model for a Zwave Node's Multi Level CC notification event.""" data: MultilevelSwitchNotificationDataType = field(repr=False) event_type: MultilevelSwitchCommand = field(init=False) event_type_label: str = field(init=False) direction: str | None = field(init=False) def __post_init__(self) -> None: """Post initialize.""" super().__post_init__() self.event_type = MultilevelSwitchCommand(self.data["args"]["eventType"]) self.event_type_label = self.data["args"]["eventTypeLabel"] self.direction = self.data["args"].get("direction") zwave-js-server-python-0.63.0/zwave_js_server/model/statistics.py000066400000000000000000000062411500374325600252630ustar00rootroot00000000000000"""Common models for statistics.""" from __future__ import annotations from dataclasses import dataclass, field from functools import cached_property from typing import TYPE_CHECKING, TypedDict from zwave_js_server.exceptions import RepeaterRssiErrorReceived, RssiErrorReceived from ..const import ProtocolDataRate, RssiError if TYPE_CHECKING: from ..client import Client from .node import Node class RouteStatisticsDataType(TypedDict, total=False): """Represent a route statistics data dict type.""" protocolDataRate: int repeaters: list[int] rssi: int repeaterRSSI: list[int] routeFailedBetween: list[int] class RouteStatisticsDict(TypedDict): """Represent a route statistics data dict type.""" protocol_data_rate: int repeaters: list[Node] rssi: int | None repeater_rssi: list[int] route_failed_between: tuple[Node, Node] | None @dataclass class RouteStatistics: """Represent route statistics.""" client: Client = field(repr=False) data: RouteStatisticsDataType = field(repr=False) protocol_data_rate: ProtocolDataRate = field(init=False) def __post_init__(self) -> None: """Post initialize.""" self.protocol_data_rate = ProtocolDataRate(self.data["protocolDataRate"]) @cached_property def repeaters(self) -> list[Node]: """Return repeaters.""" assert self.client.driver return [ self.client.driver.controller.nodes[int(node_id)] for node_id in self.data["repeaters"] ] @property def rssi(self) -> int | None: """Return RSSI.""" if (rssi := self.data.get("rssi")) is None: return None if rssi in [item.value for item in RssiError]: raise RssiErrorReceived(RssiError(rssi)) return rssi @property def repeater_rssi(self) -> list[int]: """Return repeater RSSI.""" repeater_rssi = self.data.get("repeaterRSSI", []) rssi_errors = [item.value for item in RssiError] if any(rssi_ in rssi_errors for rssi_ in repeater_rssi): raise RepeaterRssiErrorReceived(repeater_rssi) return repeater_rssi @cached_property def route_failed_between(self) -> tuple[Node, Node] | None: """Return route failed between.""" if (node_ids := self.data.get("routeFailedBetween")) is None: return None assert self.client.driver assert len(node_ids) == 2 return ( self.client.driver.controller.nodes[int(node_ids[0])], self.client.driver.controller.nodes[int(node_ids[1])], ) def as_dict(self) -> RouteStatisticsDict: """Return route statistics as dict.""" return { "protocol_data_rate": self.protocol_data_rate.value, "repeaters": self.repeaters, "rssi": self.data.get("rssi"), "repeater_rssi": self.data.get("repeaterRSSI", []), "route_failed_between": ( ( self.route_failed_between[0], self.route_failed_between[1], ) if self.route_failed_between else None ), } zwave-js-server-python-0.63.0/zwave_js_server/model/utils.py000066400000000000000000000022051500374325600242250ustar00rootroot00000000000000"""Model for utils commands.""" from __future__ import annotations from ..client import Client from ..const import MINIMUM_QR_STRING_LENGTH from .controller import QRProvisioningInformation async def async_parse_qr_code_string( client: Client, qr_code_string: str ) -> QRProvisioningInformation: """Parse a QR code string into a QRProvisioningInformation object.""" if len(qr_code_string) < MINIMUM_QR_STRING_LENGTH or not qr_code_string.startswith( "90" ): raise ValueError( f"QR code string must be at least {MINIMUM_QR_STRING_LENGTH} characters " "long and start with `90`" ) data = await client.async_send_command( {"command": "utils.parse_qr_code_string", "qr": qr_code_string} ) return QRProvisioningInformation.from_dict(data["qrProvisioningInformation"]) async def async_try_parse_dsk_from_qr_code_string( client: Client, qr_code_string: str ) -> str | None: """Try to get DSK QR code.""" data = await client.async_send_command( {"command": "utils.try_parse_dsk_from_qr_code_string", "qr": qr_code_string} ) return data.get("dsk") zwave-js-server-python-0.63.0/zwave_js_server/model/value.py000066400000000000000000000317221500374325600242070ustar00rootroot00000000000000"""Provide a model for the Z-Wave JS value.""" from __future__ import annotations from dataclasses import dataclass, field from enum import IntEnum, StrEnum from typing import TYPE_CHECKING, Any, TypedDict from ..const import ( VALUE_UNKNOWN, CommandStatus, ConfigurationValueType, SetValueStatus, SupervisionStatus, ) from ..event import Event from ..util.helpers import parse_buffer from .duration import Duration, DurationDataType if TYPE_CHECKING: from .node import Node class ValueType(StrEnum): """Enum with all value types.""" ANY = "any" BOOLEAN = "boolean" NUMBER = "number" STRING = "string" class MetaDataType(TypedDict, total=False): """Represent a metadata data dict type.""" type: str # required readable: bool # required writeable: bool # required description: str label: str min: int | None max: int | None unit: str states: dict[str, str] ccSpecific: dict[str, Any] valueChangeOptions: list[str] allowManualEntry: bool stateful: bool secret: bool default: int # Configuration Value specific attributes valueSize: int format: int noBulkSupport: bool # deprecated isAdvanced: bool requiresReInclusion: bool isFromConfig: bool class ValueDataType(TypedDict, total=False): """Represent a value data dict type.""" commandClass: int # required commandClassName: str # required endpoint: int property: int | str # required propertyName: str # required propertyKey: int | str propertyKeyName: str value: Any newValue: Any prevValue: Any metadata: MetaDataType # required ccVersion: int # required def _get_value_id_str_from_dict(node: Node, val: ValueDataType) -> str: """Return string ID of value from ValueDataType dict.""" return get_value_id_str( node, val["commandClass"], val["property"], val.get("endpoint"), val.get("propertyKey"), ) def get_value_id_str( node: Node, command_class: int, property_: int | str, endpoint: int | None = None, property_key: int | str | None = None, ) -> str: """Return string ID of value.""" # If endpoint is not provided, assume root endpoint endpoint_ = endpoint or 0 value_id = f"{node.node_id}-{command_class}-{endpoint_}-{property_}" # Property key is only included when it has a value if property_key is not None: value_id += f"-{property_key}" return value_id class ValueMetadata: """Represent metadata on a value instance.""" def __init__(self, data: MetaDataType) -> None: """Initialize metadata.""" self.data = data @property def type(self) -> str: """Return type.""" return self.data["type"] @property def readable(self) -> bool | None: """Return readable.""" return self.data.get("readable") @property def writeable(self) -> bool | None: """Return writeable.""" return self.data.get("writeable") @property def label(self) -> str | None: """Return label.""" return self.data.get("label") @property def description(self) -> str | None: """Return description.""" return self.data.get("description") @property def min(self) -> int | None: """Return min.""" return self.data.get("min") @property def max(self) -> int | None: """Return max.""" return self.data.get("max") @property def unit(self) -> str | None: """Return unit.""" return self.data.get("unit") @property def states(self) -> dict: """Return (optional) states.""" return self.data.get("states", {}) @property def cc_specific(self) -> dict[str, Any]: """Return ccSpecific.""" return self.data.get("ccSpecific", {}) @property def value_change_options(self) -> list[str]: """Return valueChangeOptions.""" return self.data.get("valueChangeOptions", []) @property def allow_manual_entry(self) -> bool | None: """Return allowManualEntry.""" return self.data.get("allowManualEntry") @property def value_size(self) -> int | None: """Return valueSize.""" return self.data.get("valueSize") @property def stateful(self) -> bool | None: """Return stateful.""" return self.data.get("stateful") @property def secret(self) -> bool | None: """Return secret.""" return self.data.get("secret") @property def default(self) -> int | None: """Return default.""" return self.data.get("default") @property def format(self) -> ConfigurationValueFormat | None: """Return format.""" if (format_ := self.data.get("format")) is None: return None return ConfigurationValueFormat(format_) @property def no_bulk_support(self) -> bool | None: """Return noBulkSupport.""" return self.data.get("noBulkSupport") @property def is_advanced(self) -> bool | None: """Return isAdvanced.""" return self.data.get("isAdvanced") @property def requires_re_inclusion(self) -> bool | None: """Return requiresReInclusion.""" return self.data.get("requiresReInclusion") @property def is_from_config(self) -> bool | None: """Return isFromConfig.""" return self.data.get("isFromConfig") def update(self, data: MetaDataType) -> None: """Update data.""" self.data.update(data) class Value: """Represent a Z-Wave JS value.""" def __init__(self, node: Node, data: ValueDataType) -> None: """Initialize value.""" self.node = node self.data: ValueDataType = {} self._value: Any = None self._metadata = ValueMetadata({"type": "unknown"}) self.update(data) def __repr__(self) -> str: """Return the representation.""" return f"{type(self).__name__}(value_id={self.value_id!r})" def __hash__(self) -> int: """Return the hash.""" return hash((self.node, self.value_id)) def __eq__(self, other: object) -> bool: """Return whether this instance equals another.""" if not isinstance(other, Value): return False return self.node == other.node and self.value_id == other.value_id @property def value_id(self) -> str: """Return value ID.""" return _get_value_id_str_from_dict(self.node, self.data) @property def metadata(self) -> ValueMetadata: """Return value metadata.""" return self._metadata @property def value(self) -> Any | None: """Return value.""" # Treat unknown values like they are None if self._value == VALUE_UNKNOWN: return None return self._value @property def command_class_name(self) -> str: """Return commandClassName.""" return self.data["commandClassName"] @property def command_class(self) -> int: """Return commandClass.""" return self.data["commandClass"] @property def cc_version(self) -> int: """Return commandClass version.""" return self.data["ccVersion"] @property def endpoint(self) -> int | None: """Return endpoint.""" return self.data.get("endpoint") @property def property_(self) -> int | str: """Return property. Note the underscore in the end of this property name. That's there to not confuse Python to think it's a property decorator. """ return self.data["property"] @property def property_key(self) -> int | str | None: """Return propertyKey.""" return self.data.get("propertyKey") @property def property_name(self) -> str | None: """Return propertyName.""" return self.data.get("propertyName") @property def property_key_name(self) -> str | None: """Return propertyKeyName.""" return self.data.get("propertyKeyName") def receive_event(self, event: Event) -> None: """Receive an event.""" self.update(event.data["args"]) def update(self, data: ValueDataType) -> None: """Update data.""" self.data.update(data) self.data.pop("prevValue", None) if "newValue" in self.data: self.data["value"] = self.data.pop("newValue") if "metadata" in data: self._metadata.update(data["metadata"]) self._value = self.data.get("value") # Handle buffer dict and json string in value. if self._value is not None and self.metadata.type == "buffer": self._value = parse_buffer(self._value) class ValueNotification(Value): """ Model for a Value Notification message. https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotvalue-notificationquot """ # format is the same as a Value message, subclassed for easier identifying and # future use class ConfigurationValueFormat(IntEnum): """Enum of all known configuration value formats.""" # https://github.com/zwave-js/node-zwave-js/blob/cc_api_options/packages/core/src/values/Metadata.ts#L157 SIGNED_INTEGER = 0 UNSIGNED_INTEGER = 1 ENUMERATED = 2 BIT_FIELD = 3 class SupervisionResultDataType(TypedDict, total=False): """Represent a Supervision result data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/cc_api_options/packages/core/src/consts/Transmission.ts#L311 status: int remainingDuration: DurationDataType # not included unless status is 1 (working) @dataclass class SupervisionResult: """Represent a Supervision result type.""" data: SupervisionResultDataType = field(repr=False) status: SupervisionStatus = field(init=False) remaining_duration: Duration | None = field(init=False, default=None) def __post_init__(self) -> None: """Post initialization.""" self.status = SupervisionStatus(self.data["status"]) if remaining_duration := self.data.get("remainingDuration"): self.remaining_duration = Duration(remaining_duration) if self.status == SupervisionStatus.WORKING ^ bool( self.remaining_duration is not None ): raise ValueError( "SupervisionStatus of WORKING requires a remaining duration, all " "other statuses don't include it" ) class ConfigurationValue(Value): """Model for a Configuration Value.""" @property def configuration_value_type(self) -> ConfigurationValueType: """Return configuration value type.""" min_ = self.metadata.min max_ = self.metadata.max states = self.metadata.states allow_manual_entry = self.metadata.allow_manual_entry type_ = self.metadata.type if (max_ == 1 and min_ == 0 or type_ == ValueType.BOOLEAN) and not states: return ConfigurationValueType.BOOLEAN if ( allow_manual_entry and not max_ == min_ == 0 and not (max_ is None and min_ is None) ): return ConfigurationValueType.MANUAL_ENTRY if states: return ConfigurationValueType.ENUMERATED if (max_ is not None or min_ is not None) and not max_ == min_ == 0: return ConfigurationValueType.RANGE return ConfigurationValueType.UNDEFINED class SetValueResultDataType(TypedDict, total=False): """Represent a setValue result data dict type.""" # https://github.com/zwave-js/node-zwave-js/blob/v11-dev/packages/cc/src/lib/API.ts#L103 status: int # required remainingDuration: DurationDataType message: str @dataclass class SetValueResult: """Result from setValue command.""" data: SetValueResultDataType = field(repr=False) status: SetValueStatus = field(init=False) remaining_duration: Duration | None = field(init=False) message: str | None = field(init=False) def __post_init__(self) -> None: """Post init.""" self.status = SetValueStatus(self.data["status"]) self.remaining_duration = ( Duration(duration_data) if (duration_data := self.data.get("remainingDuration")) else None ) self.message = self.data.get("message") def __repr__(self) -> str: """Return the representation.""" status = self.status.name.replace("_", " ").title() if self.status == SetValueStatus.WORKING: assert self.remaining_duration return f"{status} ({self.remaining_duration})" if self.status in ( SetValueStatus.ENDPOINT_NOT_FOUND, SetValueStatus.INVALID_VALUE, SetValueStatus.NOT_IMPLEMENTED, ): assert self.message return f"{status}: {self.message}" return status @dataclass class SetConfigParameterResult: """Result of a set config parameter command.""" status: CommandStatus result: SupervisionResult | SetValueResult | None = None zwave-js-server-python-0.63.0/zwave_js_server/model/version.py000066400000000000000000000023701500374325600245550ustar00rootroot00000000000000"""Represents the version from the server.""" from __future__ import annotations from dataclasses import dataclass from typing import TypedDict class VersionInfoDataType(TypedDict): """Version info data dict type.""" driverVersion: str serverVersion: str homeId: int minSchemaVersion: int maxSchemaVersion: int @dataclass class VersionInfo: """Version info of the server.""" driver_version: str server_version: str home_id: int min_schema_version: int max_schema_version: int @classmethod def from_message(cls, msg: VersionInfoDataType) -> VersionInfo: """Create a version info from a version message.""" return cls( driver_version=msg["driverVersion"], server_version=msg["serverVersion"], home_id=msg["homeId"], # schema versions are sent in the response from schema version 1+ # this info not present means the server is at schema version 0 # at some point in time (when we stop supporting schema version 0), # we could adjust this code and assume the keys are there. min_schema_version=msg.get("minSchemaVersion", 0), max_schema_version=msg.get("maxSchemaVersion", 0), ) zwave-js-server-python-0.63.0/zwave_js_server/py.typed000066400000000000000000000000001500374325600231010ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/util/000077500000000000000000000000001500374325600223715ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/util/__init__.py000066400000000000000000000000521500374325600244770ustar00rootroot00000000000000"""Utility module for zwave-js-server.""" zwave-js-server-python-0.63.0/zwave_js_server/util/command_class/000077500000000000000000000000001500374325600251745ustar00rootroot00000000000000zwave-js-server-python-0.63.0/zwave_js_server/util/command_class/__init__.py000066400000000000000000000000731500374325600273050ustar00rootroot00000000000000"""Module for Command Class specific utility functions.""" zwave-js-server-python-0.63.0/zwave_js_server/util/command_class/energy_production.py000066400000000000000000000027211500374325600313070ustar00rootroot00000000000000"""Energy Production Command Class specific utility functions for values.""" from __future__ import annotations from ...const import CommandClass from ...const.command_class.energy_production import ( CC_SPECIFIC_PARAMETER, CC_SPECIFIC_SCALE, ENERGY_PRODUCTION_PARAMETER_TO_SCALE_ENUM_MAP, EnergyProductionParameter, EnergyProductionScaleType, ) from ...exceptions import InvalidCommandClass, UnknownValueData from ...model.value import Value def get_energy_production_parameter(value: Value) -> EnergyProductionParameter: """Get the EnergyProductionParameter for a given value.""" if value.command_class != CommandClass.ENERGY_PRODUCTION: raise InvalidCommandClass(value, CommandClass.ENERGY_PRODUCTION) try: return EnergyProductionParameter( value.metadata.cc_specific[CC_SPECIFIC_PARAMETER] ) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_PARAMETER}" ) from None def get_energy_production_scale_type(value: Value) -> EnergyProductionScaleType: """Get the ScaleType for a given value.""" parameter = get_energy_production_parameter(value) scale_enum = ENERGY_PRODUCTION_PARAMETER_TO_SCALE_ENUM_MAP[parameter] try: return scale_enum(value.metadata.cc_specific[CC_SPECIFIC_SCALE]) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_SCALE}" ) from None zwave-js-server-python-0.63.0/zwave_js_server/util/command_class/meter.py000066400000000000000000000023521500374325600266640ustar00rootroot00000000000000"""Meter Command Class specific utility functions for values.""" from __future__ import annotations from ...const import CommandClass from ...const.command_class.meter import ( CC_SPECIFIC_METER_TYPE, CC_SPECIFIC_SCALE, METER_TYPE_TO_SCALE_ENUM_MAP, MeterScaleType, MeterType, ) from ...exceptions import InvalidCommandClass, UnknownValueData from ...model.value import Value def get_meter_type(value: Value) -> MeterType: """Get the MeterType for a given value.""" if value.command_class != CommandClass.METER: raise InvalidCommandClass(value, CommandClass.METER) try: return MeterType(value.metadata.cc_specific[CC_SPECIFIC_METER_TYPE]) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_METER_TYPE}" ) from None def get_meter_scale_type(value: Value) -> MeterScaleType: """Get the ScaleType for a given value.""" meter_type = get_meter_type(value) scale_enum = METER_TYPE_TO_SCALE_ENUM_MAP[meter_type] try: return scale_enum(value.metadata.cc_specific[CC_SPECIFIC_SCALE]) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_SCALE}" ) from None zwave-js-server-python-0.63.0/zwave_js_server/util/command_class/multilevel_sensor.py000066400000000000000000000026231500374325600313240ustar00rootroot00000000000000"""Multilevel Sensor Command Class specific utility functions for values.""" from __future__ import annotations from ...const import CommandClass from ...const.command_class.multilevel_sensor import ( CC_SPECIFIC_SCALE, CC_SPECIFIC_SENSOR_TYPE, MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP, MultilevelSensorScaleType, MultilevelSensorType, ) from ...exceptions import InvalidCommandClass, UnknownValueData from ...model.value import Value def get_multilevel_sensor_type(value: Value) -> MultilevelSensorType: """Get the MultilevelSensorType for a given value.""" if value.command_class != CommandClass.SENSOR_MULTILEVEL: raise InvalidCommandClass(value, CommandClass.SENSOR_MULTILEVEL) try: return MultilevelSensorType(value.metadata.cc_specific[CC_SPECIFIC_SENSOR_TYPE]) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_SENSOR_TYPE}" ) from None def get_multilevel_sensor_scale_type(value: Value) -> MultilevelSensorScaleType: """Get the ScaleType for a given value.""" sensor_type = get_multilevel_sensor_type(value) scale_enum = MULTILEVEL_SENSOR_TYPE_TO_SCALE_MAP[sensor_type] try: return scale_enum(value.metadata.cc_specific[CC_SPECIFIC_SCALE]) except ValueError: raise UnknownValueData( value, f"metadata.cc_specific.{CC_SPECIFIC_SCALE}" ) from None zwave-js-server-python-0.63.0/zwave_js_server/util/helpers.py000066400000000000000000000031461500374325600244110ustar00rootroot00000000000000"""Generic Utility helper functions.""" from __future__ import annotations import base64 import json from typing import Any from ..exceptions import UnparseableValue def is_json_string(value: Any) -> bool: """Check if the provided string looks like json.""" # NOTE: we do not use json.loads here as it is not strict enough return isinstance(value, str) and value.startswith("{") and value.endswith("}") def convert_bytes_to_base64(data: bytes) -> str: """Convert bytes data to base64 for serialization.""" return base64.b64encode(data).decode("ascii") def convert_base64_to_bytes(data: str) -> bytes: """Convert base64 data to bytes for deserialization.""" return base64.b64decode(data) def parse_buffer(value: dict[str, Any] | str) -> str: """Parse value from a buffer data type.""" if isinstance(value, dict): return parse_buffer_from_dict(value) if is_json_string(value): return parse_buffer_from_json(value) return value def parse_buffer_from_dict(value: dict[str, Any]) -> str: """Parse value dictionary from a buffer data type.""" if value.get("type") != "Buffer" or "data" not in value: raise UnparseableValue(f"Unparseable value: {value}") from ValueError( "JSON does not match expected schema" ) return "".join([chr(x) for x in value["data"]]) def parse_buffer_from_json(value: str) -> str: """Parse value string from a buffer data type.""" try: return parse_buffer_from_dict(json.loads(value)) except ValueError as err: raise UnparseableValue(f"Unparseable value: {value}") from err zwave-js-server-python-0.63.0/zwave_js_server/util/lock.py000066400000000000000000000163761500374325600237100ustar00rootroot00000000000000"""Utility functions for Z-Wave JS locks.""" from __future__ import annotations from typing import TypedDict, cast from ..const import CommandClass from ..const.command_class.lock import ( ATTR_CODE_SLOT, ATTR_IN_USE, ATTR_NAME, ATTR_USERCODE, CURRENT_AUTO_RELOCK_TIME_PROPERTY, CURRENT_BLOCK_TO_BLOCK_PROPERTY, CURRENT_HOLD_AND_RELEASE_TIME_PROPERTY, CURRENT_TWIST_ASSIST_PROPERTY, LOCK_USERCODE_ID_PROPERTY, LOCK_USERCODE_PROPERTY, LOCK_USERCODE_STATUS_PROPERTY, CodeSlotStatus, DoorLockCCConfigurationSetOptions, OperationType, ) from ..exceptions import NotFoundError from ..model.endpoint import Endpoint from ..model.node import Node from ..model.value import SetValueResult, SupervisionResult, Value, get_value_id_str def get_code_slot_value(node: Node, code_slot: int, property_name: str) -> Value: """Get a code slot value.""" value = node.values.get( get_value_id_str( node, CommandClass.USER_CODE, property_name, endpoint=0, property_key=code_slot, ) ) if not value: raise NotFoundError(f"{property_name} for code slot {code_slot} not found") return value class CodeSlot(TypedDict, total=False): """Represent a code slot.""" code_slot: int # required name: str # required in_use: bool | None # required usercode: str | None def _get_code_slots(node: Node, include_usercode: bool = False) -> list[CodeSlot]: """Get all code slots on the lock and optionally include usercode.""" code_slot = 1 slots: list[CodeSlot] = [] # Loop until we can't find a code slot while True: try: value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY) status_value = get_code_slot_value( node, code_slot, LOCK_USERCODE_STATUS_PROPERTY ) except NotFoundError: return slots code_slot = int(value.property_key) # type: ignore[arg-type] in_use = ( None if status_value.value is None else status_value.value == CodeSlotStatus.ENABLED ) # we know that code slots will always have a property key # that is an int, so we can ignore mypy slot = { ATTR_CODE_SLOT: code_slot, ATTR_NAME: value.metadata.label, ATTR_IN_USE: in_use, } if include_usercode: slot[ATTR_USERCODE] = value.value slots.append(cast(CodeSlot, slot)) code_slot += 1 def get_code_slots(node: Node) -> list[CodeSlot]: """Get all code slots on the lock and whether or not they are used.""" return _get_code_slots(node, False) def get_usercodes(node: Node) -> list[CodeSlot]: """Get all code slots and usercodes on the lock.""" return _get_code_slots(node, True) def get_usercode(node: Node, code_slot: int) -> CodeSlot: """Get usercode from slot X on the lock.""" value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY) status_value = get_code_slot_value(node, code_slot, LOCK_USERCODE_STATUS_PROPERTY) code_slot = int(value.property_key) # type: ignore[arg-type] in_use = ( None if status_value.value is None else status_value.value == CodeSlotStatus.ENABLED ) return cast( CodeSlot, { ATTR_CODE_SLOT: code_slot, ATTR_NAME: value.metadata.label, ATTR_IN_USE: in_use, ATTR_USERCODE: value.value, }, ) async def get_usercode_from_node(node: Node, code_slot: int) -> CodeSlot: """ Fetch a usercode directly from a node. Should be used when Z-Wave JS's ValueDB hasn't been populated for this code slot. This call will populate the ValueDB and trigger value update events from the driver. """ # https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=get await node.async_invoke_cc_api( CommandClass.USER_CODE, "get", code_slot, wait_for_result=True ) return get_usercode(node, code_slot) async def set_usercode( node: Node, code_slot: int, usercode: str ) -> SetValueResult | None: """Set the usercode to index X on the lock.""" value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY) return await node.async_set_value(value, usercode) async def set_usercodes(node: Node, codes: dict[int, str]) -> SupervisionResult | None: """Set the usercode to index X on the lock.""" cc_api_codes = [ { LOCK_USERCODE_ID_PROPERTY: code_slot, LOCK_USERCODE_STATUS_PROPERTY: CodeSlotStatus.ENABLED, LOCK_USERCODE_PROPERTY: usercode, } for code_slot, usercode in codes.items() ] # https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=setmany data = await node.async_invoke_cc_api( CommandClass.USER_CODE, "setMany", cc_api_codes, wait_for_result=True ) if not data: raise ValueError("Received unexpected response from User Code CC setMany API") return SupervisionResult(data) async def clear_usercode(node: Node, code_slot: int) -> SetValueResult | None: """Clear a code slot on the lock.""" value = get_code_slot_value(node, code_slot, LOCK_USERCODE_STATUS_PROPERTY) return await node.async_set_value(value, CodeSlotStatus.AVAILABLE) async def set_configuration( endpoint: Endpoint, configuration: DoorLockCCConfigurationSetOptions ) -> SupervisionResult | None: """Set lock configuration.""" # It is invalid to set the operation to timed with no timeout, or to constant # with a timeout if (configuration.operation_type == OperationType.CONSTANT) ^ ( configuration.lock_timeout_configuration is None ): raise ValueError( "Invalid operation type and lock timeout configuration combination" ) errors: list[str] = [] for property_name, attr_name in ( (CURRENT_AUTO_RELOCK_TIME_PROPERTY, "auto_relock_time"), (CURRENT_HOLD_AND_RELEASE_TIME_PROPERTY, "hold_and_release_time"), (CURRENT_TWIST_ASSIST_PROPERTY, "twist_assist"), (CURRENT_BLOCK_TO_BLOCK_PROPERTY, "block_to_block"), ): # It a value for a particular configuration value is not provided and it exists # on the node, use the cached value cached_value = next( ( value for value in endpoint.values.values() if value.command_class == CommandClass.DOOR_LOCK and value.property_name == property_name ), None, ) if ( val := getattr(configuration, attr_name) ) is not None and cached_value is None: errors.append( f"- Can't provide value for {property_name} since it is unsupported" ) elif cached_value is not None and val is None and not errors: setattr(configuration, attr_name, cached_value.value) if errors: raise ValueError("\n".join(errors)) # https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=setconfiguration data = await endpoint.async_invoke_cc_api( CommandClass.DOOR_LOCK, "setConfiguration", configuration.to_dict() ) if not data: return None return SupervisionResult(data) zwave-js-server-python-0.63.0/zwave_js_server/util/multicast.py000066400000000000000000000070371500374325600247570ustar00rootroot00000000000000"""Support for multicast commands.""" from __future__ import annotations from typing import Any, cast from ..client import Client from ..const import CommandClass from ..model.node import Node, _get_value_id_dict_from_value_data from ..model.value import SetValueResult, ValueDataType async def _async_send_command( client: Client, command: str, nodes: list[Node] | None = None, require_schema: int | None = None, **kwargs: Any, ) -> dict: """Send a multicast command.""" if nodes: cmd = { "command": f"multicast_group.{command}", "nodeIDs": [node.node_id for node in nodes], **kwargs, } else: cmd = {"command": f"broadcast_node.{command}", **kwargs} return await client.async_send_command(cmd, require_schema) async def async_multicast_set_value( client: Client, new_value: Any, value_data: ValueDataType, nodes: list[Node] | None = None, options: dict | None = None, ) -> SetValueResult: """Send a multicast set_value command.""" result = await _async_send_command( client, "set_value", nodes, valueId=_get_value_id_dict_from_value_data(value_data), value=new_value, options=options, require_schema=29, ) return SetValueResult(result["result"]) async def async_multicast_get_endpoint_count( client: Client, nodes: list[Node] | None = None ) -> int: """Send a multicast get_endpoint_count command.""" result = await _async_send_command( client, "get_endpoint_count", nodes, require_schema=5 ) return cast(int, result["count"]) async def async_multicast_endpoint_supports_cc( client: Client, endpoint: int, command_class: CommandClass, nodes: list[Node] | None = None, ) -> bool: """Send a supports_cc command to a multicast endpoint.""" result = await _async_send_command( client, "supports_cc", nodes, index=endpoint, commandClass=command_class, require_schema=5, ) return cast(bool, result["supported"]) async def async_multicast_endpoint_get_cc_version( client: Client, endpoint: int, command_class: CommandClass, nodes: list[Node] | None = None, ) -> int: """Send a get_cc_version command to a multicast endpoint.""" result = await _async_send_command( client, "get_cc_version", nodes, index=endpoint, commandClass=command_class, require_schema=5, ) return cast(int, result["version"]) async def async_multicast_endpoint_invoke_cc_api( client: Client, endpoint: int, command_class: CommandClass, method_name: str, args: list[Any] | None = None, nodes: list[Node] | None = None, ) -> Any: """Send a invoke_cc_api command to a multicast endpoint.""" result = await _async_send_command( client, "invoke_cc_api", nodes, index=endpoint, commandClass=command_class, methodName=method_name, args=args, require_schema=5, ) return result["response"] async def async_multicast_endpoint_supports_cc_api( client: Client, endpoint: int, command_class: CommandClass, nodes: list[Node] | None = None, ) -> bool: """Send a supports_cc_api command to a multicast endpoint.""" result = await _async_send_command( client, "supports_cc_api", nodes, index=endpoint, commandClass=command_class, require_schema=5, ) return cast(bool, result["supported"]) zwave-js-server-python-0.63.0/zwave_js_server/util/node.py000066400000000000000000000270061500374325600236750ustar00rootroot00000000000000"""Utility functions for Z-Wave JS nodes.""" from __future__ import annotations import logging from typing import cast from ..const import CommandClass, CommandStatus, ConfigurationValueType, SetValueStatus from ..exceptions import ( BulkSetConfigParameterFailed, InvalidNewValue, NotFoundError, SetValueFailed, ValueTypeError, ) from ..model.node import Node from ..model.value import ( ConfigurationValue, SetConfigParameterResult, SetValueResult, get_value_id_str, ) _LOGGER = logging.getLogger(__name__) def dump_node_state(node: Node) -> dict: """Get state from a node.""" return { **node.data, "values": {value_id: value.data for value_id, value in node.values.items()}, "endpoints": {idx: endpoint.data for idx, endpoint in node.endpoints.items()}, } def partial_param_bit_shift(property_key: int) -> int: """Get the number of bits to shift the value for a given property key.""" # We can get the binary representation of the property key, reverse it, # and find the first 1 return bin(property_key)[::-1].index("1") async def async_set_config_parameter( node: Node, new_value: int | str, property_or_property_name: int | str, property_key: int | str | None = None, endpoint: int = 0, ) -> tuple[ConfigurationValue, SetConfigParameterResult]: """Set a value for a config parameter on this node. new_value and property_ can be provided as labels, so we need to resolve them to the appropriate key """ config_values = node.get_configuration_values() # If a property name is provided, we have to search for the correct value since # we can't use value ID if isinstance(property_or_property_name, str): try: zwave_value = next( config_value for config_value in config_values.values() if config_value.property_name == property_or_property_name and config_value.endpoint == endpoint ) except StopIteration: raise NotFoundError( "Configuration parameter with parameter name " f"{property_or_property_name} on node {node} endpoint {endpoint} " "could not be found" ) from None else: value_id = get_value_id_str( node, CommandClass.CONFIGURATION, property_or_property_name, endpoint=endpoint, property_key=property_key, ) if value_id not in config_values: raise NotFoundError( f"Configuration parameter with value ID {value_id} could not be " "found" ) from None zwave_value = config_values[value_id] new_value = _validate_and_transform_new_value(zwave_value, new_value) # Finally attempt to set the value and return the Value object if successful result = await node.async_set_value(zwave_value, new_value) if result and result.status not in ( SetValueStatus.WORKING, SetValueStatus.SUCCESS, SetValueStatus.SUCCESS_UNSUPERVISED, ): raise SetValueFailed(str(result)) status = ( SetConfigParameterResult(CommandStatus.ACCEPTED, result) if result is not None else SetConfigParameterResult(CommandStatus.QUEUED) ) return zwave_value, status async def async_bulk_set_partial_config_parameters( node: Node, property_: int, new_value: int | dict[int | str, int | str], endpoint: int = 0, ) -> SetConfigParameterResult: """Bulk set partial configuration values on this node.""" config_values = node.get_configuration_values() partial_param_values = { value_id: value for value_id, value in config_values.items() if value.property_ == property_ and value.endpoint == endpoint and value.property_key is not None } if not partial_param_values: # If we find a value with this property_, we know this value isn't split # into partial params if ( get_value_id_str( node, CommandClass.CONFIGURATION, property_, endpoint=endpoint ) in config_values ): # If the new value is provided as a dict, we don't have enough information # to set the parameter. if isinstance(new_value, dict): raise ValueTypeError( f"Configuration parameter {property_} for node {node.node_id} " f"endpoint {endpoint} does not have partials" ) # If the new value is provided as an int, we may as well try to set it # using the standard utility function _LOGGER.info( "Falling back to async_set_config_parameter because no partials " "were found" ) _, cmd_status = await async_set_config_parameter( node, new_value, property_, endpoint=endpoint ) return cmd_status # Otherwise if we can't find any values with this property, this config # parameter does not exist raise NotFoundError( f"Configuration parameter {property_} for node {node.node_id} endpoint " f"{endpoint} not found" ) # If new_value is a dictionary, we need to calculate the full value to send if isinstance(new_value, dict): new_value = _get_int_from_partials_dict( node, partial_param_values, property_, new_value, endpoint=endpoint ) else: _validate_raw_int(partial_param_values, new_value) cmd_response = await node.async_send_command( "set_value", valueId={ "commandClass": CommandClass.CONFIGURATION.value, "endpoint": endpoint, "property": property_, }, value=new_value, require_schema=29, ) # If we didn't wait for a response, we assume the command has been queued if cmd_response is None: return SetConfigParameterResult(CommandStatus.QUEUED) result = SetValueResult(cmd_response["result"]) if result.status not in ( SetValueStatus.WORKING, SetValueStatus.SUCCESS, SetValueStatus.SUCCESS_UNSUPERVISED, ): raise SetValueFailed(str(result)) return SetConfigParameterResult(CommandStatus.ACCEPTED, result) def _validate_and_transform_new_value( zwave_value: ConfigurationValue, new_value: int | str ) -> int: """Validate a new value and return the integer value to set.""" # If needed, convert a state label to its key. We know the state exists because # of the validation above. if isinstance(new_value, str): try: new_value = int( next( key for key, label in zwave_value.metadata.states.items() if label == new_value ) ) except StopIteration: raise InvalidNewValue( f"State '{new_value}' not found for parameter {zwave_value.value_id}" ) from None if zwave_value.configuration_value_type == ConfigurationValueType.UNDEFINED: # We need to use the Configuration CC API to set the value for this type raise NotImplementedError("Configuration values of undefined type can't be set") return new_value def _bulk_set_validate_and_transform_new_value( zwave_value: ConfigurationValue, property_key: int, new_partial_value: int | str ) -> int: """ Validate and transform new value for a bulk set function call. Returns a bulk set friendly error if validation fails. """ try: return _validate_and_transform_new_value(zwave_value, new_partial_value) except (InvalidNewValue, NotImplementedError) as err: raise BulkSetConfigParameterFailed( f"Config parameter {zwave_value.value_id} failed validation on partial " f"parameter {property_key}" ) from err def _get_int_from_partials_dict( node: Node, partial_param_values: dict[str, ConfigurationValue], property_: int, new_value: dict[int | str, int | str], endpoint: int = 0, ) -> int: """Take an input dict for a set of partial values and compute the raw int value.""" int_value = 0 provided_partial_values = [] # For each property key provided, we bit shift the partial value using the # property_key for property_key_or_name, partial_value in new_value.items(): # If the dict key is a property key, we can generate the value ID to find the # partial value if isinstance(property_key_or_name, int): value_id = get_value_id_str( node, CommandClass.CONFIGURATION, property_, property_key=property_key_or_name, endpoint=endpoint, ) if value_id not in partial_param_values: raise NotFoundError( f"Bitmask {property_key_or_name} ({hex(property_key_or_name)}) " f"not found for parameter {property_} on node {node} endpoint " f"{endpoint}" ) zwave_value = partial_param_values[value_id] # If the dict key is a property name, we have to find the value from the list # of partial param values else: try: zwave_value = next( value for value in partial_param_values.values() if value.property_name == property_key_or_name and value.endpoint == endpoint ) except StopIteration: raise NotFoundError( f"Partial parameter with label '{property_key_or_name}'" f"not found for parameter {property_} on node {node} endpoint " f"{endpoint}" ) from None provided_partial_values.append(zwave_value) property_key = cast(int, zwave_value.property_key) partial_value = _bulk_set_validate_and_transform_new_value( zwave_value, property_key, partial_value ) int_value += partial_value << partial_param_bit_shift(property_key) # To set partial parameters in bulk, we also have to include cached values for # property keys that haven't been specified missing_values = set(partial_param_values.values()) - set(provided_partial_values) int_value += sum( cast(int, property_value.value) << partial_param_bit_shift(cast(int, property_value.property_key)) for property_value in missing_values ) return int_value def _validate_raw_int( partial_param_values: dict[str, ConfigurationValue], new_value: int ) -> None: """ Validate raw value against all partial values. Raises if a partial value in the raw value is invalid. """ # Break down the bulk value into partial values and validate them against # each partial parameter's metadata by looping through the property values # starting with the highest property key for zwave_value in sorted( partial_param_values.values(), key=lambda val: cast(int, val.property_key), reverse=True, ): property_key = cast(int, zwave_value.property_key) multiplication_factor = 2 ** partial_param_bit_shift(property_key) partial_value = int(new_value / multiplication_factor) new_value = new_value % multiplication_factor _bulk_set_validate_and_transform_new_value( zwave_value, property_key, partial_value ) zwave-js-server-python-0.63.0/zwave_js_server/version.py000066400000000000000000000006211500374325600234520ustar00rootroot00000000000000"""Version helper.""" from __future__ import annotations import aiohttp from .model.version import VersionInfo async def get_server_version(url: str, session: aiohttp.ClientSession) -> VersionInfo: """Return a server version.""" client = await session.ws_connect(url) try: return VersionInfo.from_message(await client.receive_json()) finally: await client.close()