pax_global_header00006660000000000000000000000064147576647650014545gustar00rootroot0000000000000052 comment=49f565bd5565655ad3495e6f6da4dd6f9e1e5a38 python-plugwise-1.7.3/000077500000000000000000000000001475766476500147335ustar00rootroot00000000000000python-plugwise-1.7.3/.github/000077500000000000000000000000001475766476500162735ustar00rootroot00000000000000python-plugwise-1.7.3/.github/ISSUE_TEMPLATE/000077500000000000000000000000001475766476500204565ustar00rootroot00000000000000python-plugwise-1.7.3/.github/ISSUE_TEMPLATE/bug.yml000066400000000000000000000123541475766476500217630ustar00rootroot00000000000000name: Bug or problem. description: Report an issue with the Plugwise module. title: "[BUG]: " labels: ["bug"] body: - type: markdown attributes: value: | This issue form is for reporting bugs only! If you have a feature or enhancement request, please use the appropriate [issue template][it]. [it]: https://github.com/plugwise/python-plugwise/issues/new/choose - type: textarea validations: required: true attributes: label: Describe the bug. description: >- Tell us what you were trying to do and what happened. Provide a clear and concise description of what the problem is. - type: textarea validations: required: true attributes: label: Expected behavior description: >- A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. - type: markdown attributes: value: | ## Environment - type: input id: version validations: required: true attributes: label: What version of Home Assistant Core has the issue? placeholder: core- description: > Can be found in: [Configuration panel -> Info](https://my.home-assistant.io/redirect/info/). **If not using Home Assistant, provide information on what you integrated with.** [![Open your Home Assistant instance and show your Home Assistant version information.](https://my.home-assistant.io/badges/info.svg)](https://my.home-assistant.io/redirect/info/) - type: dropdown validations: required: true attributes: label: What type of installation are you running? description: > Can be found in: [Configuration panel -> Info](https://my.home-assistant.io/redirect/info/). When selecting `Core`: remember to specify your way of running in the `additional information` textarea at the bottom, including your python version! [![Open your Home Assistant instance and show your Home Assistant version information.](https://my.home-assistant.io/badges/info.svg)](https://my.home-assistant.io/redirect/info/) options: - Home Assistant OS - Home Assistant Container - Home Assistant Supervised - Home Assistant Core - Other tool (described above) - type: dropdown validations: required: true attributes: label: How and which version of the integration do you have installed? description: > If you are using just Home Assistant and did not add anything special, choose `Home Assistant Core`. options: - Home Assistant Core - HACS - Manually installed `custom_component` - Cloned from GitHub - I'm not using Home Assistant - type: markdown attributes: value: | # Plugwise Information - type: dropdown validations: required: true attributes: label: What kind of Plugwise device is having issues? description: > Select the best possible option (i.e. for issues with a Lisa or Tom, select Adam, etc) options: - "Smile: Adam (including Lisa, Tom, Floor)" - "Smile: Anna" - "Smile: P1" - "Smile: Stretch" - "Other product (we might not (yet) know of it's existence!)" - type: input validations: required: true attributes: label: What firmware version is your Plugwise product at? placeholder: "x.y.z" description: > If not using Home Assistant or unsure, please check the Plugwise mobile app. Check within Home Assistant by following the below link to your integrations page. You can find your firmware version on the device page. [![Open your Home Assistant instance and show the integration page.](https://my.home-assistant.io/badges/integrations.svg)](https://my.home-assistant.io/redirect/integrations/) - type: markdown attributes: value: | # Details - type: textarea attributes: label: Home Assistant Logging (optional) description: >- Very important to understand the problem, enable logging for `plugwise` in `configuration.yaml` by adding: ``` logger: default: warn logs: custom_components.plugwise: debug plugwise.smile: debug ``` After adding this, restart HA Core. After the restart has finished please look in the supervisor **Core** logs (follow the below link and select 'Core' from the dropdown). [![Open your Home Assistant instance and show the supervisor logs.](https://my.home-assistant.io/badges/supervisor_logs.svg)](https://my.home-assistant.io/redirect/supervisor_logs/) There should be several lines related to `plugwise-beta`. Please show us the **complete** log-message that starts this: ```[custom_components.plugwise] Data: PlugwiseData(gateway={'smile_name': ...``` - type: textarea attributes: label: Diagnostics information description: >- Provide your version of python used and/or include any and all informational, error and debug messages. - type: textarea attributes: label: Additional information description: > If you have any additional information for us, use the field below. python-plugwise-1.7.3/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000012561475766476500224520ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: Home Assistant Core integration url: https://www.home-assistant.io/integrations/plugwise/ about: For more details on the Core integration this module works best with. - name: Custom component (beta-testing) for Home Assistant url: https://github.com/plugwise/plugwise-beta/ about: For more information on the component. - name: Plugwise Support url: https://www.plugwise.com/support/ about: For product support from Plugwise. - name: Home Assistant Community forum url: https://community.home-assistant.io/t/plugwise-core-and-custom-component/236250 about: Please ask and answer questions here. python-plugwise-1.7.3/.github/ISSUE_TEMPLATE/feature_request.yml000066400000000000000000000111741475766476500244100ustar00rootroot00000000000000name: Feature request description: Suggest an idea for this project. title: "[FEATURE]: " labels: ["enhancement"] body: - type: markdown attributes: value: | This issue form is for requesting features. Please note that we are not affiliated to Plugwise nor Nabu Casa and just humble developers supporting Plugwise hardware to work via this module with Home Assistant. While the module is not exclusive to Home Assistant, it's written with Home Assistant in mind, nevertheless it was written in e generic way and provides proper functionality to any python based integration. If you have a problem, please use the appropriate [issue template][it]. [it]: https://github.com/plugwise/python-plugwise/issues/new/choose - type: textarea validations: required: true attributes: label: Describe the solution you are looking for description: >- A clear and concise description of any alternative solutions or features you've considered. - type: textarea validations: required: false attributes: label: Is your feature request related to a problem? (optional) description: >- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - type: textarea validations: required: true attributes: label: Describe alternatives you've considered description: >- A clear and concise description of any alternative solutions or features you've considered. - type: markdown attributes: value: | # Your setup - type: dropdown validations: required: true attributes: label: What type of installation are you running? description: > Can be found in: [Configuration panel -> Info](https://my.home-assistant.io/redirect/info/). **If not using Home Assistant, provide information on what you integrated with.** When selecting `Core`: remember to specify your way of running in the `additional information` textarea at the bottom, including your python version! [![Open your Home Assistant instance and show your Home Assistant version information.](https://my.home-assistant.io/badges/info.svg)](https://my.home-assistant.io/redirect/info/) options: - Home Assistant OS - Home Assistant Container - Home Assistant Supervised - Home Assistant Core - Other tool(ing) (i.e. not Home Assistant) - type: dropdown validations: required: true attributes: label: How did you install python-plugwise (or `plugwise`) for short description: > If you are a Home Assistant user and are not aware of anything special, choose `Home Assistant Core`. options: - Other use (installed using `pip`) - Other use (cloned from Github) - Home Assistant Core - HA using HACS - HA using Manually installed `custom_component` - Cloned from GitHub - type: markdown attributes: value: | # Plugwise Information - type: dropdown validations: required: true attributes: label: What kind of Plugwise device is having issues? description: > Select the best possible option (i.e. for issues with a Lisa or Tom, select Adam, etc.) options: - "Smile: Adam (including Lisa, Tom, Floor)" - "Smile: Anna" - "Smile: P1" - "Smile: Stretch" - "Other product (we might not (yet) know of it's existence!)" - type: input validations: required: true attributes: label: What firmware version is your Plugwise product at? placeholder: core- description: > If not using Home Assistant or unsure, please check the Plugwise mobile app. Check within Home Assistant by following the below link to your integrations page. You can find your firmware version on the device page. Otherwise check the Plugwise mobile app. [![Open your Home Assistant instance and show the integration page.](https://my.home-assistant.io/badges/integrations.svg)](https://my.home-assistant.io/redirect/integrations/) - type: textarea validations: required: true attributes: label: Your setup description: > What additional components do you have such as Anna, Lisa, Koen, Floor, Tom, etc. - what kind of auxiliary devices as boilers/heaters/heat-exchangers - type: markdown attributes: value: | # Additional information - type: textarea attributes: label: Additional context description: > Add any other context or screenshots about the feature request here. python-plugwise-1.7.3/.github/ISSUE_TEMPLATE/todo_item.yml000066400000000000000000000003771475766476500231730ustar00rootroot00000000000000name: Todo Item description: Create a todo to help keep track. title: "[TODO]: " body: - type: textarea validations: required: true attributes: label: Todo description: >- A clear and concise description of what to do. python-plugwise-1.7.3/.github/dependabot.yml000066400000000000000000000012501475766476500211210ustar00rootroot00000000000000# 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" # See documentation for possible values # directory: "/" # Location of package manifests # schedule: # interval: "daily" # - package-ecosystem: "pip" # See documentation for possible values # directory: "/" # Location of package manifests # schedule: # interval: "daily" python-plugwise-1.7.3/.github/release.yml000066400000000000000000000013221475766476500204340ustar00rootroot00000000000000# Release drafter changelog: categories: - title: Breaking Changes 🛠 labels: - Semver-Major - breaking-change - title: Exciting New Features 🎉 labels: - Semver-Minor - "feature" - "enhancement" - "quality" - "smile" - title: Bug Fixes 🐛 labels: - "fix" - "bugfix" - "bug" - title: Maintenance 🧰 labels: - "chore" - "dashboard" - "auto-merge" - "dependencies" - "python" - "documentation" - "github-actions" - "userdata" - "pre-commit" - "manual-merge" - title: Other Changes labels: - "*" python-plugwise-1.7.3/.github/renovate.json000066400000000000000000000002051475766476500210060ustar00rootroot00000000000000{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["github>plugwise/renovate-config:python-module"] } python-plugwise-1.7.3/.github/workflows/000077500000000000000000000000001475766476500203305ustar00rootroot00000000000000python-plugwise-1.7.3/.github/workflows/codeql-analysis.yml000066400000000000000000000045701475766476500241510ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # ******** NOTE ******** name: "CodeQL" on: # push: # branches: [ main ] # pull_request: # # The branches below must be a subset of the branches above # branches: [ main ] schedule: - cron: "24 14 * * 5" jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: ["python"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 python-plugwise-1.7.3/.github/workflows/merge.yml000066400000000000000000000023531475766476500221550ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Latest release env: CACHE_VERSION: 10 DEFAULT_PYTHON: "3.13" # Only run on merges on: pull_request: types: closed branches: - main jobs: publishing: name: Build and publish Python 🐍 distributions đŸ“Ļ to PyPI runs-on: ubuntu-latest # Only trigger on merges, not just closes if: github.event.pull_request.merged == true steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Install pypa/build run: >- python3 -m pip install build --user - name: Build a binary wheel and a source tarball run: python3 -m build - name: Publish distribution đŸ“Ļ to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.pypi_token }} skip-existing: true python-plugwise-1.7.3/.github/workflows/verify.yml000066400000000000000000000367071475766476500223740ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Latest commit env: CACHE_VERSION: 12 DEFAULT_PYTHON: "3.13.0" PRE_COMMIT_HOME: ~/.cache/pre-commit on: schedule: - cron: "2 4 * * 0" # weekly workflow_dispatch: push: # pull_request: jobs: # Prepare default python version environment prepare: runs-on: ubuntu-latest name: Prepare steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} restore-keys: | ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }}- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }} ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}- - name: Create Python virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | pip install virtualenv --upgrade python -m venv venv . venv/bin/activate pip install uv uv pip install -U pip setuptools wheel uv pip install -r requirements_test.txt -r requirements_commit.txt - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v4 with: path: ${{ env.PRE_COMMIT_HOME }} key: | ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} restore-keys: | ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit- - name: Install pre-commit dependencies if: steps.cache-precommit.outputs.cache-hit != 'true' run: | . venv/bin/activate pre-commit install-hooks ruff: runs-on: ubuntu-latest name: Ruff check and force needs: prepare steps: - name: Check out committed code uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python ${{ env.DEFAULT_PYTHON }} virtual environment from cache" exit 1 - name: Ruff (with fix) run: | . venv/bin/activate ruff check plugwise/ tests/ - name: If needed, commit ruff changes to the pull request if: failure() run: | . venv/bin/activate ruff format plugwise/ tests/ git config --global user.name 'autoruff' git config --global user.email 'plugwise@users.noreply.github.com' git remote set-url origin https://x-access-token:${{ secrets.PAT_CT }}@github.com/$GITHUB_REPOSITORY git checkout $GITHUB_HEAD_REF git commit -am "fixup: ${GITHUB_REF##*/} Python code fixed using ruff" git push origin ${GITHUB_REF##*/} commitcheck: runs-on: ubuntu-latest name: Check commit needs: - ruff - shellcheck - dependencies_check steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python ${{ env.DEFAULT_PYTHON }} virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v4 with: path: ${{ env.PRE_COMMIT_HOME }} key: | ${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - name: Fail job if cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Verify commit run: | . venv/bin/activate pre-commit run --show-diff-on-failure --color=always --all-files --hook-stage manual pylint - name: Biome lint run: | . venv/bin/activate mkdir -p ./tmp && curl -sL "https://github.com/biomejs/biome/releases/latest/download/biome-linux-x64" -o ./tmp/biome && chmod +x ./tmp/biome pre-commit run --show-diff-on-failure --color=always --all-files --hook-stage manual biome - name: Lint markdown files run: | . venv/bin/activate pre-commit run --show-diff-on-failure --color=always --all-files --hook-stage manual markdownlint prepare-test-cache: runs-on: ubuntu-latest name: Create pytest cache for Python ${{ matrix.python-version }} needs: commitcheck strategy: matrix: python-version: ["3.13.0", "3.12"] steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} id: python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} restore-keys: | ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }} ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}- - name: Create full Python ${{ matrix.python-version }} virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | python -m venv venv . venv/bin/activate pip install uv uv pip install -U pip setuptools wheel #pip install -r requirements_test.txt # 20220124 Mimic setup_test.sh uv pip install --upgrade -r requirements_test.txt -c https://raw.githubusercontent.com/home-assistant/core/dev/homeassistant/package_constraints.txt -r https://raw.githubusercontent.com/home-assistant/core/dev/requirements_test.txt -r https://raw.githubusercontent.com/home-assistant/core/dev/requirements_test_pre_commit.txt uv pip install --upgrade pytest-asyncio pytest: runs-on: ubuntu-latest name: Run pytest using Python ${{ matrix.python-version }} needs: prepare-test-cache strategy: matrix: python-version: ["3.13.0", "3.12"] steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} id: python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{ matrix.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Run all tests run: | . venv/bin/activate pytest --log-level info tests/*.py --cov='.' - name: Upload coverage artifact uses: actions/upload-artifact@v4 with: name: coverage-${{ matrix.python-version }} path: .coverage if-no-files-found: error include-hidden-files: true mypy: runs-on: ubuntu-latest name: Run mypy needs: pytest steps: - name: Check out committed code uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python ${{ env.DEFAULT_PYTHON }} virtual environment from cache" exit 1 - name: Run mypy run: | . venv/bin/activate pip list | grep -i mypy mypy plugwise/ # Check shellscripts shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - name: Check out committed code uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master # Check for missing python dependencies dependencies_check: runs-on: ubuntu-latest name: Dependency steps: - name: Check out committed code uses: actions/checkout@v4 - name: Run dependency checker run: scripts/dependencies_check.sh debug coverage: name: Process test coverage runs-on: ubuntu-latest needs: pytest steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Download all coverage artifacts uses: actions/download-artifact@v4 - name: Combine coverage results run: | . venv/bin/activate coverage combine coverage*/.coverage* coverage report --fail-under=94 coverage xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} test-publishing: name: Build and publish Python 🐍 distributions đŸ“Ļ to TestPyPI runs-on: ubuntu-latest needs: [coverage, mypy] steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Install pypa/build run: >- python3 -m pip install build --user - name: Build a binary wheel and a source tarball run: python3 -m build - name: Publish distribution đŸ“Ļ to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 continue-on-error: true with: password: ${{ secrets.testpypi_token }} repository-url: https://test.pypi.org/legacy/ skip-existing: true complexity: name: Process test complexity runs-on: ubuntu-latest needs: coverage steps: - name: Check out committed code uses: actions/checkout@v4 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv uses: actions/cache@v4 with: path: venv key: >- ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('setup.py') }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Run complexity report (click to view details) run: | . venv/bin/activate echo "Showing complexity higher or equal to 'C'" radon cc plugwise/ tests/ -s -nc --no-assert python-plugwise-1.7.3/.gitignore000066400000000000000000000002431475766476500167220ustar00rootroot00000000000000build.sh .DS_Store *.pyc .*.swp __pycache__ /dist/ /*.egg-info /build/ .idea tests/__pycache__ .coverage .vscode venv *.sedbck .mypy_cache fixtures/updated/*/ tmp python-plugwise-1.7.3/.markdownlint.yaml000066400000000000000000000000331475766476500204020ustar00rootroot00000000000000default: true MD013: false python-plugwise-1.7.3/.pre-commit-config.yaml000066400000000000000000000072141475766476500212200ustar00rootroot00000000000000default_language_version: # force all unspecified python hooks to run python3 python: python3.13 repos: # Run manually in CI skipping the branch checks - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.9.7 hooks: - id: ruff name: "Ruff check" args: - --fix - id: ruff-format name: "Ruff format" - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: check-executables-have-shebangs name: "Check scripts" stages: [manual] - id: no-commit-to-branch name: "Check branch" args: - --branch=main - repo: https://github.com/asottile/pyupgrade rev: v3.19.1 hooks: - id: pyupgrade name: "Check Py upgrade" args: [--py311-plus] # Moved codespell configuration to setup.cfg as per 'all-files' issues not reading args - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell name: "Check spelling" exclude_types: [csv, json] - repo: https://github.com/PyCQA/bandit rev: 1.8.3 hooks: - id: bandit name: "Bandit checking" args: - --quiet - --format=custom - --configfile=tests/bandit.yaml files: ^(plugwise|tests)/.+\.py$ - repo: https://github.com/adrienverge/yamllint.git rev: v1.35.1 hooks: - id: yamllint name: "YAML linting" - repo: https://github.com/cdce8p/python-typing-update rev: v0.7.0 hooks: # Run `python-typing-update` hook manually from time to time # to update python typing syntax. # Will require manual work, before submitting changes! - id: python-typing-update name: "Python typing" stages: [manual] args: - --py39-plus - --force - --keep-updates files: ^(plugwise|tests)/.+\.py$ - repo: local hooks: # Run mypy through our wrapper script in order to get the possible # pyenv and/or virtualenv activated; it may not have been e.g. if # committing from a GUI tool that was not launched from an activated # shell. - id: setup name: "Setup" entry: /usr/bin/env bash -c 'test -d ./venv || scripts/setup.sh' language: script - id: setup_test name: "Setup (extended for testing" entry: /usr/bin/env bash -c 'test -f ./tmp/biome || scripts/setup_test.sh pre-commit' language: script - id: userdata name: "Validating userdata" entry: scripts/pre-commit.sh language: script types: [python] pass_filenames: false - id: mypy name: "Running MyPy" entry: scripts/run-in-env.sh mypy language: script types: [python] require_serial: true files: ^plugwise/$ - id: pylint name: "PyLinting" entry: scripts/run-in-env.sh pylint -j 0 language: script types: [python] files: ^plugwise/.+\.py$ - id: testing name: "Performing Tests" # yamllint disable-line rule:line-length entry: /usr/bin/env bash -c 'exec env GITHUB_ACTIONS="1" NO_FIXTURES="1" scripts/tests_and_coverage.sh test_and_coverage' language: script pass_filenames: false - id: biome name: "Biome (prettier)" entry: ./tmp/biome check fixtures/ plugwise/ tests/ --files-ignore-unknown=true --no-errors-on-unmatched --json-formatter-indent-width=2 --json-formatter-indent-style=space language: script - repo: https://github.com/igorshubovych/markdownlint-cli rev: v0.44.0 hooks: - id: markdownlint python-plugwise-1.7.3/.yamllint000066400000000000000000000022261475766476500165670ustar00rootroot00000000000000ignore: | .github* rules: braces: level: error min-spaces-inside: 0 max-spaces-inside: 1 min-spaces-inside-empty: -1 max-spaces-inside-empty: -1 brackets: level: error min-spaces-inside: 0 max-spaces-inside: 0 min-spaces-inside-empty: -1 max-spaces-inside-empty: -1 colons: level: error max-spaces-before: 0 max-spaces-after: 1 commas: level: error max-spaces-before: 0 min-spaces-after: 1 max-spaces-after: 1 comments: level: error require-starting-space: true min-spaces-from-content: 2 comments-indentation: level: error document-end: level: error present: false document-start: level: error present: false empty-lines: level: error max: 1 max-start: 0 max-end: 1 hyphens: level: error max-spaces-after: 1 indentation: level: error spaces: 2 indent-sequences: true check-multi-line-strings: false key-duplicates: level: error line-length: disable new-line-at-end-of-file: level: error new-lines: level: error type: unix trailing-spaces: level: error truthy: level: error python-plugwise-1.7.3/CHANGELOG.md000066400000000000000000001231621475766476500165510ustar00rootroot00000000000000# Changelog ## v1.7.3 - Improve readability of xml-data in POST/PUT requests via [#707](https://github.com/plugwise/python-plugwise/pull/707), [#708](https://github.com/plugwise/python-plugwise/pull/708) and [#715](https://github.com/plugwise/python-plugwise/pull/715) - Continuous improvements via [#711](https://github.com/plugwise/python-plugwise/pull/711), [#713](https://github.com/plugwise/python-plugwise/pull/713) and [#716](https://github.com/plugwise/python-plugwise/pull/716) ## v1.7.2 - Bugfix for Plugwise-beta issue [833](https://github.com/plugwise/plugwise-beta/issues/833) solving relay- and lock-switches not switching for the Stretch. ## v1.7.1 - Avoid None-init for smile_version [#699](https://github.com/plugwise/python-plugwise/pull/699) - Replace string.split() by string.partition() [#702](https://github.com/plugwise/python-plugwise/pull/702) ## v1.7.0 - Continuous improvements [#678](https://github.com/plugwise/python-plugwise/pull/678) - Refresh Anna_Elga_2 userdata and adapt, add missing item-count, line-up test-data headers [#679](https://github.com/plugwise/python-plugwise/pull/679) - Rework code: output a single dict, add gw_data items as Smile-properties [#698](https://github.com/plugwise/python-plugwise/pull/698) ## v1.6.4 - Continuous improvements [#662](https://github.com/plugwise/python-plugwise/pull/662) - Rework tooling [#664](https://github.com/plugwise/python-plugwise/pull/664) - Archive p1v4 userdata [#666](https://github.com/plugwise/python-plugwise/pull/666) - Correct manual_fixtures script [#668](https://github.com/plugwise/python-plugwise/pull/668) - Improve P1 fault-handling, continuous improvements [#670](https://github.com/plugwise/python-plugwise/pull/670) - Add control_state to Anna output [#671](https://github.com/plugwise/python-plugwise/pull/671) ## v1.6.3 - Implement cooling-related fixes, trying to solve HA Core issue [#132479](https://github.com/home-assistant/core/issues/132479) ## v1.6.2 - Improve control_state processing: - Change value from `off` to `idle` to better match HA Core `HVACAction` states. - Handle difference between old and new Adam firmware: set `control_state` based on `setpoint` vs `temperature` for older firmware. - Implement fix for [#776](https://github.com/plugwise/plugwise-beta/issues/776), move it from the integration to the backend library. - Add a test to cover the code that fixes #776. - Update related fixtures and test-data json files. ## v1.6.1 - Support python 3.13 ## v1.6.0 - New Feature: implement collection of location/zone data: Plugwise Adam thermostat representations are zone-based instead of device-based. Solution for HA Core issue [#130597](https://github.com/home-assistant/core/issues/130597) ## v1.5.2 - Bugfix for Adam: improve recognition of unknown zigbee devices. ## v1.5.1 - Fix typing and rounding of P1 and thermostat sensors, energy-device-related code improvements. - Rename mode to climate_mode. ## v1.5.0 - Make timeout an internal parameter. ## v1.4.4 - Change connect() function to output the gateway firmware-version. ## v1.4.3 - Clean up timeout-related, pass _request-function as an argument. ## v1.4.2 - Bugfix: implement solution for issue reported in [#739](https://github.com/plugwise/plugwise-beta/issues/739) ## v1.4.1 - Prettying documents with Biome (CLI), fixture layout updated accordingly. ## v1.4.0 - Improve model_id implementation, allow direct access to the gateway `smile_model_id`. ## v1.3.1 - Add missing typing for model_id. ## v1.3.0 - New Feature: add device model_id's to the API output (not for legacy devices). ## v1.2.0 - Improve the low_battery feature, also take the battery-critically-low warning notification into account. ## v1.1.0 - New Feature: add a low_battery binary_sensor for battery-powered devices and block the related battery-low notifications. ## v1.0.0 - First formal release to v1.0.0! ## v0.38.3 - Implement fix for Core Issue [#119686](https://github.com/home-assistant/core/issues/119686) ## v0.38.2 - Lower connection-timeout for actual devices after initial connect ## v0.38.1 - Add missing exception-handling for set-function in `__init__.py` - Add call_request() functions combining all common exception-handling for all set-functions - Update and improve test code - Implementing code improvements as suggested in #567 ## v0.38.0 - Add a reboot_gateway() function for actual Plugwise devices. ## v0.37.9 - Correct set_select() function. ## v0.37.8 - Create a set_select() function, combining the set_dhw_mode(), set_gateway_mode(), set_regulation_mode() and set_schedule_state() functions. ## v0.37.7 - Don't output schedule-related data when no valid schedule(s) found. - Various corrections to impacted test- and data-files/fixtures. ## v0.37.6 - Schedule-related improvements. - Revert removal of set_temperature_offset() function. ## v0.37.5 - Add setting the thermostat temperature_offset to the set_number() function. - Fix typo in manual_fixtures.py script. ## v0.37.4 - not released - Create a set_number() function, combining the set_number_setpoint() and set_temperature_offset() functions. ## v0.37.3 - Fix for [plugwise-beta #620](https://github.com/plugwise/plugwise-beta/issues/620). ## v0.37.2 - Code improvements. - Remove unused dependencies from pyproject.toml. ## V0.37.1 - Further optimization / deduplication of the refactored code. ## v0.37.0 - Refactor code into separate parts/paths for actual and legacy Plugwise devices. ## v0.36.3 - Bugfixes for [#558](https://github.com/plugwise/plugwise-beta/issues/558) and [#559](https://github.com/plugwise/plugwise-beta/issues/559). ## v0.36.2 - Improve support for Anna+Elga systems that do not support cooling (fix for [#547](https://github.com/plugwise/plugwise-beta/issues/547)). - Update test-fixtures for Plugwise-beta/Core Plugwise. - Fix deprecation-warnings. ## v0.36.1 - New Feature: For Adam, implement limited access to the gateway-modes. - Refresh adam_plus_anna_new userdata and adapt. - Bump actions and requirements to Python 3.12, where possible. - Ruff as per #470 (defaulting black and isort to ruff). - Modularize/split testing, including separation of code and data. - Improve quality as indicated by SonarCloud. ## v0.36.0 - retracted ## v0.35.4 - Remove support for Adam with fw 2.x and Anna with fw 3.x - Add 4.4.1 Anna testing (`control_state` added to xml but not active) - Maintenance, archive older firmware and clean/update tests accordingly - Introduce quick-fixture generation without testing - Fix `adam_jip` testcase ## v0.35.3 - Working solution for [Core Issue #104433](https://github.com/home-assistant/core/issues/104433) ## v0.35.2 - Add detection & removal of orphaned heater_central. - Bugfix for [Core Issue #104433](https://github.com/home-assistant/core/issues/104433) - Improve/optimize/reorder. - Typing-constants clean-up. ## v0.35.1 - Update OFF-constant, removal capital begin-letter. ## v0.35.0 - Feature: add "Off" as option in available_schedules, selecting this option will disable the active schedule for a thermostat. - Fix not being able to turn off a schedule. - Update fixture to create a testcase for HVACAction.PREHEATING ## v0.34.5 - Adam: return the control_state for each thermostat/location. - Bugfix: correct removal of obsolete `outdoor_air_temperature` sensor. ## v0.34.4 - Bugfix: avoid device_list growing at every full-update, add device_list to fixtures. ## v0.34.3 - Anna+Elga now always has `cooling_present` set to `True`: the Elga (always) has cooling-capability. - Cooling-mode on/off is determined from specific Elga status-codes. ## v0.34.2 - Add a list of Plugwise devices to the API. ## v0.34.1 - Skipped ## v0.34.0 - New feature: for Adam, provide mode = off, related to the regulation_mode = off, and mode = cool, for regulation_mode = cooling. Also, for Adam, return to providing a single setpoint for both heating and cooling. - Update userdata, manual-fixture-creation, and tests related to the added modes. - A few small Typing updates. - Manually change the adam_jip fixture, for testing in pw-beta/Core plugwise. ## v0.33.2 Bugfix for HA climate - Remove last_used (schedule) from output. - Bugfix for [Core Issue #102204](https://github.com/home-assistant/core/issues/102204) - Add item-count to output. - Support python 3.12 ## v0.33.1 Bugfix for Adam - Adam: remove use of control_state, xml-key no longer present. - Fix error in manual fixture creation. ## v0.33.0 Bugfixes, implement daily full-update - New feature: implement a daily full-update (other part of solution for [HA Core issue #99372](https://github.com/home-assistant/core/issues/99372)) - Reorder device-dicts: gateway first, optionally heater_central second - Improve handling of obsolete sensors (solution for [HA Core issue #100306](https://github.com/home-assistant/core/issues/100306) - Improve handling of invalid actuator xml-data (partial solution for [HA Core issue #99372](https://github.com/home-assistant/core/issues/99372) ## v0.32.3 Improve quality by extended testing, bugfix - Testing: make it possible to emulate binary_sensors, climates, numbers, sensors, switches, etc., updating. - Add extra updated-testcases for each platform. - Fix a bug which prevents the updating of the available-state of zigbee devices (correct data-collection at updating). - Optimize first-time data-collection at initialization. - Modify the added P1 Plugwise notification so that it does not impact the device-availability. ## v0.32.2 Continuous improvements, bugfix - Extend p1v4_442_triple userdata to include a Plugwise notification, extending the related fixture which is used in PW-beta and Core Plugwise. - Optimize and rearrange typing-related constants, implement and cleanup. - Optimize and reorder code, for the Stretch prevent the creation of a switch-group with an orphaned switch. ## v0.32.1 Improve typing, bugfix - Integrate the process of creating binary_sensors, sensors, and switches dicts. Should make typing simpler. - Fix an apparent notification-bug for p1v4. - Improve typing: fix all type-ignores. - Clean up no longer used code. - Remove support for python3.9. ## v0.32.0: New Feature: add support for changing the temperature offset on a supported thermostat device - Add support for changing the temperature-offset on Jip, Lisa, Tom, Floor and on Anna (in some configurations) - Fix issue introduced by ruff: replace using .keys() in xml-find result ## v0.31.9: Further typing improvements - Add NumberType, SelectType and SelectOptionsType constants to improve typing further - Code quality housekeeping ## v0.31.8: Improve typing as per Core PR #96915 ## v0.31.8: Improve typing - Add BinarySensorType, SensorType, SwitchType as per HA Core PR 96915 ## v0.31.7: Various small updates - Repair coverage/fix testing - #294 - Correct non-unique device names in adam_jip userdata - Add domestic_hot_water_setpoint data to anna_heatpump_heating userdata, update relevant test-cases - Add raising an error when providing the wrong type of temperature input to set_temperature() with cooling active - Add preliminary support for python 3.12 by updating build system requirements - Code improvements ## v0.31.6: Fix domestic_hot_water_setpoint-related bug for Anna + Elga - Add guarding for popping domestic_hot_water_setpoint - Improved fixture generation and prettifying ## v0.31.5: Cooling-related fix/improvements - Fix cooling-related bug in set_temperature(), raise an error when the user tries to change the not-active setpoint - Change setpoint_low/_high generation, show the active setpoint and the related min/max values, don't show related setpoints in the active schedule - Update related test-assert / fixtures - Improve dhw_setpoint related code ## v0.31.4: Improvements - Improve fixture generation and manual fixtures, exposing (prettier-ed) fixtures - Fix unneeded Union-typing ## v0.31.3: Typing updates, improved fixture generation and manual mode-changes ## v0.31.2: Introduce strict-typing (py.typed) ## v0.31.1: Legacy Anna - read and process system-xml data - Add support for reading the system-xml data from the legacy Smile T - Repo-generic: CI/CD Improvements ## v0.31.0: Split off the USB-related code: the Plugwise Stick related code has been moved into [#plugwise_usb](https://github.com/plugwise/python-plugwise-usb) --- Split between Smile/Stretch and USB-Stick related code --- ## v0.27.10: Anna + Elga: final fix for [#320](https://github.com/plugwise/plugwise-beta/issues/320) ## v0.27.9: P1 legacy: collect data from /core/modules - Collect P1 legacy data from /core/modules - fix for [#368](https://github.com/plugwise/plugwise-beta/issues/368) - `Dependencies`: Default to python 3.11 - `Development` - Improved markdown (i.e. markup and contents), added linter for markdown & added code owners - Replaced flake8 linting with ruff (following HA-Core) - Improved testing on commit ## v0.27.8: Stick bugfix: fix for reported Plugwise-Beta issue [#347](https://github.com/plugwise/plugwise-beta/issues/347) - Change message request queue a FiFO queue ## v0.27.7: Stick bugfix: fix for reported issue #312 - [#312](https://github.com/plugwise/plugwise-beta/issues/312) - Fix Stick-related memory-leaks - `Dependencies`: Add python 3.11 support ## v0.27.6: Stick bugfix: properly handle responses without mac ## v0.27.5: Bugfix for #340 - [#340](https://github.com/plugwise/plugwise-beta/issues/340) ## v0.27.4: Bugfix for HA Core Issue 85910 - [Core Issue 85910](https://github.com/home-assistant/core/issues/85910) (# v0.27.3, v0.27.2: were not released) ## v0.27.1: More cooling-related updates, based on additional info from Plugwise - Updates for Anna+Elga and Adam-OnOff systems - Loria/Thermastage fix ## v0.27.0: Smile P1: support 3-phase measurements (# v0.26.0: not released) ## v0.25.14: Improve, bugfix - Anna+Elga: final solution for [#320](https://github.com/plugwise/plugwise-beta/issues/320) - Related to [Core Issue 83068](https://github.com/home-assistant/core/issues/83068): handle actuator_functionality or sensor depending on which one is present ## v0.25.13: Anna+Elga, OnOff device: base heating_state, cooling_state on central_heating_state key only - Partial solution for [#320](https://github.com/plugwise/plugwise-beta/issues/320) - Improving the solution for [Core Issue 81839](https://github.com/home-assistant/core/issues/81839) ## v0.25.12: Revert remove raising of InvalidSetupError ## v0.25.11: Improve/change contents building on v0.25.10 - Revert: Improve handling of xml-data missing, raise exception with warning; the reason for adding this fix is not clear. Needs further investigation. - Remove raising of InvalidSetupError, no longer needed; handled in Plugwise config_flow (function added by Frenck) - Simplify logic calling _power_data_from_location() (similar to v0.21.4); possible solution for [Core Issue 81672](https://github.com/home-assistant/core/issues/81672) - _full_update_device(): revert back to v0.21.4 logic - async_update(): not needed to refresh self._modules - Add fix for Core #81712 ## v0.25.10: Thermostats: more improvements - Anna + Elga: hide cooling_enable switch, (hardware-)switch is on Elga, not in Plugwise App - Adam: improve collecting regulation_mode-related data. Fix for [#240](https://github.com/plugwise/python-plugwise/issues/240) - Anna: remove device availability, fix for [Core Issue 81716](https://github.com/home-assistant/core/issues/81716) - Anna + OnOff device: fix incorrect heating-state, fix for [Core Issue 81839](https://github.com/home-assistant/core/issues/81839) - Improve handling of xml-data missing, raise exception with warning. Solution for [Core Issue 81672](https://github.com/home-assistant/core/issues/81672) - Improve handling of empty schedule, fix for [#241](https://github.com/plugwise/python-plugwise/issues/241) ## v0.25.9: Adam: hide cooling-related switch, binary_sensors when there is no cooling present - This fixes the unexpected appearance of new entities after the Adam 3.7.1 firmware-update - Properly handle an empty schedule, should fix [#313](https://github.com/plugwise/plugwise-beta/issues/313) ## v0.25.8: Make collection of toggle-data future-proof ## v0.25.7: Correct faulty logic in the v0.25.6 release ## v0.25.6: Revert py.typed, fix Core PR #81531 ## v0.25.5: not released ## v0.25.4: Add py.typed, fix typing as suggested in #231 ## v0.25.3: Bugfix for #309 - [#309](https://github.com/plugwise/plugwise-beta/issues/309) ## v0.25.2: Bugfix, code improvements - Fix a set_temperature() and heat_cool related bug ## v0.25.1: Remove sensor-keys from output when cooling is present ## v0.25.0: Improve compatibility with HA Core climate platform - Change mode cool to heat_cool - Add setpoint_high/setpoint_low to output ## v0.24.1: Bugfix: fix root-cause of Core issue 79708 - [Core Issue 79708](https://github.com/home-assistant/core/issues/79708) ## v0.24.0: Improve support for Anna-Loria combination - Replace mode heat_cool by cool (available modes are: auto, heat, cool) - Add cooling_enabled switch - Add dhw_mode/dhw_modes (for selector in HA) - Add dhw_temperature sensor - Show Plugwise notifications for non-legacy Smile P1 ## v0.23.0: Add device availability for non-legacy Smiles - Add back Adam vacation preset, fixing reopened issue #185 ## v0.22.1: Improve solution for issue #213 ## v0.22.0: Smile P1 - add a P1 smartmeter device - Change all gateway model names to Gateway - Change Anna Smile name to Smile Anna, Anna model name to ThermoTouch - Change P1 Smile name to Smile P1 - Remove raise error-message, change priority of logger messages to less critical - Fix for issue #213 ## v0.21.3: Revert all hvac_mode HEAT_COOL related - The Anna-Elga usecase, providing a heating and a cooling setpoint, was reverted back to providing a single setpoint. ## v0.21.2: Code improvements, cleanup ## v0.21.1: Smile: various updates % fixes - Change Anna-gateway model to Smile - related to [Core blog entity_naming](https://developers.home-assistant.io/blog/2022/07/10/entity_naming/) and changes in the Core Plugwise(-beta) code. - Output elga_cooling_enabled, lortherm_cooling_enabled or adam_cooling_enabled when applicable. To be used in Core Plugwise(-beta) instead of calling api-variables. - Protect the self-variables that will no longer be used in Core Plugwise(-beta). - pyproject.toml updates. - Adapt test-code where needed. ## v0.21.0: Smile: improve and add to output, fix cooling-bug - Add `domestic_hot_water_setpoint` to the output. Will become an additional Number in Plugwise(-beta). - Create separate dicts for `domestic_hot_water_setpoint`, `maximum_boiler_temperature`, and `thermostat` in the output. - Change `set_max_boiler_temperature()` to `set_number_setpoint()` and make it more general so that more than one Number setpoint can be changed. - Fix a cooling-related bug (Anna + Elga). - Improve `set_temperature()`function. - Update the testcode accordingly. ## v0.20.1: Smile: fix/improve cooling support (Elga/Loria/Thermastage) based on input from Plugwise ## v0.20.0: Adam: add support for the Aqara Plug ## v0.19.1: Smile & Stretch: line up error handling with Plugwise-beta ## v0.19.0: Smile Adam & Anna: cooling-related updates - Anna: replace `setpoint` with `setpoint_low` and `setpoint_high` when cooling is active - Anna: update according to recent Anna-with-cooling firmware updates (info provided by Plugwise) - Anna: handle `cooling_state = on` according to Plugwise specification (`cooling_state = on` and `modulation_level = 100`) - Move boiler-type detection and cooling-present detection into `_all_device_data()` - Update/extend testing and corresponding userdata ## v0.18.5: Smile bugfix for #192 - [#192](https://github.com/plugwise/python-plugwise/issues/192) ## v0.18.4: Smile: schedule-related bug-fixes and clean-up - Update `_last_used_schedule()`: provide the collected schedules as input in order to find the last-modified valid schedule. - `_rule_ids_by_x()`: replace None by NONE, allowing for simpler typing. - Remove `schedule_temperature` from output: for Adam the schedule temperature cannot be collected when a schedule is not active. - Simplify `_schedules()`, don't collect the schedule-details as no longer required. - Improve solution for plugwise-beta issue #276 - Move HA Core input-checks into the backend library (into set_schedule_state() and set_preset()) ## v0.18.3: Smile: move solution for #276 into backend - [#276](https://github.com/plugwise/plugwise-beta/issues/276) ## v0.18.2: Smile: fix for #187 - [#187](https://github.com/plugwise/plugwise-beta/issues/187) ## v0.18.1: Smile Adam: don't show vacation-preset, as not shown in the Plugwise App or on the local Adam-website ## v0.18.0: Smile: add generation of cooling-schedules - Further improve typing hints: e.g. all collected measurements are now typed via TypedDicts - Implement correct generation of schedules for both heating and cooling (needs testing) ## v0.17.8: Smile: Bugfix, improve testing - Fix [#277](https://github.com/plugwise/plugwise-beta/issues/277) - Improve incorrect test-case validation ## v0.17.7: Smile: Corrections, fixes, clean up - Move compressor_state into binary_sensors - Adam: add missing zigbee_mac to wireless thermostats - Stretch & Adam: don't show devices without a zigbee_mac, should be orphaned devices - Harmonize appliance dicts for legacy devices - Typing improvements - Fix related test asserts ## v0.17.6: Smile: revert removing LOGGER.error messages ## v0.17.5: Smile: rework to raise instead of return - raise in error-cases, move LOGGER.debug messages into raise - clean up code ## v0.17.4 - Smile: improve typing hints, implement mypy testing ## v0.17.3 - Smile Adam: add support for heater_electric type Plugs ## v0.17.2 - Smile Adam: more bugfixes, improvementds - Bugfix: update set_schedule_state() to handle multi thermostat scenario's - Improve tracking of the last used schedule, needed due to the changes in set_schedule_state() - Improve invalid schedule handling - Update & add related testcases - Naming cleanup ## v0.17.1 - Smile: bugfix for Core Issue 68621 - [Core Issue 68621](https://github.com/home-assistant/core/issues/68621) ## v0.17.0 - Smile: add more outputs - Add regulation_mode and regulation_modes to gateway dict, add related set-function - Add max_boiler_temperature to heater_central dict, add related set-function - Improve typing hints ## v0.16.9 - Smile: bugfix and improve - Fix for [#250](https://github.com/plugwise/plugwise-beta/issues/250) - Rename heatpump outdoor_temperature sensor to outdoor_air_temperature sensor ## v0.16.8 - Smile: bugfixes, continued - Fix for [Core Issue 68003](https://github.com/home-assistant/core/issues/68003) - Refix solution for #158 ## v0.16.7 - Smile: Bugfixes, more changes and improvements - Fix for #158: error setting up for systems with an Anna and and Elga (heatpump). - Block connecting to the Anna when an Adam is present (fixes pw-beta #231). - Combine helper-functions, possible after removing code related to the device_state sensor. - Remove single_master_thermostat() function and the related self's, no longer needed. - Use .get() where possible. - Implement walrus constructs ( := ) where possible. - Improve and simplify. ## v0.16.6 - Smile: various changes/improvements - Provide cooling_state and heating_state as `binary_sensors`, show cooling_state only when cooling is present. - Clean up gw_data, e.g. remove `single_master_thermostat` key. ## v0.16.5 - Smile: small improvements - Move schedule debug-message to the correct position. - Code quality fixes. ## v0.16.4 - Adding measurements - Expose mac-addresses for network and zigbee devices. - Expose min/max thermostat (and heater) values and resolution (step in HA). - Changed mac-addresses in userdata/fixtures to be obfuscated but unique. ## v0.16.3 - Typing - Code quality improvements. ## v0.16.2 - Generic and Stretch - As per Core deprecation of python 3.8, removed CI/CD testing and bumped pypi to 3.9 and production. - Add support for Stretch with fw 2.7.18. ## v0.16.1 - Smile - various updates - **BREAKING**: Change active device detection, detect both OpenTherm (replace Auxiliary) and OnOff (new) heating and cooling devices. - Stretch: base detection on the always present Stick - Add Adam v3.6.x (beta) and Anna firmware 4.2 support (representation and switching on/off of a schedule has changed) - Anna: Fix cooling_active prediction - Schedules: always show `available_schemas` and `selected_schema`, also with "None" available and/or selected - Cleanup and optimize code - Adapt and improve testcode ## v0.16.0 - Smile - Change output format, allowing full use of Core DataUpdateCoordintor in plugwise-beta - Change from list- to dict-format for binary_sensors, sensors and switches - Provide gateway-devices for Legacy Anna and Stretch - Code-optimizations ## v0.15.7 - Smile - Improve implementation of cooling-function-detection - Anna: add two sensors related to automatic switching between heating and cooling and add a heating/cooling-mode active indication - Adam: also provide a heating/cooling-mode active indication - Fixing #171 - Improved dependency handling (@dependabot) ## v0.15.6 - Smile - Various fixes and improvements - Adam: collect `control_state` from master thermostats, allows showing the thermostat state as on the Plugwise App - Adam: collect `allowed_modes` and look for `cooling`, indicating cooling capability being available - Optimize code: use `_all_appliances()` once instead of 3 times, by updating/changing `single_master_thermostat()`, - Protect several more variables, - Change/improve how `illuminance` and `outdoor_temperature` are obtained, - Use walrus operator where applicable, - Various small code improvements, - Add and adapt testcode - Add testing for python 3.10, improve dependencies (github workflow) - Bump aiohttp to 3.8.1, remove fixed dependencies ## v0.15.5 - Skipping, not released ## v0.15.4 - Smile - Bugfix: handle removed thermostats - Recognize when a thermostat has been removed from a zone and don't show it in Core - Rename Group Switch to Switchgroup, remove vendor name ## v0.15.3 - Skipping, not released ## v0.15.2 - Smile: Implement possible fix for HA Core issue #59711 ## v0.15.1 - Smile: Dependency update (aiohttp 3.8.0) and aligning other HA Core dependencies ## v0.15.0 - Smile: remove all HA Core related-information from the provided output ## v0.14.5 - Smile: prepare for using the HA Core DataUpdateCoordintor in Plugwise-beta - Change the output to enable the use of the HA Core DUC in plugwise-beta. - Change state_class to "total" for interval- and net_cumulative sensors (following the HA Core sensor platform updates). - Remove all remnant code related to last_reset (log_date) - Restructure: introduce additional classes: SmileComm and SmileConnect ## v0.14.2 - Smile: fix P1 legacy location handling error ## v0.14.1 - Smile: removing further `last_reset`s - As per [Core Blog `state_class_total`](https://developers.home-assistant.io/blog/2021/08/16/state_class_total) ## v0.14.0 - Smile: sensor-platform updates - 2021.9 compatible ## v0.13.1 - Smile: fix point-sensor-names for P1 v2 ## v0.13.0 - Smile: fully support P1 legacy (specifically with firmware v2.1.13) ## v0.12.0 - Energy support and bugfixes - Stick: Add new properties `energy_consumption_today` counter and `energy_consumption_today_last_reset` timestamp. These properties can be used to properly measure the used energy. Very useful for the 'Energy' capabilities introduced in Home Assistant 2021.8 - Stick: Synchronize clock of all plugwise devices once a day - Stick: Reduced local clock drift from 30 to 5 seconds - Stick: Optimized retrieval and handling of energy history - Smile: add the required sensor attributes for Energy support - Smile: add last_reset timestamps for interval-sensors and cumulative sensors - Smile: fix the unit_of_measurement of electrical-cumulative-sensors (Wh --> kWh) ## 0.11.2 - Fix new and remaining pylint warnings ## 0.11.1 - Code improvements - Smile: improve use of protection for functions and parameter - Fix pylint warnings and errors ## 0.11.0 - Smile: add support for the Plugwise Jip - Adam, Anna: don't show removed thermostats / thermostats without a location ## 0.10.0 - Smile: move functionality into backend, rearrange data in output - Rearrange data: the outputs of get_all_devices() and get_device_data() are combined into self.gw_devices. Binary_sensors, sensors and switches are included with all their attributes, in lists. - Two classes have been added (entities.py), one for master_thermostats and one for binary_sensors, these classes now handle the processing of data previously done in plugwise-beta (climate.py and binary_sensor.py). ## 0.9.4 - Bugfix and improvements - Stick: make stick code run at python 3.9 (fixes AttributeError: 'Thread' object has no attribute 'isAlive') - Smile: underlying code improvements (solve complexity, linting, etc.), continuing to improve on the changes implemented in v0.9.2. ## 0.9.3 - Smile: add lock-state switches - Add support for getting and setting the lock-state of Plugs-, Circles-, Stealth-switches, for Adam and Stretch only. A set lock-state prevents a switch from being turned off. - There is no lock_state available for the following special Plugwise classes: `central heating pump` and `value actuator` ## 0.9.2 - Smile: optimize - Functions not called by the plugwise(-beta) code have been moved to helper.py in which they are part of the subclass SmileHelper - All for-loops are now executed only once, the results are stored in self-parameters. - Added fw, model and vendor information into the output of get_device_data(), for future use in the HA Core Plugwise(-beta) Integration - Split off HEATER_CENTRAL_MEASUREMENTS from DEVICE_MEASUREMENTS so they can be blocked when there is no Auxiliary device present - Collect only the data from the Smile that is needed: full_update_device() for initialisation, update-device() for updating of live data - Adapt test_smile.py to the new code, increase test-coverage further ## 0.9.1 - Smile: add Domestic Hot Water Comfort Mode switch - Feature request ## 0.9.0 - Stick: API change - Improvement: Debounce relay state - Improvement: Prioritize request so requests like switching a relay get send out before power measurement requests. - Improvement: Dynamically change the refresh interval based on the actual discovered nodes with power measurement capabilities - Added: New property attributes for USB-stick. The old methods are still available but will give a deprecate warning - Stick - `devices` (dict) - All discovered and supported plugwise devices with the MAC address as their key - `joined_nodes` (integer) - Total number of registered nodes at Plugwise Circle+ - `mac` (string) - The MAC address of the USB-Stick - `network_state` (boolean) - The state (on-line/off-line) of the Plugwise network. - `network_id` (integer) - The ID of the Plugwise network. - `port` (string) - The port connection string - All plugwise devices - `available` (boolean) - The current network availability state of the device - `battery_powered` (boolean) - Indicates if device is battery powered - `features` (tuple) - List of supported attribute IDs - `firmware_version` (string) - Firmware version device is running - `hardware_model` (string) - Hardware model name - `hardware_version` (string) - Hardware version of device - `last_update` (datetime) - Date/time stamp of last received update from device - `mac` (string) - MAC address of device - `measures_power` (boolean) - Indicates if device supports power measurement - `name` (string) - Name of device based om hardware model and MAC address - `ping` (integer) - Network roundtrip time in milliseconds - `rssi_in` (integer) - Inbound RSSI level in DBm - `rssi_out` (integer) - Outbound RSSI level based on the received inbound RSSI level of the neighbor node in DBm - Scan devices - `motion` (boolean) - Current detection state of motion. - Sense devices - `humidity` (integer) - Last reported humidity value. - `temperature` (integer) - Last reported temperature value. - Circle/Circle+/Stealth devices - `current_power_usage` (float) - Current power usage (Watts) during the last second - `current_power_usage_8_sec` (float) - Current power usage (Watts) during the last 8 seconds - `power_consumption_current_hour` (float) - Total power consumption (kWh) this running hour - `power_consumption_previous_hour` (float) - Total power consumption (kWh) during the previous hour - `power_consumption_today` (float) - Total power consumption (kWh) of today - `power_consumption_yesterday` (float) - Total power consumption (kWh) during yesterday - `power_production_current_hour` (float) - Total power production (kWh) this hour - `relay_state` (boolean) - State of the output power relay. Setting this property will operate the relay - Switch devices - `switch` (boolean) - Last reported state of switch - Stretch v2: fix failed connection by re-adding the aiohttp-workaround ## 0.8.6 - Stick: code quality improvements - Bug-fix: Power history was not reported (0 value) during last week of the month - Improvement: Validate message checksums - Improvement: Do a single ping request to validate if node is on-line - Improvement: Guard Scan sensitivity setting to medium - Improvement: Move general module code of messages, nodes, connection to the **init**.py files. - Improvement: Do proper timeout handling while sequence counter resets (once every 65532 messages) - Improvement: Better code separation. All logic is in their designated files: 1. Connection (connection/\*.py) 2. Data parsing (parser.py) 3. Data encoding/decoding of message (messages/\*.py) 4. Message handling - Initialization & transportation (controller.py) 5. Message processing - Do the required stuff (stick.py & nodes/\*.py) - Improvement: Resolves all flake8 comments ## 0.8.5 - Smile: fix sensor scaling - Fix for HA Core issue #44349 - Fix other value scaling bugs - Remove aiohttp-workaround - issue solved in aiohttp 3.7.1 (## 0.8.4 - Not released: Fix "Gas Consumed Interval stays 0" ) ## 0.8.2/0.8.3 - Smile: code quality improvements - Switch Smile to defusedxml from lxml (improving security) - Lint and flake recommendations fixed - Project CI changes - Bug-fix: fix use of major due to change of using semver.VersionInfo. - Add model-info: to be used in Core to provide a more correct model-name for each device. - Code improvements and increase in test-coverage. ## 0.8.1 - Stick: standardize logging ## 0.8.0 - Merged Smile/Stick module - Merge of the former network and former USB module to a single python module - Improved commit/test/CI&CD - Notifications handling for fixtures --- Changelogs below this line are separated in the former python-plugwise USB-only fork from @brefra and the former Plugwise_Smile Network-only module by @bouwew and @CoMPaTech --- ## Old change log python-plugwise ### 2.0.2 - Get MAC-address of stick ### 2.0.1 - Fixes and optimizations ### 2.0.0 - Support for Scan devices, (un)join of new devices and experimental support for Sense - [All details](https://github.com/brefra/python-plugwise/releases/tag/2.0.0) in the release tag ### 1.2.2 - Logging level corrections ### 1.2.1 - Watchdog exception fix ### 1.2.0 - Fixes and changes - Return power usage even if it's 0 - Callbacks for nodes discovered after initial scan ### 1.1.1 - Rewritten connection logic - Registered node counter - Improved reliability of node discovery - Fixed negative power usage ### alpha - rewrite to async ## Change log former Smile ### 1.6.0 - Adam: improved support for city-heating ### 1.5.1 - Decrease sensitivity for future updates ### 1.5.0 - Add delete_notification service - Add a service to dismiss/delete the Plugwise Notification(s) from within HA Core (plugwise.delete_notification) - Improve detection of switch-groups and add group switching for the Stretch ### 1.4.0 - Stretch and switch-groups - Improve error handling, add group switching of plugs (Adam). ### 1.3.0 - Only released in alpha/beta - Initial support for Stretch (v2/v3) including tests - Force gzip encoding, work-around for aiohttp-error - Improve P1 DSMR legacy support - Ensure `gateway_id` is properly defined (i.e. not `None`) - b4: Use `domain_objects` over `direct_objects` endpoints - Remove py3x internal modules (as requested per #86) - CI-handling improvements and both 3.7 and 3.8 testing - Code cleanup and output formatting improvements ### 1.2.2 - Re-fix notifications ### 1.2.1 - Fix url display, cleanup and adding tests ### 1.2.0 - HA-Core config_flow unique_id fixes - Fix situation where `unique_id` was set to `None` for legacy P1 DSMRs - Introduce using the (discovered) hostname as unique_id ### 1.1.2 - Fix notifications-related bugs ### 1.1.0 - Add HA-core test-fixtures, Plugwise notifications and improvement of error-detection - Add exporter for fixtures to be used by HA-core for testing plugwise - Improve `error`-detection - Expose Plugwise System notifications (i.e. warnings or errors visible in the app) ### 1.0.0 - Stable release - Just blacked code (Python `black`) ### 0.2.15 - Code cleanup - Just code improvements ### 0.2.14 - Code cleanup - Just code improvements ### 0.2.13 - Final legacy fix - Adjust `dwh` and `setpoint` handling ### 0.2.12 - Fix available schema's - Thanks to report from @fsaris - Adept code to allow for change introduced by firmware 4.x ### 0.2.11 - Add community requested sensors - See [65](https://github.com/plugwise/plugwise-beta/issues/65) - Add return water temperature from Auxiliary ### 0.2.10 - Core PR updates - Add exception for InvalidAuthentication - Revert setting heating when None ### 0.2.9 - Use intended state - Change to `intended_central_heating_state` ### 0.2.8 - Asynchronous HTTP improvement, firmware 4.x testing - Code improvement for asyncio - Added firmware 4.x test data and tests - CI/CD improve pre-commit hooks - Remove useless water sensor - Improve testing guidelines README ### 0.2.7 - CI/CD - CI/CD Version number handling ### 0.2.6 - New firmware support and XML handling - Improvement by contributor @sbeukers (Smile P1 v4 support) - Legacy Anna fixes and test improvements - Favour `domain_objects` over `appliances` XML-data ### 0.2.5 - Issuefix, cleanup and CI/CD - Fix for HVAC idle issue [#57](https://github.com/plugwise/plugwise-beta/issues/57) - Improve XML - Remove debug output - CI/CD handling ### 0.2.4 Legacy Anna fixes and Auxiliary handling - `chs` and `dhw` determined from `boiler_state` - No `chs` or `dhw` on legacy Anna - More legacy anna fixes ### 0.2.1 - Master thermostat fixes - Legacy Anna fixes - Auxiliary tests - Fix for `smt` (single master thermostat) - CI/CD Improved testing - Sensor value rounding ### 0.2.0 - Second beta release - Improve sensor names - Handle `set`-commands in testing - Code style improvements (lint/black) ### 0.1.26 - Documentation and CI/CD improvements - Create further testing - Improve coverage/linting/etc. - Prepare virtualenvs (travis etc.) - Code styling/wording fixes (lint/pep) - Improve READMEs ### 0.1.25 - Domestic hot water and CI/CD improvements - Testing improvements - `dhw`-handling ### 0.1.24 - Add handling erroneous XML and/or timeouts - Favour exception raises above returning `False` - Restructure full device update accordingly - Add Plugwise Exceptions - CI/CD add tests accordingly ### 0.1.23 - Code quality improvements - FutureWarnings acted accordingly ### 0.1.22 - Add scheduled temperature in output ### 0.1.21 - CI/CD improvements - Add heatpump-environment data and tests (thanks to @marcelveldt) - Improve `outdoor_temperature` accordingly (favour Auxiliary over Smile) ### 0.1.20 - Fix thermostat count ### 0.1.19 - Add thermostat counting ### 0.1.18 - Add flame state ### 0.1.17 - Code improvements - Squash device names ### 0.1.16 - Fix central components - Version skip to align with `-beta`-component ### 0.1.12 - Introduce heatpump - Thanks to @marcelveldt and his environment - Coherent heating/cooling state ### 0.1.11 - Add all options for P1 DSMR - Thanks to @(tbd) and his environment ### 0.1.9 - Set HVAC on legacy Anna ### 0.1.8 - Scheduled state on legacy Anna ### 0.1.7 - Legacy Anna small improvements ### 0.1.6 - Fix schedules for Legacy Anna's ### 0.1.2 - Code improvements and public variables - More linting - Cleanup scan_thermostat - Cleanup unused variables - Improve/standardize public variables - Tests updated accordingly - Version skip to align with `-beta`-component ### 0.1.0 - Public beta ### 0.0.57 - Review to public beta - Delete fugly sleeping - Improve binary sensors - Update tests accordingly ### 0.0.56 - Documentation and code improvements - `black` - READMEs updated ### 0.0.55 - `dhw` off for legacy Anna ### 0.0.54 - Gateway detection (which smile) ### 0.0.53 - Gateway detection (which smile) ### 0.0.52 - Fix for Legacy anna missing devices ### 0.0.51 - Add Anna firmware 4.x support ### 0.0.43 - Thermostat finding and peak/net P1 DSMR values - Fix peak values for DSMR - Calculate net (netto) values - Thermostat finder - Add tests accordingly ### 0.0.40 - Legacy Anna and legacy P1 introduction - Re-introduce legacy Anna from `haanna`/`anna-ha` - Add legacy P1 DSMR - Including tests ### 0.0.27 - Prepare for HA config flow and multiple devices - Add tests and location mapping - Improve handling Lisa thermostat - Improve relay (plugs) functionality - Add individual Smiles as 'hub'-components ### 0.0.26 - Add relay (plugs) support and tests ### 0.0.x - Not individually release but left in old repository - [this repo](https://github.com/plugwise/Plugwise-HA) ### x.x.x - Before that commits where made in haanna - [haanna](https://github.com/laetificat/haanna) - After mostly leaving `haanna` as a stale project (where @bouwew didn't have PyPi permissions) development was shortly split between personal repositories from both @bouwew and @CoMPaTech before we decided to fully rewrite - from scratch - it to `Plugwise-HA` which was renamed to `Plugwise_Smile` from 0.0.26 onwards. python-plugwise-1.7.3/CODEOWNERS000066400000000000000000000010331475766476500163230ustar00rootroot00000000000000# Plugwise CodeOwners # Order is important. The last matching pattern has the most precedence. # Specific files setup.cfg @plugwise/plugwise-smile setup.py @plugwise/plugwise-smile pyproject.toml @plugwise/plugwise-smile requirements*.txt @plugwise/plugwise-smile # Main code /plugwise/ @plugwise/plugwise-smile /userdata/ @plugwise/plugwise-smile # Tests and development support /tests/ @bouwew @compatech /scripts/ @bouwew @compatech # Networked Plugwise components /plugwise @bouwew @compatech # Generic * @plugwise/plugwise-smile python-plugwise-1.7.3/LICENSE000066400000000000000000000021701475766476500157400ustar00rootroot00000000000000MIT License Copyright (c) 2019 @laetificat, 2019-2020 @CoMPaTech & @bouwew, 2020-current @CoMPaTech, @bouwew & @brefra Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-plugwise-1.7.3/README.md000066400000000000000000000155741475766476500162260ustar00rootroot00000000000000# Plugwise python module This module is the backend for the [`plugwise` component](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) in Home Assistant Core (which we maintain as code owners). This module supports Hubs such as `Adam`, `Smile`s for Anna and P1 and `Stretch`, i.e. the networked plugwise devices. For the USB (or Stick-standalone version) please refer to upcoming [`plugwise-usb` component](https://github.com/plugwise/plugwise_usb-beta). Our main usage for this module is supporting [Home Assistant](https://www.home-assistant.io) / [home-assistant](http://github.com/home-assistant/core/) ![Static Badge](https://img.shields.io/badge/Plugwise_Discord-Join_now-purple?style=social&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FmFVhF8Ar6A) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/plugwise) [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai) [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/plugwise/python-plugwise/issues/291) [![PyPI version fury.io](https://badge.fury.io/py/plugwise.svg)](https://pypi.python.org/pypi/plugwise/) [![Latest release](https://github.com/plugwise/python-plugwise/workflows/Latest%20release/badge.svg)](https://github.com/plugwise/python-plugwise/actions) [![Newest commit](https://github.com/plugwise/python-plugwise/workflows/Latest%20commit/badge.svg)](https://github.com/plugwise/python-plugwise/actions) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/plugwise/python-plugwise/main.svg)](https://results.pre-commit.ci/latest/github/plugwise/python-plugwise/main) [![CodeFactor](https://www.codefactor.io/repository/github/plugwise/python-plugwise/badge)](https://www.codefactor.io/repository/github/plugwise/python-plugwise) [![codecov](https://codecov.io/gh/plugwise/python-plugwise/branch/main/graph/badge.svg)](https://codecov.io/gh/plugwise/python-plugwise) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=plugwise_python-plugwise&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=plugwise_python-plugwise) [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=plugwise_python-plugwise&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=plugwise_python-plugwise) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=plugwise_python-plugwise&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=plugwise_python-plugwise) ## Integration ### Home-Assistant Integration (maintained through Home-Assistant) [![Generic badge](https://img.shields.io/badge/HA%20core-yes-green.svg)](https://github.com/home-assistant/core/tree/dev/homeassistant/components/plugwise) Works out of the box with every Home Assistant installation, use the button below to install [![Open your Home Assistant instance and show your integrations.](https://my.home-assistant.io/badges/integrations.svg)](https://my.home-assistant.io/redirect/integrations/) ### Home-Assistant custom_component (beta) We do (also) maintain a `custom_component`, please note this is **only** intended for users helping us test new features (use at your own risk) [![Generic badge](https://img.shields.io/github/v/release/plugwise/plugwise-beta)](https://github.com/plugwise/plugwise-beta) You can add our `custom_component` repository to HACS, do note that we do not intent for our `beta` `custom_component` to be included in the HACS repository. [![Generic badge](https://img.shields.io/badge/HACS-add%20our%20repo-yellow.svg)](https://github.com/plugwise/plugwise-beta) See the [`plugwise-beta`](https://github.com/plugwise/plugwise-beta) repository for more info. ## Development/patches Like Home Assistant Core, we use `pre-commit` and additionally run [pre-commit.ci](http://pre-commit.ci) to automatically validate your commits and PRs. If you want to create a PR, please ensure you at least run `scripts/setup.sh`. This will ensure your environment is set up correctly before attempting to `git commit`. We sincerely and highly recommended also setting up local testing, see [`tests/README.md`](https://github.com/plugwise/python-plugwise/blob/main/tests/README.md) for more information and run `scripts/setup_test.sh` to prepare your environment. ## Project support status **Notice** at this time we are refactoring the module code to move towards a supporting way for the integration to become multiple components under an umbrella `plugwise` integration featuring multiple components. Module providing interfacing with the Plugwise devices: ### Smile - [x] Adam - [x] Lisa - [x] Jip - [x] Floor - [x] Tom - [x] Koen (a Koen always comes with a Plug, the Plug is the active part) - [x] Plug - [x] Aqara Plug - [x] Anna - [x] Smile P1 - [x] Stretch - [ ] Some of the equipment mentioned in USB when in use via Stretch or Adam - [x] [Home-Assistant](https://home-assistant.io) via - [x] Native supporting networked Plugwise products - [x] [HACS](https://hacs.xyz) and `custom_component` [Plugwise Beta](https://github.com/plugwise/plugwise-beta/) (supporting all devices above) ## License, origins and contributors As per the origins, we have retained the appropriate licensing and including the MIT-license for this project. Origins (from newest to oldest): - Networked (Smile/Stretch) Plugwise support by @bouwew (Bouwe) and @CoMPaTech (Tom). We both support and help out @brefra (Frank) where possible, he's supporting the USB module and integration. - 'All' available Plugwise support by @bouwew (Bouwe), @brefra (Frank) and @CoMPaTech (Tom) - Upstreamed haanna/HA-core Anna, including all later products - 'Plugwise-Smile/Plugwise-HA/plugwise-beta' by @bouwew (Bouwe) & @CoMPaTech (Tom) - Networked Plugwise Anna module with custom_module - `haanna/anna-ha` via (Kevin) - USB-based stick module with custom_module - `plugwise-stick/plugwise` by @brefra (Frank) - USB-plugwise module - `plugwise` by (Ron) originally by (Johan) (with reference only in license to Sven) - Sensor for Plugwise Smile P1 integration - `home-assistant-sensor-plugwise-smile-p1` by (Jeroen van der Schoot) ## Thanks On behalf of all of us, big thanks to Plugwise and community members @riemers and @tane from [HAshop](https://hashop.nl) for their support and obviously all our users and testers who dealt with our typos and challenges. Disclaimer, while we are communicating with Plugwise and they expressed their gratitude through their newsletter, we are not part of Plugwise as a company. We are just a bunch of guys anxious to get our (and your) Plugwise products working with Home Assistant. python-plugwise-1.7.3/SECURITY.md000066400000000000000000000020141475766476500165210ustar00rootroot00000000000000# Security Policy ## Supported Versions As spare-time/free-time developers we support this python module as best as we can. We will support released versions as old as the module version included in the `manifest.json` of the current and previous releases of [Home Assistant Core](https://github.com/home-assistant/core) and/or [`plugwise-beta`](https://github.com/plugwise/plugwise-beta) (whichever used release is the oldest). ## Reporting a Vulnerability Create an issue in this repository using the `bug` template. We're frequent visitors of our own repositories and will try to provide a solution as quick as we can. We are available on discourse using our github aliases for quicker response, but always file an issue so other users are also informed. (Security) fixes will always be pre-released and released through [`plugwise-beta`](https://github.com/plugwise/plugwise-beta) for testing. A PR to HA Core will follow either in parallel or as soon as possible. Thanks in advance for helping us keeping the community safe. python-plugwise-1.7.3/fixtures/000077500000000000000000000000001475766476500166045ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_heatpump_cooling/000077500000000000000000000000001475766476500231235ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_heatpump_cooling/data.json000066400000000000000000000515741475766476500247430ustar00rootroot00000000000000{ "04b15f6e884448288f811d29fb7b1b30": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer SJ", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 22.6 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 20.5, "upper_bound": 99.9 }, "thermostats": { "primary": ["d3a276aeb3114a509bab1e4bf8c40348"], "secondary": [] }, "vendor": "Plugwise" }, "0ca13e8176204ca7bf6f09de59f81c83": { "available": true, "binary_sensors": { "cooling_enabled": true, "cooling_state": false, "dhw_state": true, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "eedadcb297564f1483faa509179aebed", "max_dhw_temperature": { "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 65.0 }, "maximum_boiler_temperature": { "lower_bound": 7.0, "resolution": 0.01, "setpoint": 35.0, "upper_bound": 50.0 }, "model": "Generic heater/cooler", "model_id": "17.1", "name": "OpenTherm", "sensors": { "dhw_temperature": 63.5, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 13.5, "return_temperature": 24.9, "water_pressure": 2.0, "water_temperature": 24.5 }, "switches": { "dhw_cm_switch": true }, "vendor": "Remeha B.V." }, "1053c8bbf8be43c6921742b146a625f1": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "b52908550469425b812c87f766fe5303", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat BK", "sensors": { "battery": 55, "setpoint": 18.0, "temperature": 18.8 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A17" }, "1a27dd03b5454c4e8b9e75c8d1afc7af": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "20e735858f8146cead98b873177a4f99", "model": "Plug", "model_id": "160-01", "name": "Smart Plug DB", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "20e735858f8146cead98b873177a4f99": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer DB", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 22.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["47e2c550a33846b680725aa3fb229473"], "secondary": [] }, "vendor": "Plugwise" }, "2e0fc4db2a6d4cbeb7cf786143543961": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "a562019b0b1f47a4bde8ebe3dbe3e8a9", "model": "Plug", "model_id": "160-01", "name": "Smart Plug KK", "sensors": { "electricity_consumed": 2.13, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" }, "3b4d2574e2c9443a832b48d19a1c4f06": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "04b15f6e884448288f811d29fb7b1b30", "model": "Plug", "model_id": "160-01", "name": "Smart Plug SJ", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A14" }, "3f0afa71f16c45ab964050002560e43c": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "fa5fa6b34f6b40a0972988b20e888ed4", "model": "Plug", "model_id": "160-01", "name": "Smart Plug WK", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A18" }, "47e2c550a33846b680725aa3fb229473": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "20e735858f8146cead98b873177a4f99", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat DB", "sensors": { "setpoint": 18.0, "temperature": 22.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A20" }, "5cc21042f87f4b4c94ccb5537c47a53f": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Badkamer 2", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "Werkdag schema", "sensors": { "electricity_consumed": 0.0, "temperature": 21.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 20.5, "upper_bound": 99.9 }, "thermostats": { "primary": ["f04c985c11ad4848b8fcd710343f9dcf"], "secondary": [] }, "vendor": "Plugwise" }, "5ead63c65e5f44e7870ba2bd680ceb9e": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "9a27714b970547ee9a6bdadc2b815ad5", "model": "Plug", "model_id": "160-01", "name": "Smart Plug SQ", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A15" }, "7d97fc3117784cfdafe347bcedcbbbcb": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.2.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "eedadcb297564f1483faa509179aebed", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": [ "heating", "off", "bleeding_cold", "bleeding_hot", "cooling" ], "select_gateway_mode": "full", "select_regulation_mode": "cooling", "sensors": { "outdoor_temperature": 13.4 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "7fda9f84f01342f8afe9ebbbbff30c0f": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "e39529c79ab54fda9bed26cfc0447546", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat JM", "sensors": { "setpoint": 18.0, "temperature": 20.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "838c2f48195242709b87217cf8d8a71f": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "b52908550469425b812c87f766fe5303", "model": "Plug", "model_id": "160-01", "name": "Smart Plug BK", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "8a482fa9dddb43acb765d019d8c9838b": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "5cc21042f87f4b4c94ccb5537c47a53f", "model": "Plug", "model_id": "160-01", "name": "Smart Plug BK2", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "8cf650a4c10c44819e426bed406aec34": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Badkamer 1", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "Werkdag schema", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 21.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 20.5, "upper_bound": 99.9 }, "thermostats": { "primary": ["eac5db95d97241f6b17790897847ccf5"], "secondary": [] }, "vendor": "Plugwise" }, "93ac3f7bf25342f58cbb77c4a99ac0b3": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer RB", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 3.13, "temperature": 20.7 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 17.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["c4ed311d54e341f58b4cdd201d1fde7e"], "secondary": [] }, "vendor": "Plugwise" }, "96714ad90fc948bcbcb5021c4b9f5ae9": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "e39529c79ab54fda9bed26cfc0447546", "model": "Plug", "model_id": "160-01", "name": "Smart Plug JM", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "9a27714b970547ee9a6bdadc2b815ad5": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer SQ", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 21.4 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.5, "upper_bound": 99.9 }, "thermostats": { "primary": ["beb32da072274e698146db8b022f3c36"], "secondary": [] }, "vendor": "Plugwise" }, "a03b6e8e76dd4646af1a77c31dd9370c": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "93ac3f7bf25342f58cbb77c4a99ac0b3", "model": "Plug", "model_id": "160-01", "name": "Smart Plug RB", "sensors": { "electricity_consumed": 3.13, "electricity_consumed_interval": 0.77, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "a562019b0b1f47a4bde8ebe3dbe3e8a9": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Keuken", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "Werkdag schema", "sensors": { "electricity_consumed": 2.13, "electricity_produced": 0.0, "temperature": 22.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 99.9 }, "thermostats": { "primary": ["ea8372c0e3ad4622ad45a041d02425f5"], "secondary": [] }, "vendor": "Plugwise" }, "b52908550469425b812c87f766fe5303": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bijkeuken", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 18.8 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["1053c8bbf8be43c6921742b146a625f1"], "secondary": [] }, "vendor": "Plugwise" }, "bbcffa48019f4b09b8368bbaf9559e68": { "available": true, "dev_class": "valve_actuator_plug", "firmware": "2020-05-13T02:00:00+02:00", "location": "8cf650a4c10c44819e426bed406aec34", "model": "Plug", "model_id": "160-01", "name": "Smart Plug BK1", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A16" }, "beb32da072274e698146db8b022f3c36": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "9a27714b970547ee9a6bdadc2b815ad5", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat SQ", "sensors": { "setpoint": 18.5, "temperature": 21.4 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "c4ed311d54e341f58b4cdd201d1fde7e": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "93ac3f7bf25342f58cbb77c4a99ac0b3", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat RB", "sensors": { "setpoint": 17.0, "temperature": 20.7 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "ca79d23ae0094120b877558734cff85c": { "dev_class": "thermostat", "location": "fa5fa6b34f6b40a0972988b20e888ed4", "model": "ThermoTouch", "model_id": "143.1", "name": "Thermostaat WK", "sensors": { "setpoint": 21.5, "temperature": 22.5 }, "vendor": "Plugwise" }, "d3a276aeb3114a509bab1e4bf8c40348": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "04b15f6e884448288f811d29fb7b1b30", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat SJ", "sensors": { "setpoint": 20.5, "temperature": 22.6 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "e39529c79ab54fda9bed26cfc0447546": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "cool", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer JM", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 20.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["7fda9f84f01342f8afe9ebbbbff30c0f"], "secondary": [] }, "vendor": "Plugwise" }, "ea8372c0e3ad4622ad45a041d02425f5": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "a562019b0b1f47a4bde8ebe3dbe3e8a9", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat KK", "sensors": { "battery": 53, "setpoint": 21.5, "temperature": 22.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "eac5db95d97241f6b17790897847ccf5": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "8cf650a4c10c44819e426bed406aec34", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat BK1", "sensors": { "setpoint": 20.5, "temperature": 21.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "f04c985c11ad4848b8fcd710343f9dcf": { "available": true, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "5cc21042f87f4b4c94ccb5537c47a53f", "model": "Lisa", "model_id": "158-01", "name": "Thermostaat BK2", "sensors": { "setpoint": 20.5, "temperature": 21.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, "fa5fa6b34f6b40a0972988b20e888ed4": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "Werkdag schema", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 22.5 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ca79d23ae0094120b877558734cff85c"], "secondary": [] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/adam_jip/000077500000000000000000000000001475766476500203505ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_jip/data.json000066400000000000000000000232431475766476500221600ustar00rootroot00000000000000{ "06aecb3d00354375924f50c47af36bd2": { "active_preset": "no_frost", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 24.2 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["1346fbd8498d4dbcab7e18d51b771f3d"], "secondary": ["356b65335e274d769c338223e7af9c33"] }, "vendor": "Plugwise" }, "13228dab8ce04617af318a2888b3c548": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 27.4 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.01, "setpoint": 9.0, "upper_bound": 30.0 }, "thermostats": { "primary": ["f61f1a2535f54f52ad006a3d18e459ca"], "secondary": ["833de10f269c4deab58fb9df69901b4e"] }, "vendor": "Plugwise" }, "1346fbd8498d4dbcab7e18d51b771f3d": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "06aecb3d00354375924f50c47af36bd2", "model": "Lisa", "model_id": "158-01", "name": "Slaapkamer", "sensors": { "battery": 92, "setpoint": 13.0, "temperature": 24.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "1da4d325838e4ad8aac12177214505c9": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "d58fec52899f4f1c92e4f8fad6d8c48c", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Logeerkamer", "sensors": { "setpoint": 13.0, "temperature": 28.8, "temperature_difference": 2.0, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "356b65335e274d769c338223e7af9c33": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "06aecb3d00354375924f50c47af36bd2", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Slaapkamer", "sensors": { "setpoint": 13.0, "temperature": 24.2, "temperature_difference": 1.7, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "457ce8414de24596a2d5e7dbc9c7682f": { "available": true, "dev_class": "zz_misc_plug", "location": "9e4433a9d69f40b3aefd15e74395eaec", "model": "Aqara Smart Plug", "model_id": "lumi.plug.maeu01", "name": "Plug", "sensors": { "electricity_consumed_interval": 0.0 }, "switches": { "lock": true, "relay": false }, "vendor": "LUMI", "zigbee_mac_address": "ABCD012345670A06" }, "6f3e9d7084214c21b9dfa46f6eeb8700": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "d27aede973b54be484f6842d1b2802ad", "model": "Lisa", "model_id": "158-01", "name": "Kinderkamer", "sensors": { "battery": 79, "setpoint": 13.0, "temperature": 30.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "833de10f269c4deab58fb9df69901b4e": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "13228dab8ce04617af318a2888b3c548", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Woonkamer", "sensors": { "setpoint": 9.0, "temperature": 24.0, "temperature_difference": 1.8, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "a6abc6a129ee499c88a4d420cc413b47": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "d58fec52899f4f1c92e4f8fad6d8c48c", "model": "Lisa", "model_id": "158-01", "name": "Logeerkamer", "sensors": { "battery": 80, "setpoint": 13.0, "temperature": 30.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "b5c2386c6f6342669e50fe49dd05b188": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.2.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "9e4433a9d69f40b3aefd15e74395eaec", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": ["heating", "off", "bleeding_cold", "bleeding_hot"], "select_gateway_mode": "full", "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 24.9 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "d27aede973b54be484f6842d1b2802ad": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Kinderkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 30.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["6f3e9d7084214c21b9dfa46f6eeb8700"], "secondary": ["d4496250d0e942cfa7aea3476e9070d5"] }, "vendor": "Plugwise" }, "d4496250d0e942cfa7aea3476e9070d5": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "d27aede973b54be484f6842d1b2802ad", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Kinderkamer", "sensors": { "setpoint": 13.0, "temperature": 28.7, "temperature_difference": 1.9, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "d58fec52899f4f1c92e4f8fad6d8c48c": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Logeerkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 30.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["a6abc6a129ee499c88a4d420cc413b47"], "secondary": ["1da4d325838e4ad8aac12177214505c9"] }, "vendor": "Plugwise" }, "e4684553153b44afbef2200885f379dc": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "9e4433a9d69f40b3aefd15e74395eaec", "max_dhw_temperature": { "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 20.0, "resolution": 0.01, "setpoint": 90.0, "upper_bound": 90.0 }, "model": "Generic heater", "model_id": "10.20", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "return_temperature": 37.1, "water_pressure": 1.4, "water_temperature": 37.3 }, "switches": { "dhw_cm_switch": false }, "vendor": "Remeha B.V." }, "f61f1a2535f54f52ad006a3d18e459ca": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermometer", "firmware": "2020-09-01T02:00:00+02:00", "hardware": "1", "location": "13228dab8ce04617af318a2888b3c548", "model": "Jip", "model_id": "168-01", "name": "Woonkamer", "sensors": { "battery": 100, "humidity": 56.2, "setpoint": 9.0, "temperature": 27.4 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" } } python-plugwise-1.7.3/fixtures/adam_multiple_devices_per_zone/000077500000000000000000000000001475766476500250245ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_multiple_devices_per_zone/data.json000066400000000000000000000370601475766476500266360ustar00rootroot00000000000000{ "02cf28bfec924855854c544690a609ef": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "NVR", "sensors": { "electricity_consumed": 34.0, "electricity_consumed_interval": 9.15, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A15" }, "08963fec7c53423ca5680aa4cb502c63": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Badkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "Badkamer Schema", "sensors": { "temperature": 18.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 14.0, "upper_bound": 100.0 }, "thermostats": { "primary": [ "f1fee6043d3642a9b0a65297455f008e", "680423ff840043738f42cc7f1ff97a36" ], "secondary": [] }, "vendor": "Plugwise" }, "12493538af164a409c6a1c79e38afe1c": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bios", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 16.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["df4a4a8169904cdb9c03d61a21f42140"], "secondary": ["a2c3583e0a6349358998b760cea82d2a"] }, "vendor": "Plugwise" }, "21f2b542c49845e6bb416884c55778d6": { "available": true, "dev_class": "game_console_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Playstation Smart Plug", "sensors": { "electricity_consumed": 84.1, "electricity_consumed_interval": 8.6, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "446ac08dd04d4eff8ac57489757b7314": { "active_preset": "no_frost", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Garage", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "off", "sensors": { "temperature": 15.6 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 5.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["e7693eb9582644e5b865dba8d4447cf1"], "secondary": [] }, "vendor": "Plugwise" }, "4a810418d5394b3f82727340b91ba740": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "USG Smart Plug", "sensors": { "electricity_consumed": 8.5, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A16" }, "675416a629f343c495449970e2ca37b5": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Ziggo Modem", "sensors": { "electricity_consumed": 12.2, "electricity_consumed_interval": 2.97, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "680423ff840043738f42cc7f1ff97a36": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Badkamer 1", "sensors": { "battery": 51, "setpoint": 14.0, "temperature": 19.1, "temperature_difference": -0.4, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A17" }, "6a3bf693d05e48e0b460c815a4fdd09d": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Lisa", "model_id": "158-01", "name": "Zone Thermostat Jessie", "sensors": { "battery": 37, "setpoint": 15.0, "temperature": 17.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "78d1126fc4c743db81b61c20e88342a7": { "available": true, "dev_class": "central_heating_pump_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Plug", "model_id": "160-01", "name": "CV Pomp", "sensors": { "electricity_consumed": 35.6, "electricity_consumed_interval": 7.37, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "82fa13f017d240daa0d0ea1775420f24": { "active_preset": "asleep", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Jessie", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "CV Jessie", "sensors": { "temperature": 17.2 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 15.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["6a3bf693d05e48e0b460c815a4fdd09d"], "secondary": ["d3da73bde12a47d5a6b8f9dad971f2ec"] }, "vendor": "Plugwise" }, "90986d591dcd426cae3ec3e8111ff730": { "binary_sensors": { "heating_state": true }, "dev_class": "heater_central", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "model": "Unknown", "name": "OnOff", "sensors": { "intended_boiler_temperature": 70.0, "modulation_level": 1, "water_temperature": 70.0 } }, "a28f588dc4a049a483fd03a30361ad3a": { "available": true, "dev_class": "settop_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Fibaro HC2", "sensors": { "electricity_consumed": 12.5, "electricity_consumed_interval": 3.8, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Tom/Floor", "model_id": "106-03", "name": "Bios Cv Thermostatic Radiator ", "sensors": { "battery": 62, "setpoint": 13.0, "temperature": 17.2, "temperature_difference": -0.2, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "b310b72a0e354bfab43089919b9a88bf": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Tom/Floor", "model_id": "106-03", "name": "Floor kraan", "sensors": { "setpoint": 21.5, "temperature": 26.0, "temperature_difference": 3.5, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "b59bcebaf94b499ea7d46e4a66fb62d8": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa WK", "sensors": { "battery": 34, "setpoint": 21.5, "temperature": 20.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "c50f167537524366a5af7aa3942feb1e": { "active_preset": "home", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "heating", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "GF7 Woonkamer", "sensors": { "electricity_consumed": 35.6, "electricity_produced": 0.0, "temperature": 20.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["b59bcebaf94b499ea7d46e4a66fb62d8"], "secondary": ["b310b72a0e354bfab43089919b9a88bf"] }, "vendor": "Plugwise" }, "cd0ddb54ef694e11ac18ed1cbce5dbbd": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "NAS", "sensors": { "electricity_consumed": 16.5, "electricity_consumed_interval": 0.5, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A14" }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Jessie", "sensors": { "battery": 62, "setpoint": 15.0, "temperature": 17.1, "temperature_difference": 0.1, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "df4a4a8169904cdb9c03d61a21f42140": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa Bios", "sensors": { "battery": 67, "setpoint": 13.0, "temperature": 16.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" }, "e7693eb9582644e5b865dba8d4447cf1": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "446ac08dd04d4eff8ac57489757b7314", "model": "Tom/Floor", "model_id": "106-03", "name": "CV Kraan Garage", "sensors": { "battery": 68, "setpoint": 5.5, "temperature": 15.6, "temperature_difference": 0.0, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, "f1fee6043d3642a9b0a65297455f008e": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Lisa", "model_id": "158-01", "name": "Thermostatic Radiator Badkamer 2", "sensors": { "battery": 92, "setpoint": 14.0, "temperature": 18.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "fe799307f1624099878210aa0b9f1475": { "binary_sensors": { "plugwise_notification": true }, "dev_class": "gateway", "firmware": "3.0.15", "hardware": "AME Smile 2.0 board", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." } }, "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 7.81 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" } } python-plugwise-1.7.3/fixtures/adam_onoff_cooling_fake_firmware/000077500000000000000000000000001475766476500252715ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_onoff_cooling_fake_firmware/data.json000066400000000000000000000054471475766476500271070ustar00rootroot00000000000000{ "0ca13e8176204ca7bf6f09de59f81c83": { "binary_sensors": { "cooling_enabled": true, "cooling_state": true, "dhw_state": true, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "eedadcb297564f1483faa509179aebed", "max_dhw_temperature": { "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 65.0 }, "maximum_boiler_temperature": { "lower_bound": 7.0, "resolution": 0.01, "setpoint": 35.0, "upper_bound": 50.0 }, "model": "Unknown", "name": "OnOff", "sensors": { "dhw_temperature": 63.5, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 13.5, "return_temperature": 24.9, "water_pressure": 2.0, "water_temperature": 24.5 }, "switches": { "dhw_cm_switch": true } }, "7d97fc3117784cfdafe347bcedcbbbcb": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.2.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "eedadcb297564f1483faa509179aebed", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": [ "heating", "off", "bleeding_cold", "bleeding_hot", "cooling" ], "select_gateway_mode": "full", "select_regulation_mode": "cooling", "sensors": { "outdoor_temperature": 13.4 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "ca79d23ae0094120b877558734cff85c": { "dev_class": "thermostat", "location": "fa5fa6b34f6b40a0972988b20e888ed4", "model": "ThermoTouch", "model_id": "143.1", "name": "Thermostaat WK", "sensors": { "setpoint": 21.5, "temperature": 22.5 }, "vendor": "Plugwise" }, "fa5fa6b34f6b40a0972988b20e888ed4": { "active_preset": "away", "available_schedules": [ "Opstaan weekdag", "Werkdag schema", "Weekend", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["no_frost", "vacation", "away", "home", "asleep"], "select_schedule": "Werkdag schema", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 22.5 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ca79d23ae0094120b877558734cff85c"], "secondary": [] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/adam_plus_anna/000077500000000000000000000000001475766476500215465ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_plus_anna/data.json000066400000000000000000000066761475766476500233710ustar00rootroot00000000000000{ "009490cc2f674ce6b576863fbb64f867": { "active_preset": "home", "available_schedules": ["Weekschema", "off"], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Living room", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "Weekschema", "sensors": { "electricity_consumed": 74.2, "electricity_produced": 0.0, "temperature": 20.5 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 20.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ee62cad889f94e8ca3d09021f03a660b"], "secondary": [] }, "vendor": "Plugwise" }, "2743216f626f43948deec1f7ab3b3d70": { "available": false, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "07d618f0bb80412687f065b8698ce3e7", "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 80.0, "upper_bound": 100.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 0.0, "water_temperature": 48.0 }, "switches": { "dhw_cm_switch": false } }, "aa6b0002df0a46e1b1eb94beb61eddfe": { "available": true, "dev_class": "hometheater_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "45d410adf8fd461e85cebf16d5ead542", "model": "Plug", "model_id": "160-01", "name": "MediaCenter", "sensors": { "electricity_consumed": 10.3, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "b128b4bbbd1f47e9bf4d756e8fb5ee94": { "binary_sensors": { "plugwise_notification": true }, "dev_class": "gateway", "firmware": "3.0.15", "hardware": "AME Smile 2.0 board", "location": "07d618f0bb80412687f065b8698ce3e7", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": { "6fb89e35caeb4b1cb275184895202d84": { "error": "There is no OpenTherm communication with the boiler." } }, "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 11.9 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "ee62cad889f94e8ca3d09021f03a660b": { "dev_class": "thermostat", "location": "009490cc2f674ce6b576863fbb64f867", "model": "ThermoTouch", "model_id": "143.1", "name": "Anna", "sensors": { "setpoint": 20.5, "temperature": 20.5 }, "vendor": "Plugwise" }, "f2be121e4a9345ac83c6e99ed89a98be": { "available": true, "dev_class": "computer_desktop_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "5ccb6c41a7d9403988d261ceee04239f", "name": "Work-PC", "sensors": { "electricity_consumed": 80.5, "electricity_consumed_interval": 7.03, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" } } python-plugwise-1.7.3/fixtures/adam_plus_anna_new/000077500000000000000000000000001475766476500224175ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_plus_anna_new/data.json000066400000000000000000000167331475766476500242350ustar00rootroot00000000000000{ "056ee145a816487eaa69243c3280f8bf": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": true, "heating_state": true }, "dev_class": "heater_central", "location": "bc93488efab249e5bc54fd7e175a6f91", "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 50.0, "upper_bound": 95.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 23.9, "water_temperature": 30.0 }, "switches": { "dhw_cm_switch": false } }, "10016900610d4c7481df78c89606ef22": { "available": true, "dev_class": "valve_actuator_plug", "location": "d9786723dbcf4f19b5c629a54629f9c7", "model_id": "TS0011", "name": "Aanvoer water afsluiter (nous lz3)", "switches": { "relay": false }, "vendor": "_TZ3000_abjodzas", "zigbee_mac_address": "A4C13862AF9917B1" }, "1772a4ea304041adb83f357b751341ff": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "f871b8c4d63549319221e294e4f88074", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Badkamer", "sensors": { "battery": 99, "setpoint": 18.0, "temperature": 17.6, "temperature_difference": -0.2, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C8FF5EE" }, "2568cc4b9c1e401495d4741a5f89bee1": { "available": true, "dev_class": "hometheater_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug MediaTV", "sensors": { "electricity_consumed": 14.8, "electricity_consumed_interval": 3.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CCFD" }, "29542b2b6a6a4169acecc15c72a599b8": { "available": true, "dev_class": "computer_desktop_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug Werkplek", "sensors": { "electricity_consumed": 91.3, "electricity_consumed_interval": 23.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CA9A" }, "67d73d0bd469422db25a618a5fb8eeb0": { "available": true, "dev_class": "heater_central_plug", "location": "b4f211175e124df59603412bafa77a34", "model": "Aqara Smart Plug", "model_id": "lumi.plug.maeu01", "name": "SmartPlug Floor 0", "sensors": { "electricity_consumed_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "LUMI", "zigbee_mac_address": "54EF4410002C97F2" }, "854f8a9b0e7e425db97f1f110e1ce4b3": { "available": true, "dev_class": "central_heating_pump_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug Vloerverwarming", "sensors": { "electricity_consumed": 43.8, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CB6F" }, "ad4838d7d35c4d6ea796ee12ae5aedf8": { "dev_class": "thermostat", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "ThermoTouch", "model_id": "143.1", "name": "Anna", "sensors": { "setpoint": 18.5, "temperature": 18.4 }, "vendor": "Plugwise" }, "da224107914542988a88561b4452b0f6": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.7.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "bc93488efab249e5bc54fd7e175a6f91", "mac_address": "012345679891", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"], "select_gateway_mode": "full", "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 9.19 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { "available": true, "binary_sensors": { "low_battery": true }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "f871b8c4d63549319221e294e4f88074", "model": "Lisa", "model_id": "158-01", "name": "Lisa Badkamer", "sensors": { "battery": 14, "setpoint": 18.0, "temperature": 16.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C869B61" }, "e8ef2a01ed3b4139a53bf749204fe6b4": { "dev_class": "switching", "members": [ "2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8" ], "model": "Switchgroup", "name": "Test", "switches": { "relay": true }, "vendor": "Plugwise" }, "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "auto", "control_state": "heating", "dev_class": "climate", "model": "ThermoZone", "name": "Living room", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Weekschema", "sensors": { "electricity_consumed": 149.9, "electricity_produced": 0.0, "temperature": 18.4 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 18.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ad4838d7d35c4d6ea796ee12ae5aedf8"], "secondary": [] }, "vendor": "Plugwise" }, "f871b8c4d63549319221e294e4f88074": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "auto", "control_state": "preheating", "dev_class": "climate", "model": "ThermoZone", "name": "Bathroom", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 16.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["e2f4322d57924fa090fbbc48b3a140dc"], "secondary": ["1772a4ea304041adb83f357b751341ff"] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/adam_plus_anna_new_regulation_off/000077500000000000000000000000001475766476500255025ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_plus_anna_new_regulation_off/data.json000066400000000000000000000167011475766476500273130ustar00rootroot00000000000000{ "056ee145a816487eaa69243c3280f8bf": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "bc93488efab249e5bc54fd7e175a6f91", "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 50.0, "upper_bound": 95.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 0.0, "water_temperature": 30.0 }, "switches": { "dhw_cm_switch": false } }, "10016900610d4c7481df78c89606ef22": { "available": true, "dev_class": "valve_actuator_plug", "location": "d9786723dbcf4f19b5c629a54629f9c7", "model_id": "TS0011", "name": "Aanvoer water afsluiter (nous lz3)", "switches": { "relay": false }, "vendor": "_TZ3000_abjodzas", "zigbee_mac_address": "A4C13862AF9917B1" }, "1772a4ea304041adb83f357b751341ff": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "f871b8c4d63549319221e294e4f88074", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Badkamer", "sensors": { "battery": 99, "setpoint": 18.0, "temperature": 21.6, "temperature_difference": -0.2, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C8FF5EE" }, "2568cc4b9c1e401495d4741a5f89bee1": { "available": true, "dev_class": "hometheater_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug MediaTV", "sensors": { "electricity_consumed": 14.8, "electricity_consumed_interval": 3.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CCFD" }, "29542b2b6a6a4169acecc15c72a599b8": { "available": true, "dev_class": "computer_desktop_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug Werkplek", "sensors": { "electricity_consumed": 91.3, "electricity_consumed_interval": 23.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CA9A" }, "67d73d0bd469422db25a618a5fb8eeb0": { "available": true, "dev_class": "heater_central_plug", "location": "b4f211175e124df59603412bafa77a34", "model": "Aqara Smart Plug", "model_id": "lumi.plug.maeu01", "name": "SmartPlug Floor 0", "sensors": { "electricity_consumed_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "LUMI", "zigbee_mac_address": "54EF4410002C97F2" }, "854f8a9b0e7e425db97f1f110e1ce4b3": { "available": true, "dev_class": "central_heating_pump_plug", "firmware": "2020-11-10T01:00:00+01:00", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "Plug", "model_id": "160-01", "name": "Plug Vloerverwarming", "sensors": { "electricity_consumed": 43.8, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D13CB6F" }, "ad4838d7d35c4d6ea796ee12ae5aedf8": { "dev_class": "thermostat", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "ThermoTouch", "model_id": "143.1", "name": "Anna", "sensors": { "setpoint": 18.5, "temperature": 22.4 }, "vendor": "Plugwise" }, "da224107914542988a88561b4452b0f6": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.7.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "bc93488efab249e5bc54fd7e175a6f91", "mac_address": "012345679891", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"], "select_gateway_mode": "full", "select_regulation_mode": "off", "sensors": { "outdoor_temperature": 9.19 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { "available": true, "binary_sensors": { "low_battery": true }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "f871b8c4d63549319221e294e4f88074", "model": "Lisa", "model_id": "158-01", "name": "Lisa Badkamer", "sensors": { "battery": 14, "setpoint": 18.0, "temperature": 21.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C869B61" }, "e8ef2a01ed3b4139a53bf749204fe6b4": { "dev_class": "switching", "members": [ "2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8" ], "model": "Switchgroup", "name": "Test", "switches": { "relay": true }, "vendor": "Plugwise" }, "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "off", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Living room", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "off", "sensors": { "electricity_consumed": 149.9, "electricity_produced": 0.0, "temperature": 22.4 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 18.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ad4838d7d35c4d6ea796ee12ae5aedf8"], "secondary": [] }, "vendor": "Plugwise" }, "f871b8c4d63549319221e294e4f88074": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "off", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bathroom", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 21.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 18.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["e2f4322d57924fa090fbbc48b3a140dc"], "secondary": ["1772a4ea304041adb83f357b751341ff"] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/adam_zone_per_device/000077500000000000000000000000001475766476500227265ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/adam_zone_per_device/data.json000066400000000000000000000370011475766476500245330ustar00rootroot00000000000000{ "02cf28bfec924855854c544690a609ef": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "c4d2bda6df8146caa2e5c2b5dc65660e", "model": "Plug", "model_id": "160-01", "name": "NVR", "sensors": { "electricity_consumed": 34.0, "electricity_consumed_interval": 8.65, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A15" }, "08963fec7c53423ca5680aa4cb502c63": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Badkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "Badkamer Schema", "sensors": { "temperature": 18.8 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 14.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["f1fee6043d3642a9b0a65297455f008e"], "secondary": ["680423ff840043738f42cc7f1ff97a36"] }, "vendor": "Plugwise" }, "12493538af164a409c6a1c79e38afe1c": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bios", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 16.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["df4a4a8169904cdb9c03d61a21f42140"], "secondary": ["a2c3583e0a6349358998b760cea82d2a"] }, "vendor": "Plugwise" }, "21f2b542c49845e6bb416884c55778d6": { "available": true, "dev_class": "game_console_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "4efbab4c8bb84fbab26c8decf670eb96", "model": "Plug", "model_id": "160-01", "name": "Playstation Smart Plug", "sensors": { "electricity_consumed": 80.1, "electricity_consumed_interval": 12.7, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "446ac08dd04d4eff8ac57489757b7314": { "active_preset": "no_frost", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Garage", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "off", "sensors": { "temperature": 15.6 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 5.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["e7693eb9582644e5b865dba8d4447cf1"], "secondary": [] }, "vendor": "Plugwise" }, "4a810418d5394b3f82727340b91ba740": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "0217e9743c174eef9d6e9f680d403ce2", "model": "Plug", "model_id": "160-01", "name": "USG Smart Plug", "sensors": { "electricity_consumed": 8.5, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A16" }, "675416a629f343c495449970e2ca37b5": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "2b1591ecf6344d4d93b03dece9747648", "model": "Plug", "model_id": "160-01", "name": "Ziggo Modem", "sensors": { "electricity_consumed": 12.2, "electricity_consumed_interval": 2.8, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "680423ff840043738f42cc7f1ff97a36": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Badkamer", "sensors": { "battery": 51, "setpoint": 14.0, "temperature": 19.1, "temperature_difference": -0.3, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A17" }, "6a3bf693d05e48e0b460c815a4fdd09d": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Lisa", "model_id": "158-01", "name": "Zone Thermostat Jessie", "sensors": { "battery": 37, "setpoint": 16.0, "temperature": 17.1 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "78d1126fc4c743db81b61c20e88342a7": { "available": true, "dev_class": "central_heating_pump_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Plug", "model_id": "160-01", "name": "CV Pomp", "sensors": { "electricity_consumed": 35.8, "electricity_consumed_interval": 5.85, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "82fa13f017d240daa0d0ea1775420f24": { "active_preset": "asleep", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Jessie", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "CV Jessie", "sensors": { "temperature": 17.1 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 16.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["6a3bf693d05e48e0b460c815a4fdd09d"], "secondary": ["d3da73bde12a47d5a6b8f9dad971f2ec"] }, "vendor": "Plugwise" }, "90986d591dcd426cae3ec3e8111ff730": { "binary_sensors": { "heating_state": true }, "dev_class": "heater_central", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "model": "Unknown", "name": "OnOff", "sensors": { "intended_boiler_temperature": 70.0, "modulation_level": 1, "water_temperature": 70.0 } }, "a28f588dc4a049a483fd03a30361ad3a": { "available": true, "dev_class": "settop_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Fibaro HC2", "sensors": { "electricity_consumed": 12.5, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Tom/Floor", "model_id": "106-03", "name": "Bios Cv Thermostatic Radiator ", "sensors": { "battery": 62, "setpoint": 13.0, "temperature": 17.1, "temperature_difference": -0.1, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "b310b72a0e354bfab43089919b9a88bf": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Tom/Floor", "model_id": "106-03", "name": "Floor kraan", "sensors": { "setpoint": 21.5, "temperature": 26.2, "temperature_difference": 3.7, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "b59bcebaf94b499ea7d46e4a66fb62d8": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa WK", "sensors": { "battery": 34, "setpoint": 21.5, "temperature": 21.1 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "c50f167537524366a5af7aa3942feb1e": { "active_preset": "home", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "heating", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "GF7 Woonkamer", "sensors": { "electricity_consumed": 35.8, "electricity_produced": 0.0, "temperature": 21.1 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["b59bcebaf94b499ea7d46e4a66fb62d8"], "secondary": ["b310b72a0e354bfab43089919b9a88bf"] }, "vendor": "Plugwise" }, "cd0ddb54ef694e11ac18ed1cbce5dbbd": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "e704bae65654496f9cade9c855decdfe", "model": "Plug", "model_id": "160-01", "name": "NAS", "sensors": { "electricity_consumed": 16.5, "electricity_consumed_interval": 0.29, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A14" }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Jessie", "sensors": { "battery": 62, "setpoint": 16.0, "temperature": 16.9, "temperature_difference": 0.1, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "df4a4a8169904cdb9c03d61a21f42140": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa Bios", "sensors": { "battery": 67, "setpoint": 13.0, "temperature": 16.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" }, "e7693eb9582644e5b865dba8d4447cf1": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "446ac08dd04d4eff8ac57489757b7314", "model": "Tom/Floor", "model_id": "106-03", "name": "CV Kraan Garage", "sensors": { "battery": 68, "setpoint": 5.5, "temperature": 15.6, "temperature_difference": 0.1, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, "f1fee6043d3642a9b0a65297455f008e": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Lisa", "model_id": "158-01", "name": "Zone Thermostat Badkamer", "sensors": { "battery": 92, "setpoint": 14.0, "temperature": 18.8 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "fe799307f1624099878210aa0b9f1475": { "binary_sensors": { "plugwise_notification": true }, "dev_class": "gateway", "firmware": "3.0.15", "hardware": "AME Smile 2.0 board", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." } }, "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 7.69 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" } } python-plugwise-1.7.3/fixtures/anna_elga_2/000077500000000000000000000000001475766476500207325ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_elga_2/data.json000066400000000000000000000045051475766476500225420ustar00rootroot00000000000000{ "573c152e7d4f4720878222bd75638f5b": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": false, "cooling_state": false, "dhw_state": false, "flame_state": true, "heating_state": true, "secondary_boiler_state": true }, "dev_class": "heater_central", "location": "d34dfe6ab90b410c98068e75de3eb631", "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "domestic_hot_water_setpoint": 60.0, "intended_boiler_temperature": 58.3, "modulation_level": 55, "outdoor_air_temperature": 6.0, "return_temperature": 35.5, "water_pressure": 0.5, "water_temperature": 42.6 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "ebd90df1ab334565b5895f37590ccff4": { "active_preset": "home", "available_schedules": ["Thermostat schedule", "off"], "climate_mode": "auto", "control_state": "heating", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "d3ce834534114348be628b61b26d9220", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "no_frost", "vacation", "home", "asleep"], "select_schedule": "Thermostat schedule", "sensors": { "cooling_activation_outdoor_temperature": 24.0, "cooling_deactivation_threshold": 2.0, "illuminance": 0.5, "setpoint_high": 30.0, "setpoint_low": 19.5, "temperature": 19.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 19.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "fb49af122f6e4b0f91267e1cf7666d6f": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.4.1", "hardware": "AME Smile 2.0 board", "location": "d34dfe6ab90b410c98068e75de3eb631", "mac_address": "C4930002FE76", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 6.38 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_elga_2_cooling/000077500000000000000000000000001475766476500224445ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_elga_2_cooling/data.json000066400000000000000000000047251475766476500242600ustar00rootroot00000000000000{ "573c152e7d4f4720878222bd75638f5b": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": true, "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "d34dfe6ab90b410c98068e75de3eb631", "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "domestic_hot_water_setpoint": 60.0, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 30.0, "return_temperature": 23.4, "water_pressure": 0.5, "water_temperature": 22.8 }, "switches": { "dhw_cm_switch": true }, "vendor": "Techneco" }, "ebd90df1ab334565b5895f37590ccff4": { "active_preset": "home", "available_schedules": ["Thermostat schedule", "off"], "climate_mode": "auto", "control_state": "cooling", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "d3ce834534114348be628b61b26d9220", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "no_frost", "vacation", "home", "asleep"], "select_schedule": "Thermostat schedule", "sensors": { "cooling_activation_outdoor_temperature": 26.0, "cooling_deactivation_threshold": 3.0, "illuminance": 0.5, "setpoint_high": 23.0, "setpoint_low": 4.0, "temperature": 24.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 23.0, "setpoint_low": 4.0, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "fb49af122f6e4b0f91267e1cf7666d6f": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.2.1", "hardware": "AME Smile 2.0 board", "location": "d34dfe6ab90b410c98068e75de3eb631", "mac_address": "C4930002FE76", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 31.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_elga_2_schedule_off/000077500000000000000000000000001475766476500234405ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_elga_2_schedule_off/data.json000066400000000000000000000047141475766476500252520ustar00rootroot00000000000000{ "573c152e7d4f4720878222bd75638f5b": { "available": true, "binary_sensors": { "compressor_state": false, "cooling_enabled": false, "cooling_state": false, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "d34dfe6ab90b410c98068e75de3eb631", "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "domestic_hot_water_setpoint": 60.0, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 13.0, "return_temperature": 23.4, "water_pressure": 0.5, "water_temperature": 22.8 }, "switches": { "dhw_cm_switch": true }, "vendor": "Techneco" }, "ebd90df1ab334565b5895f37590ccff4": { "active_preset": "home", "available_schedules": ["Thermostat schedule", "off"], "climate_mode": "heat_cool", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "d3ce834534114348be628b61b26d9220", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "no_frost", "vacation", "home", "asleep"], "select_schedule": "off", "sensors": { "cooling_activation_outdoor_temperature": 26.0, "cooling_deactivation_threshold": 3.0, "illuminance": 0.5, "setpoint_high": 30.0, "setpoint_low": 19.5, "temperature": 20.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 19.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "fb49af122f6e4b0f91267e1cf7666d6f": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.2.1", "hardware": "AME Smile 2.0 board", "location": "d34dfe6ab90b410c98068e75de3eb631", "mac_address": "C4930002FE76", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 13.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_elga_no_cooling/000077500000000000000000000000001475766476500227175ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_elga_no_cooling/data.json000066400000000000000000000047001475766476500245240ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 20.2 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": true, "dhw_state": false, "flame_state": false, "heating_state": true, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "dhw_temperature": 46.3, "intended_boiler_temperature": 35.0, "modulation_level": 52, "outdoor_air_temperature": 3.0, "return_temperature": 25.1, "water_pressure": 1.57, "water_temperature": 29.1 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "auto", "control_state": "heating", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "standaard", "sensors": { "cooling_activation_outdoor_temperature": 21.0, "cooling_deactivation_threshold": 4.0, "illuminance": 86.0, "setpoint": 20.5, "temperature": 19.3 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_heatpump_cooling/000077500000000000000000000000001475766476500231365ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_heatpump_cooling/data.json000066400000000000000000000047431475766476500247520ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 22.0 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": true, "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "dhw_temperature": 41.5, "domestic_hot_water_setpoint": 60.0, "intended_boiler_temperature": 0.0, "modulation_level": 40, "outdoor_air_temperature": 22.0, "return_temperature": 23.8, "water_pressure": 1.61, "water_temperature": 24.7 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "heat_cool", "control_state": "cooling", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "off", "sensors": { "cooling_activation_outdoor_temperature": 21.0, "cooling_deactivation_threshold": 6.0, "illuminance": 24.5, "setpoint_high": 22.0, "setpoint_low": 4.0, "temperature": 22.3 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 22.0, "setpoint_low": 4.0, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_heatpump_cooling_fake_firmware/000077500000000000000000000000001475766476500260205ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_heatpump_cooling_fake_firmware/data.json000066400000000000000000000047451475766476500276360ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.10.10", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 22.0 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": true, "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "dhw_temperature": 41.5, "domestic_hot_water_setpoint": 60.0, "intended_boiler_temperature": 0.0, "modulation_level": 100, "outdoor_air_temperature": 22.0, "return_temperature": 23.8, "water_pressure": 1.61, "water_temperature": 24.7 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "heat_cool", "control_state": "cooling", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "off", "sensors": { "cooling_activation_outdoor_temperature": 21.0, "cooling_deactivation_threshold": 6.0, "illuminance": 24.5, "setpoint_high": 22.0, "setpoint_low": 4.0, "temperature": 22.3 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 22.0, "setpoint_low": 4.0, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_heatpump_heating/000077500000000000000000000000001475766476500231235ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_heatpump_heating/data.json000066400000000000000000000051071475766476500247320ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 20.2 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": false, "cooling_state": false, "dhw_state": false, "flame_state": false, "heating_state": true, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "dhw_temperature": 46.3, "intended_boiler_temperature": 35.0, "modulation_level": 52, "outdoor_air_temperature": 3.0, "return_temperature": 25.1, "water_pressure": 1.57, "water_temperature": 29.1 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "auto", "control_state": "heating", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "standaard", "sensors": { "cooling_activation_outdoor_temperature": 21.0, "cooling_deactivation_threshold": 4.0, "illuminance": 86.0, "setpoint_high": 30.0, "setpoint_low": 20.5, "temperature": 19.3 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/anna_loria_cooling_active/000077500000000000000000000000001475766476500237545ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_loria_cooling_active/data.json000066400000000000000000000050231475766476500255600ustar00rootroot00000000000000{ "582dfbdace4d4aeb832923ce7d1ddda0": { "active_preset": "home", "available_schedules": ["Winter", "Test ", "off"], "climate_mode": "auto", "control_state": "cooling", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "15da035090b847e7a21f93e08c015ebc", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "vacation", "no_frost", "home", "asleep"], "select_schedule": "Winter", "sensors": { "illuminance": 45.0, "setpoint_high": 23.5, "setpoint_low": 4.0, "temperature": 24.1 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 23.5, "setpoint_low": 4.0, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "9ff0569b4984459fb243af64c0901894": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.3.8", "hardware": "AME Smile 2.0 board", "location": "674b657c138a41a291d315d7471deb06", "mac_address": "C493000278E2", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 15.5 }, "vendor": "Plugwise" }, "bfb5ee0a88e14e5f97bfa725a760cc49": { "available": true, "binary_sensors": { "cooling_enabled": true, "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "dhw_modes": ["off", "auto", "boost", "eco", "comfort"], "location": "674b657c138a41a291d315d7471deb06", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 40.0, "upper_bound": 45.0 }, "model": "Generic heater/cooler", "model_id": "173", "name": "OpenTherm", "select_dhw_mode": "auto", "sensors": { "dhw_temperature": 52.9, "intended_boiler_temperature": 0.0, "modulation_level": 100, "outdoor_air_temperature": 17.2, "return_temperature": 26.3, "water_temperature": 25.3 }, "switches": { "cooling_ena_switch": true, "dhw_cm_switch": true }, "vendor": "Atlantic" } } python-plugwise-1.7.3/fixtures/anna_loria_driessens/000077500000000000000000000000001475766476500227665ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_loria_driessens/data.json000066400000000000000000000051541475766476500245770ustar00rootroot00000000000000{ "5c118b1842e943c0a5b6ef88a60bb17a": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.4.1", "hardware": "AME Smile 2.0 board", "location": "82c15f65c9bf44c592d69e16139355e3", "mac_address": "D40FB2011556", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 6.81 }, "vendor": "Plugwise" }, "9fb768d699e44c7fb5cc50309dc4e7d4": { "active_preset": "home", "available_schedules": [ "Verwarmen@9-23u", "VAKANTIE (winter)", "VERWARMEN", "KOELEN", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "fa70e08550c94de3a34feb27ecf31421", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "asleep", "vacation", "away", "home"], "select_schedule": "Verwarmen@9-23u", "sensors": { "illuminance": 5.5, "setpoint_high": 30.0, "setpoint_low": 20.0, "temperature": 21.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 20.0, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "a449cbc334ae4a5bb7f89064984b2906": { "available": true, "binary_sensors": { "cooling_enabled": false, "cooling_state": false, "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "dhw_modes": ["comfort", "eco", "off", "boost", "auto"], "location": "82c15f65c9bf44c592d69e16139355e3", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 45.0, "upper_bound": 45.0 }, "model": "Generic heater/cooler", "model_id": "173", "name": "OpenTherm", "select_dhw_mode": "auto", "sensors": { "dhw_temperature": 49.5, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 7.5, "return_temperature": 23.0, "water_temperature": 23.3 }, "switches": { "cooling_ena_switch": false, "dhw_cm_switch": true }, "vendor": "Atlantic" } } python-plugwise-1.7.3/fixtures/anna_loria_heating_idle/000077500000000000000000000000001475766476500234035ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_loria_heating_idle/data.json000066400000000000000000000050251475766476500252110ustar00rootroot00000000000000{ "582dfbdace4d4aeb832923ce7d1ddda0": { "active_preset": "home", "available_schedules": ["Winter", "Test ", "off"], "climate_mode": "auto", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "15da035090b847e7a21f93e08c015ebc", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "vacation", "no_frost", "home", "asleep"], "select_schedule": "Winter", "sensors": { "illuminance": 45.0, "setpoint_high": 30.0, "setpoint_low": 20.5, "temperature": 22.1 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "9ff0569b4984459fb243af64c0901894": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.3.8", "hardware": "AME Smile 2.0 board", "location": "674b657c138a41a291d315d7471deb06", "mac_address": "C493000278E2", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 15.5 }, "vendor": "Plugwise" }, "bfb5ee0a88e14e5f97bfa725a760cc49": { "available": true, "binary_sensors": { "cooling_enabled": false, "cooling_state": false, "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "dhw_modes": ["off", "auto", "boost", "eco", "comfort"], "location": "674b657c138a41a291d315d7471deb06", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 40.0, "upper_bound": 45.0 }, "model": "Generic heater/cooler", "model_id": "173", "name": "OpenTherm", "select_dhw_mode": "auto", "sensors": { "dhw_temperature": 52.9, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "outdoor_air_temperature": 17.2, "return_temperature": 26.3, "water_temperature": 25.3 }, "switches": { "cooling_ena_switch": false, "dhw_cm_switch": true }, "vendor": "Atlantic" } } python-plugwise-1.7.3/fixtures/anna_v4/000077500000000000000000000000001475766476500201325ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_v4/data.json000066400000000000000000000044021475766476500217360ustar00rootroot00000000000000{ "01b85360fdd243d0aaad4d6ac2a5ba7e": { "active_preset": "home", "available_schedules": ["Standaard", "Thuiswerken", "off"], "climate_mode": "heat", "control_state": "heating", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "eb5309212bf5407bb143e5bfa3b18aee", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["vacation", "no_frost", "away", "asleep", "home"], "select_schedule": "off", "sensors": { "illuminance": 60.0, "setpoint": 20.5, "temperature": 20.6 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "0466eae8520144c78afb29628384edeb": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 7.44 }, "vendor": "Plugwise" }, "cd0e6156b1f04d5f952349ffbe397481": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": true }, "dev_class": "heater_central", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "max_dhw_temperature": { "lower_bound": 30.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 70.0, "upper_bound": 100.0 }, "model": "Generic heater", "model_id": "2.32", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, "water_pressure": 2.2, "water_temperature": 45.0 }, "switches": { "dhw_cm_switch": false }, "vendor": "Bosch Thermotechniek B.V." } } python-plugwise-1.7.3/fixtures/anna_v4_dhw/000077500000000000000000000000001475766476500207745ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_v4_dhw/data.json000066400000000000000000000043761475766476500226120ustar00rootroot00000000000000{ "01b85360fdd243d0aaad4d6ac2a5ba7e": { "active_preset": "home", "available_schedules": ["Standaard", "Thuiswerken", "off"], "climate_mode": "heat", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "eb5309212bf5407bb143e5bfa3b18aee", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["vacation", "no_frost", "away", "asleep", "home"], "select_schedule": "off", "sensors": { "illuminance": 60.0, "setpoint": 20.5, "temperature": 20.6 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "0466eae8520144c78afb29628384edeb": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 7.44 }, "vendor": "Plugwise" }, "cd0e6156b1f04d5f952349ffbe397481": { "available": true, "binary_sensors": { "dhw_state": true, "flame_state": true, "heating_state": false }, "dev_class": "heater_central", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "max_dhw_temperature": { "lower_bound": 30.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 70.0, "upper_bound": 100.0 }, "model": "Generic heater", "model_id": "2.32", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, "water_pressure": 2.2, "water_temperature": 45.0 }, "switches": { "dhw_cm_switch": false }, "vendor": "Bosch Thermotechniek B.V." } } python-plugwise-1.7.3/fixtures/anna_v4_no_tag/000077500000000000000000000000001475766476500214615ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_v4_no_tag/data.json000066400000000000000000000044121475766476500232660ustar00rootroot00000000000000{ "01b85360fdd243d0aaad4d6ac2a5ba7e": { "active_preset": "home", "available_schedules": ["Standaard", "Thuiswerken", "off"], "climate_mode": "auto", "control_state": "heating", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "eb5309212bf5407bb143e5bfa3b18aee", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["vacation", "no_frost", "away", "asleep", "home"], "select_schedule": "Thuiswerken", "sensors": { "illuminance": 60.0, "setpoint": 20.5, "temperature": 20.6 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "0466eae8520144c78afb29628384edeb": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 7.44 }, "vendor": "Plugwise" }, "cd0e6156b1f04d5f952349ffbe397481": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": true }, "dev_class": "heater_central", "location": "94c107dc6ac84ed98e9f68c0dd06bf71", "max_dhw_temperature": { "lower_bound": 30.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 70.0, "upper_bound": 100.0 }, "model": "Generic heater", "model_id": "2.32", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 39.9, "modulation_level": 0.0, "return_temperature": 32.0, "water_pressure": 2.2, "water_temperature": 45.0 }, "switches": { "dhw_cm_switch": false }, "vendor": "Bosch Thermotechniek B.V." } } python-plugwise-1.7.3/fixtures/anna_without_boiler_fw441/000077500000000000000000000000001475766476500235655ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/anna_without_boiler_fw441/data.json000066400000000000000000000031141475766476500253700ustar00rootroot00000000000000{ "7ffbb3ab4b6c4ab2915d7510f7bf8fe9": { "active_preset": "home", "available_schedules": ["Test", "Normaal", "off"], "climate_mode": "auto", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c34c6864216446528e95d88985e714cc", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "asleep", "away", "vacation", "home"], "select_schedule": "Normaal", "sensors": { "illuminance": 0.25, "setpoint": 19.0, "temperature": 19.1 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 19.0, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "a270735e4ccd45239424badc0578a2b1": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.4.1", "hardware": "AME Smile 2.0 board", "location": "0f4f2ada20734a339fe353348fe87b96", "mac_address": "D40FB200FA1C", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 8.31 }, "vendor": "Plugwise" }, "c46b4794d28149699eacf053deedd003": { "binary_sensors": { "heating_state": false }, "dev_class": "heater_central", "location": "0f4f2ada20734a339fe353348fe87b96", "model": "Unknown", "name": "OnOff" } } python-plugwise-1.7.3/fixtures/legacy_anna/000077500000000000000000000000001475766476500210455ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/legacy_anna/data.json000066400000000000000000000031301475766476500226460ustar00rootroot00000000000000{ "0000aaaa0000aaaa0000aaaa0000aa00": { "dev_class": "gateway", "firmware": "1.8.22", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "mac_address": "01:23:45:67:89:AB", "model": "Gateway", "name": "Smile Anna", "vendor": "Plugwise" }, "04e4cbfe7f4340f090f85ec3b9e6a950": { "binary_sensors": { "flame_state": true, "heating_state": true }, "dev_class": "heater_central", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "maximum_boiler_temperature": { "lower_bound": 50.0, "resolution": 1.0, "setpoint": 50.0, "upper_bound": 90.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "dhw_temperature": 51.2, "intended_boiler_temperature": 17.0, "modulation_level": 0.0, "return_temperature": 21.7, "water_pressure": 1.2, "water_temperature": 23.6 }, "vendor": "Bosch Thermotechniek B.V." }, "0d266432d64443e283b5d708ae98b455": { "active_preset": "home", "climate_mode": "heat", "control_state": "heating", "dev_class": "thermostat", "firmware": "2017-03-13T11:54:58+01:00", "hardware": "6539-1301-500", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["away", "vacation", "asleep", "home", "no_frost"], "sensors": { "illuminance": 150.8, "setpoint": 20.5, "temperature": 20.4 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/legacy_anna_2/000077500000000000000000000000001475766476500212665ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/legacy_anna_2/data.json000066400000000000000000000032721475766476500230760ustar00rootroot00000000000000{ "9e7377867dc24e51b8098a5ba02bd89d": { "active_preset": null, "available_schedules": ["Thermostat schedule", "off"], "climate_mode": "heat", "control_state": "idle", "dev_class": "thermostat", "firmware": "2017-03-13T11:54:58+01:00", "hardware": "6539-1301-5002", "location": "be81e3f8275b4129852c4d8d550ae2eb", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["vacation", "away", "no_frost", "home", "asleep"], "select_schedule": "off", "sensors": { "illuminance": 19.5, "setpoint": 15.0, "temperature": 21.4 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint": 15.0, "upper_bound": 30.0 }, "vendor": "Plugwise" }, "be81e3f8275b4129852c4d8d550ae2eb": { "dev_class": "gateway", "firmware": "1.8.22", "location": "be81e3f8275b4129852c4d8d550ae2eb", "mac_address": "01:23:45:67:89:AB", "model": "Gateway", "name": "Smile Anna", "sensors": { "outdoor_temperature": 21.0 }, "vendor": "Plugwise" }, "ea5d8a7177e541b0a4b52da815166de4": { "binary_sensors": { "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "be81e3f8275b4129852c4d8d550ae2eb", "maximum_boiler_temperature": { "lower_bound": 50.0, "resolution": 1.0, "setpoint": 70.0, "upper_bound": 90.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "dhw_temperature": 0.0, "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "return_temperature": 0.0, "water_pressure": 1.7, "water_temperature": 54.0 } } } python-plugwise-1.7.3/fixtures/m_adam_cooling/000077500000000000000000000000001475766476500215345ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_adam_cooling/data.json000066400000000000000000000120021475766476500233330ustar00rootroot00000000000000{ "056ee145a816487eaa69243c3280f8bf": { "available": true, "binary_sensors": { "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "bc93488efab249e5bc54fd7e175a6f91", "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 50.0, "upper_bound": 95.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 17.5, "water_temperature": 19.0 }, "switches": { "dhw_cm_switch": false } }, "1772a4ea304041adb83f357b751341ff": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "f871b8c4d63549319221e294e4f88074", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Badkamer", "sensors": { "battery": 99, "setpoint": 18.0, "temperature": 21.6, "temperature_difference": -0.2, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C8FF5EE" }, "ad4838d7d35c4d6ea796ee12ae5aedf8": { "available": true, "dev_class": "thermostat", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "ThermoTouch", "model_id": "143.1", "name": "Anna", "sensors": { "setpoint": 23.5, "temperature": 25.8 }, "vendor": "Plugwise" }, "da224107914542988a88561b4452b0f6": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.7.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "bc93488efab249e5bc54fd7e175a6f91", "mac_address": "012345679891", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": [ "bleeding_hot", "bleeding_cold", "off", "heating", "cooling" ], "select_gateway_mode": "full", "select_regulation_mode": "cooling", "sensors": { "outdoor_temperature": 29.65 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { "available": true, "binary_sensors": { "low_battery": true }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "f871b8c4d63549319221e294e4f88074", "model": "Lisa", "model_id": "158-01", "name": "Lisa Badkamer", "sensors": { "battery": 14, "setpoint": 23.5, "temperature": 23.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C869B61" }, "e8ef2a01ed3b4139a53bf749204fe6b4": { "dev_class": "switching", "members": [ "2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8" ], "model": "Switchgroup", "name": "Test", "switches": { "relay": true }, "vendor": "Plugwise" }, "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "cool", "control_state": "cooling", "dev_class": "climate", "model": "ThermoZone", "name": "Living room", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "off", "sensors": { "electricity_consumed": 149.9, "electricity_produced": 0.0, "temperature": 25.8 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 23.5, "upper_bound": 35.0 }, "thermostats": { "primary": ["ad4838d7d35c4d6ea796ee12ae5aedf8"], "secondary": [] }, "vendor": "Plugwise" }, "f871b8c4d63549319221e294e4f88074": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "auto", "control_state": "cooling", "dev_class": "climate", "model": "ThermoZone", "name": "Bathroom", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 23.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 25.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["e2f4322d57924fa090fbbc48b3a140dc"], "secondary": ["1772a4ea304041adb83f357b751341ff"] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/m_adam_heating/000077500000000000000000000000001475766476500215215ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_adam_heating/data.json000066400000000000000000000121001475766476500233170ustar00rootroot00000000000000{ "056ee145a816487eaa69243c3280f8bf": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": true }, "dev_class": "heater_central", "location": "bc93488efab249e5bc54fd7e175a6f91", "max_dhw_temperature": { "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 25.0, "resolution": 0.01, "setpoint": 50.0, "upper_bound": 95.0 }, "model": "Generic heater", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 38.1, "water_temperature": 37.0 }, "switches": { "dhw_cm_switch": false } }, "1772a4ea304041adb83f357b751341ff": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "f871b8c4d63549319221e294e4f88074", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Badkamer", "sensors": { "battery": 99, "setpoint": 18.0, "temperature": 18.6, "temperature_difference": -0.2, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C8FF5EE" }, "ad4838d7d35c4d6ea796ee12ae5aedf8": { "available": true, "dev_class": "thermostat", "location": "f2bf9048bef64cc5b6d5110154e33c81", "model": "ThermoTouch", "model_id": "143.1", "name": "Anna", "sensors": { "setpoint": 20.0, "temperature": 19.1 }, "vendor": "Plugwise" }, "da224107914542988a88561b4452b0f6": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.7.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "bc93488efab249e5bc54fd7e175a6f91", "mac_address": "012345679891", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"], "select_gateway_mode": "full", "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": -1.25 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000D5A168D" }, "e2f4322d57924fa090fbbc48b3a140dc": { "available": true, "binary_sensors": { "low_battery": true }, "dev_class": "zone_thermostat", "firmware": "2016-10-10T02:00:00+02:00", "hardware": "255", "location": "f871b8c4d63549319221e294e4f88074", "model": "Lisa", "model_id": "158-01", "name": "Lisa Badkamer", "sensors": { "battery": 14, "setpoint": 15.0, "temperature": 17.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "000D6F000C869B61" }, "e8ef2a01ed3b4139a53bf749204fe6b4": { "dev_class": "switching", "members": [ "2568cc4b9c1e401495d4741a5f89bee1", "29542b2b6a6a4169acecc15c72a599b8" ], "model": "Switchgroup", "name": "Test", "switches": { "relay": true }, "vendor": "Plugwise" }, "f2bf9048bef64cc5b6d5110154e33c81": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "heat", "control_state": "preheating", "dev_class": "climate", "model": "ThermoZone", "name": "Living room", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "off", "sensors": { "electricity_consumed": 149.9, "electricity_produced": 0.0, "temperature": 19.1 }, "thermostat": { "lower_bound": 1.0, "resolution": 0.01, "setpoint": 20.0, "upper_bound": 35.0 }, "thermostats": { "primary": ["ad4838d7d35c4d6ea796ee12ae5aedf8"], "secondary": [] }, "vendor": "Plugwise" }, "f871b8c4d63549319221e294e4f88074": { "active_preset": "home", "available_schedules": [ "Badkamer", "Test", "Vakantie", "Weekschema", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bathroom", "preset_modes": ["no_frost", "asleep", "vacation", "home", "away"], "select_schedule": "Badkamer", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 17.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 15.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["e2f4322d57924fa090fbbc48b3a140dc"], "secondary": ["1772a4ea304041adb83f357b751341ff"] }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/m_adam_jip/000077500000000000000000000000001475766476500206645ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_adam_jip/data.json000066400000000000000000000232051475766476500224720ustar00rootroot00000000000000{ "06aecb3d00354375924f50c47af36bd2": { "active_preset": "no_frost", "climate_mode": "off", "dev_class": "climate", "model": "ThermoZone", "name": "Slaapkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 24.2 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["1346fbd8498d4dbcab7e18d51b771f3d"], "secondary": ["356b65335e274d769c338223e7af9c33"] }, "vendor": "Plugwise" }, "13228dab8ce04617af318a2888b3c548": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 27.4 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.01, "setpoint": 9.0, "upper_bound": 30.0 }, "thermostats": { "primary": ["f61f1a2535f54f52ad006a3d18e459ca"], "secondary": ["833de10f269c4deab58fb9df69901b4e"] }, "vendor": "Plugwise" }, "1346fbd8498d4dbcab7e18d51b771f3d": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "06aecb3d00354375924f50c47af36bd2", "model": "Lisa", "model_id": "158-01", "name": "Slaapkamer", "sensors": { "battery": 92, "setpoint": 13.0, "temperature": 24.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "1da4d325838e4ad8aac12177214505c9": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "d58fec52899f4f1c92e4f8fad6d8c48c", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Logeerkamer", "sensors": { "setpoint": 13.0, "temperature": 28.8, "temperature_difference": 2.0, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "356b65335e274d769c338223e7af9c33": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "06aecb3d00354375924f50c47af36bd2", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Slaapkamer", "sensors": { "setpoint": 13.0, "temperature": 24.2, "temperature_difference": 1.7, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "457ce8414de24596a2d5e7dbc9c7682f": { "available": true, "dev_class": "zz_misc_plug", "location": "9e4433a9d69f40b3aefd15e74395eaec", "model": "Aqara Smart Plug", "model_id": "lumi.plug.maeu01", "name": "Plug", "sensors": { "electricity_consumed_interval": 0.0 }, "switches": { "lock": true, "relay": false }, "vendor": "LUMI", "zigbee_mac_address": "ABCD012345670A06" }, "6f3e9d7084214c21b9dfa46f6eeb8700": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "d27aede973b54be484f6842d1b2802ad", "model": "Lisa", "model_id": "158-01", "name": "Kinderkamer", "sensors": { "battery": 79, "setpoint": 13.0, "temperature": 30.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "833de10f269c4deab58fb9df69901b4e": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "13228dab8ce04617af318a2888b3c548", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Woonkamer", "sensors": { "setpoint": 9.0, "temperature": 24.0, "temperature_difference": 1.8, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "a6abc6a129ee499c88a4d420cc413b47": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "d58fec52899f4f1c92e4f8fad6d8c48c", "model": "Lisa", "model_id": "158-01", "name": "Logeerkamer", "sensors": { "battery": 80, "setpoint": 13.0, "temperature": 30.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "b5c2386c6f6342669e50fe49dd05b188": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "3.2.8", "gateway_modes": ["away", "full", "vacation"], "hardware": "AME Smile 2.0 board", "location": "9e4433a9d69f40b3aefd15e74395eaec", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": {}, "regulation_modes": ["heating", "off", "bleeding_cold", "bleeding_hot"], "select_gateway_mode": "full", "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 24.9 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "d27aede973b54be484f6842d1b2802ad": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Kinderkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 30.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["6f3e9d7084214c21b9dfa46f6eeb8700"], "secondary": ["d4496250d0e942cfa7aea3476e9070d5"] }, "vendor": "Plugwise" }, "d4496250d0e942cfa7aea3476e9070d5": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2020-11-04T01:00:00+01:00", "hardware": "1", "location": "d27aede973b54be484f6842d1b2802ad", "model": "Tom/Floor", "model_id": "106-03", "name": "Tom Kinderkamer", "sensors": { "setpoint": 13.0, "temperature": 28.7, "temperature_difference": 1.9, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.1, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "d58fec52899f4f1c92e4f8fad6d8c48c": { "active_preset": "home", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Logeerkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 30.0 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 99.9 }, "thermostats": { "primary": ["a6abc6a129ee499c88a4d420cc413b47"], "secondary": ["1da4d325838e4ad8aac12177214505c9"] }, "vendor": "Plugwise" }, "e4684553153b44afbef2200885f379dc": { "available": true, "binary_sensors": { "dhw_state": false, "flame_state": false, "heating_state": false }, "dev_class": "heater_central", "location": "9e4433a9d69f40b3aefd15e74395eaec", "max_dhw_temperature": { "lower_bound": 40.0, "resolution": 0.01, "setpoint": 60.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 20.0, "resolution": 0.01, "setpoint": 90.0, "upper_bound": 90.0 }, "model": "Generic heater", "model_id": "10.20", "name": "OpenTherm", "sensors": { "intended_boiler_temperature": 0.0, "modulation_level": 0.0, "return_temperature": 37.1, "water_pressure": 1.4, "water_temperature": 37.3 }, "switches": { "dhw_cm_switch": false }, "vendor": "Remeha B.V." }, "f61f1a2535f54f52ad006a3d18e459ca": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermometer", "firmware": "2020-09-01T02:00:00+02:00", "hardware": "1", "location": "13228dab8ce04617af318a2888b3c548", "model": "Jip", "model_id": "168-01", "name": "Woonkamer", "sensors": { "battery": 100, "humidity": 56.2, "setpoint": 9.0, "temperature": 27.4 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" } } python-plugwise-1.7.3/fixtures/m_adam_multiple_devices_per_zone/000077500000000000000000000000001475766476500253405ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_adam_multiple_devices_per_zone/data.json000066400000000000000000000365511475766476500271560ustar00rootroot00000000000000{ "02cf28bfec924855854c544690a609ef": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "NVR", "sensors": { "electricity_consumed": 34.0, "electricity_consumed_interval": 9.15, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A15" }, "08963fec7c53423ca5680aa4cb502c63": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Badkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "Badkamer Schema", "sensors": { "temperature": 18.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 14.0, "upper_bound": 100.0 }, "thermostats": { "primary": [ "f1fee6043d3642a9b0a65297455f008e", "680423ff840043738f42cc7f1ff97a36" ], "secondary": [] }, "vendor": "Plugwise" }, "12493538af164a409c6a1c79e38afe1c": { "active_preset": "away", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Bios", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "off", "sensors": { "electricity_consumed": 0.0, "electricity_produced": 0.0, "temperature": 16.5 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 13.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["df4a4a8169904cdb9c03d61a21f42140"], "secondary": ["a2c3583e0a6349358998b760cea82d2a"] }, "vendor": "Plugwise" }, "21f2b542c49845e6bb416884c55778d6": { "available": true, "dev_class": "game_console_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Playstation Smart Plug", "sensors": { "electricity_consumed": 84.1, "electricity_consumed_interval": 8.6, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "446ac08dd04d4eff8ac57489757b7314": { "active_preset": "no_frost", "climate_mode": "heat", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Garage", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "sensors": { "temperature": 15.6 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 5.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["e7693eb9582644e5b865dba8d4447cf1"], "secondary": [] }, "vendor": "Plugwise" }, "4a810418d5394b3f82727340b91ba740": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "USG Smart Plug", "sensors": { "electricity_consumed": 8.5, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A16" }, "675416a629f343c495449970e2ca37b5": { "available": true, "dev_class": "router_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Ziggo Modem", "sensors": { "electricity_consumed": 12.2, "electricity_consumed_interval": 2.97, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "680423ff840043738f42cc7f1ff97a36": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Badkamer 1", "sensors": { "battery": 51, "setpoint": 14.0, "temperature": 19.1, "temperature_difference": -0.4, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A17" }, "6a3bf693d05e48e0b460c815a4fdd09d": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Lisa", "model_id": "158-01", "name": "Zone Thermostat Jessie", "sensors": { "battery": 37, "setpoint": 15.0, "temperature": 17.2 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "78d1126fc4c743db81b61c20e88342a7": { "available": true, "dev_class": "central_heating_pump_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Plug", "model_id": "160-01", "name": "CV Pomp", "sensors": { "electricity_consumed": 35.6, "electricity_consumed_interval": 7.37, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "82fa13f017d240daa0d0ea1775420f24": { "active_preset": "asleep", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "idle", "dev_class": "climate", "model": "ThermoZone", "name": "Jessie", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "CV Jessie", "sensors": { "temperature": 17.2 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 15.0, "upper_bound": 100.0 }, "thermostats": { "primary": ["6a3bf693d05e48e0b460c815a4fdd09d"], "secondary": ["d3da73bde12a47d5a6b8f9dad971f2ec"] }, "vendor": "Plugwise" }, "90986d591dcd426cae3ec3e8111ff730": { "binary_sensors": { "heating_state": true }, "dev_class": "heater_central", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "model": "Unknown", "name": "OnOff", "sensors": { "intended_boiler_temperature": 70.0, "modulation_level": 1, "water_temperature": 70.0 } }, "a28f588dc4a049a483fd03a30361ad3a": { "available": true, "dev_class": "settop_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "Fibaro HC2", "sensors": { "electricity_consumed": 12.5, "electricity_consumed_interval": 3.8, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "a2c3583e0a6349358998b760cea82d2a": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Tom/Floor", "model_id": "106-03", "name": "Bios Cv Thermostatic Radiator ", "sensors": { "battery": 62, "setpoint": 13.0, "temperature": 17.2, "temperature_difference": -0.2, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "b310b72a0e354bfab43089919b9a88bf": { "available": true, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Tom/Floor", "model_id": "106-03", "name": "Floor kraan", "sensors": { "setpoint": 21.5, "temperature": 26.0, "temperature_difference": 3.5, "valve_position": 100 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "b59bcebaf94b499ea7d46e4a66fb62d8": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-08-02T02:00:00+02:00", "hardware": "255", "location": "c50f167537524366a5af7aa3942feb1e", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa WK", "sensors": { "battery": 34, "setpoint": 21.5, "temperature": 20.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "c50f167537524366a5af7aa3942feb1e": { "active_preset": "home", "available_schedules": [ "CV Roan", "Bios Schema met Film Avond", "GF7 Woonkamer", "Badkamer Schema", "CV Jessie", "off" ], "climate_mode": "auto", "control_state": "heating", "dev_class": "climate", "model": "ThermoZone", "name": "Woonkamer", "preset_modes": ["home", "asleep", "away", "vacation", "no_frost"], "select_schedule": "GF7 Woonkamer", "sensors": { "electricity_consumed": 35.6, "electricity_produced": 0.0, "temperature": 20.9 }, "thermostat": { "lower_bound": 0.0, "resolution": 0.01, "setpoint": 21.5, "upper_bound": 100.0 }, "thermostats": { "primary": ["b59bcebaf94b499ea7d46e4a66fb62d8"], "secondary": ["b310b72a0e354bfab43089919b9a88bf"] }, "vendor": "Plugwise" }, "cd0ddb54ef694e11ac18ed1cbce5dbbd": { "available": true, "dev_class": "vcr_plug", "firmware": "2019-06-21T02:00:00+02:00", "location": "cd143c07248f491493cea0533bc3d669", "model": "Plug", "model_id": "160-01", "name": "NAS", "sensors": { "electricity_consumed": 16.5, "electricity_consumed_interval": 0.5, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A14" }, "d3da73bde12a47d5a6b8f9dad971f2ec": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "82fa13f017d240daa0d0ea1775420f24", "model": "Tom/Floor", "model_id": "106-03", "name": "Thermostatic Radiator Jessie", "sensors": { "battery": 62, "setpoint": 15.0, "temperature": 17.1, "temperature_difference": 0.1, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "df4a4a8169904cdb9c03d61a21f42140": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "zone_thermostat", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "12493538af164a409c6a1c79e38afe1c", "model": "Lisa", "model_id": "158-01", "name": "Zone Lisa Bios", "sensors": { "battery": 67, "setpoint": 13.0, "temperature": 16.5 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" }, "e7693eb9582644e5b865dba8d4447cf1": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2019-03-27T01:00:00+01:00", "hardware": "1", "location": "446ac08dd04d4eff8ac57489757b7314", "model": "Tom/Floor", "model_id": "106-03", "name": "CV Kraan Garage", "sensors": { "battery": 68, "setpoint": 5.5, "temperature": 15.6, "temperature_difference": 0.0, "valve_position": 0.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, "f1fee6043d3642a9b0a65297455f008e": { "available": true, "binary_sensors": { "low_battery": false }, "dev_class": "thermostatic_radiator_valve", "firmware": "2016-10-27T02:00:00+02:00", "hardware": "255", "location": "08963fec7c53423ca5680aa4cb502c63", "model": "Lisa", "model_id": "158-01", "name": "Thermostatic Radiator Badkamer 2", "sensors": { "battery": 92, "setpoint": 14.0, "temperature": 18.9 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": 0.0, "upper_bound": 2.0 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "fe799307f1624099878210aa0b9f1475": { "binary_sensors": { "plugwise_notification": true }, "dev_class": "gateway", "firmware": "3.0.15", "hardware": "AME Smile 2.0 board", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_open_therm", "name": "Adam", "notifications": { "af82e4ccf9c548528166d38e560662a4": { "warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device." } }, "select_regulation_mode": "heating", "sensors": { "outdoor_temperature": 7.81 }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" } } python-plugwise-1.7.3/fixtures/m_anna_heatpump_cooling/000077500000000000000000000000001475766476500234525ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_anna_heatpump_cooling/data.json000066400000000000000000000051061475766476500252600ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 28.2 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": true, "cooling_enabled": true, "cooling_state": true, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "dhw_temperature": 41.5, "intended_boiler_temperature": 0.0, "modulation_level": 40, "outdoor_air_temperature": 28.0, "return_temperature": 23.8, "water_pressure": 1.57, "water_temperature": 22.7 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "auto", "control_state": "cooling", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "standaard", "sensors": { "cooling_activation_outdoor_temperature": 21.0, "cooling_deactivation_threshold": 4.0, "illuminance": 86.0, "setpoint_high": 30.0, "setpoint_low": 20.5, "temperature": 26.3 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/m_anna_heatpump_idle/000077500000000000000000000000001475766476500227355ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/m_anna_heatpump_idle/data.json000066400000000000000000000051051475766476500245420ustar00rootroot00000000000000{ "015ae9ea3f964e668e490fa39da3870b": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.0.15", "hardware": "AME Smile 2.0 board", "location": "a57efe5f145f498c9be62a9b63626fbf", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile_thermo", "name": "Smile Anna", "notifications": {}, "sensors": { "outdoor_temperature": 28.2 }, "vendor": "Plugwise" }, "1cbf783bb11e4a7c8a6843dee3a86927": { "available": true, "binary_sensors": { "compressor_state": false, "cooling_enabled": true, "cooling_state": false, "dhw_state": false, "flame_state": false, "heating_state": false, "secondary_boiler_state": false }, "dev_class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf", "max_dhw_temperature": { "lower_bound": 35.0, "resolution": 0.01, "setpoint": 53.0, "upper_bound": 60.0 }, "maximum_boiler_temperature": { "lower_bound": 0.0, "resolution": 1.0, "setpoint": 60.0, "upper_bound": 100.0 }, "model": "Generic heater/cooler", "name": "OpenTherm", "sensors": { "dhw_temperature": 46.3, "intended_boiler_temperature": 18.0, "modulation_level": 0, "outdoor_air_temperature": 28.2, "return_temperature": 22.0, "water_pressure": 1.57, "water_temperature": 19.1 }, "switches": { "dhw_cm_switch": false }, "vendor": "Techneco" }, "3cb70739631c4d17a86b8b12e8a5161b": { "active_preset": "home", "available_schedules": ["standaard", "off"], "climate_mode": "auto", "control_state": "idle", "dev_class": "thermostat", "firmware": "2018-02-08T11:15:53+01:00", "hardware": "6539-1301-5002", "location": "c784ee9fdab44e1395b8dee7d7a497d5", "model": "ThermoTouch", "name": "Anna", "preset_modes": ["no_frost", "home", "away", "asleep", "vacation"], "select_schedule": "standaard", "sensors": { "cooling_activation_outdoor_temperature": 25.0, "cooling_deactivation_threshold": 4.0, "illuminance": 86.0, "setpoint_high": 30.0, "setpoint_low": 20.5, "temperature": 23.0 }, "temperature_offset": { "lower_bound": -2.0, "resolution": 0.1, "setpoint": -0.5, "upper_bound": 2.0 }, "thermostat": { "lower_bound": 4.0, "resolution": 0.1, "setpoint_high": 30.0, "setpoint_low": 20.5, "upper_bound": 30.0 }, "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/p1v4_442_single/000077500000000000000000000000001475766476500213305ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/p1v4_442_single/data.json000066400000000000000000000027241475766476500231410ustar00rootroot00000000000000{ "a455b61e52394b2db5081ce025a430f3": { "binary_sensors": { "plugwise_notification": false }, "dev_class": "gateway", "firmware": "4.4.2", "hardware": "AME Smile 2.0 board", "location": "a455b61e52394b2db5081ce025a430f3", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile", "name": "Smile P1", "notifications": {}, "vendor": "Plugwise" }, "ba4de7613517478da82dd9b6abea36af": { "available": true, "dev_class": "smartmeter", "location": "a455b61e52394b2db5081ce025a430f3", "model": "KFM5KAIFA-METER", "name": "P1", "sensors": { "electricity_consumed_off_peak_cumulative": 17643.423, "electricity_consumed_off_peak_interval": 15, "electricity_consumed_off_peak_point": 486, "electricity_consumed_peak_cumulative": 13966.608, "electricity_consumed_peak_interval": 0, "electricity_consumed_peak_point": 0, "electricity_phase_one_consumed": 486, "electricity_phase_one_produced": 0, "electricity_produced_off_peak_cumulative": 0.0, "electricity_produced_off_peak_interval": 0, "electricity_produced_off_peak_point": 0, "electricity_produced_peak_cumulative": 0.0, "electricity_produced_peak_interval": 0, "electricity_produced_peak_point": 0, "net_electricity_cumulative": 31610.031, "net_electricity_point": 486 }, "vendor": "SHENZHEN KAIFA TECHNOLOGY \uff08CHENGDU\uff09 CO., LTD." } } python-plugwise-1.7.3/fixtures/p1v4_442_triple/000077500000000000000000000000001475766476500213465ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/p1v4_442_triple/data.json000066400000000000000000000036331475766476500231570ustar00rootroot00000000000000{ "03e65b16e4b247a29ae0d75a78cb492e": { "binary_sensors": { "plugwise_notification": true }, "dev_class": "gateway", "firmware": "4.4.2", "hardware": "AME Smile 2.0 board", "location": "03e65b16e4b247a29ae0d75a78cb492e", "mac_address": "012345670001", "model": "Gateway", "model_id": "smile", "name": "Smile P1", "notifications": { "97a04c0c263049b29350a660b4cdd01e": { "warning": "The Smile P1 is not connected to a smart meter." } }, "vendor": "Plugwise" }, "b82b6b3322484f2ea4e25e0bd5f3d61f": { "available": true, "dev_class": "smartmeter", "location": "03e65b16e4b247a29ae0d75a78cb492e", "model": "XMX5LGF0010453051839", "name": "P1", "sensors": { "electricity_consumed_off_peak_cumulative": 70537.898, "electricity_consumed_off_peak_interval": 314, "electricity_consumed_off_peak_point": 5553, "electricity_consumed_peak_cumulative": 161328.641, "electricity_consumed_peak_interval": 0, "electricity_consumed_peak_point": 0, "electricity_phase_one_consumed": 1763, "electricity_phase_one_produced": 0, "electricity_phase_three_consumed": 2080, "electricity_phase_three_produced": 0, "electricity_phase_two_consumed": 1703, "electricity_phase_two_produced": 0, "electricity_produced_off_peak_cumulative": 0.0, "electricity_produced_off_peak_interval": 0, "electricity_produced_off_peak_point": 0, "electricity_produced_peak_cumulative": 0.0, "electricity_produced_peak_interval": 0, "electricity_produced_peak_point": 0, "gas_consumed_cumulative": 16811.37, "gas_consumed_interval": 0.06, "net_electricity_cumulative": 231866.539, "net_electricity_point": 5553, "voltage_phase_one": 233.2, "voltage_phase_three": 234.7, "voltage_phase_two": 234.4 }, "vendor": "XEMEX NV" } } python-plugwise-1.7.3/fixtures/smile_p1_v2/000077500000000000000000000000001475766476500207245ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/smile_p1_v2/data.json000066400000000000000000000022241475766476500225300ustar00rootroot00000000000000{ "938696c4bcdb4b8a9a595cb38ed43913": { "dev_class": "smartmeter", "location": "938696c4bcdb4b8a9a595cb38ed43913", "model": "Ene5\\T210-DESMR5.0", "name": "P1", "sensors": { "electricity_consumed_off_peak_cumulative": 1642.74, "electricity_consumed_off_peak_interval": 0, "electricity_consumed_peak_cumulative": 1155.195, "electricity_consumed_peak_interval": 250, "electricity_consumed_point": 458, "electricity_produced_off_peak_cumulative": 482.598, "electricity_produced_off_peak_interval": 0, "electricity_produced_peak_cumulative": 1296.136, "electricity_produced_peak_interval": 0, "electricity_produced_point": 0, "gas_consumed_cumulative": 584.433, "gas_consumed_interval": 0.016, "net_electricity_cumulative": 1019.201, "net_electricity_point": 458 }, "vendor": "Ene5\\T210-DESMR5.0" }, "aaaa0000aaaa0000aaaa0000aaaa00aa": { "dev_class": "gateway", "firmware": "2.5.9", "location": "938696c4bcdb4b8a9a595cb38ed43913", "mac_address": "012345670001", "model": "Gateway", "name": "Smile P1", "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/smile_p1_v2_2/000077500000000000000000000000001475766476500211455ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/smile_p1_v2_2/data.json000066400000000000000000000022241475766476500227510ustar00rootroot00000000000000{ "199aa40f126840f392983d171374ab0b": { "dev_class": "smartmeter", "location": "199aa40f126840f392983d171374ab0b", "model": "Ene5\\T210-DESMR5.0", "name": "P1", "sensors": { "electricity_consumed_off_peak_cumulative": 1642.74, "electricity_consumed_off_peak_interval": 0, "electricity_consumed_peak_cumulative": 1155.195, "electricity_consumed_peak_interval": 250, "electricity_consumed_point": 458, "electricity_produced_off_peak_cumulative": 482.598, "electricity_produced_off_peak_interval": 0, "electricity_produced_peak_cumulative": 1296.136, "electricity_produced_peak_interval": 0, "electricity_produced_point": 0, "gas_consumed_cumulative": 584.433, "gas_consumed_interval": 0.016, "net_electricity_cumulative": 1019.201, "net_electricity_point": 458 }, "vendor": "Ene5\\T210-DESMR5.0" }, "aaaa0000aaaa0000aaaa0000aaaa00aa": { "dev_class": "gateway", "firmware": "2.5.9", "location": "199aa40f126840f392983d171374ab0b", "mac_address": "012345670001", "model": "Gateway", "name": "Smile P1", "vendor": "Plugwise" } } python-plugwise-1.7.3/fixtures/stretch_v23/000077500000000000000000000000001475766476500207525ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/stretch_v23/data.json000066400000000000000000000236321475766476500225640ustar00rootroot00000000000000{ "0000aaaa0000aaaa0000aaaa0000aa00": { "dev_class": "gateway", "firmware": "2.3.12", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "mac_address": "01:23:45:67:89:AB", "model": "Gateway", "name": "Stretch", "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "09c8ce93d7064fa6a233c0e4c2449bfe": { "dev_class": "lamp", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "kerstboom buiten 043B016", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "199fd4b2caa44197aaf5b3128f6464ed": { "dev_class": "airconditioner", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Airco 25F69E3", "sensors": { "electricity_consumed": 2.06, "electricity_consumed_interval": 1.62, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "24b2ed37c8964c73897db6340a39c129": { "dev_class": "router", "firmware": "2011-06-27T10:47:37+02:00", "hardware": "6539-0700-7325", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle+ type F", "name": "MK Netwerk 1A4455E", "sensors": { "electricity_consumed": 4.63, "electricity_consumed_interval": 0.65, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "0123456789AB" }, "2587a7fcdd7e482dab03fda256076b4b": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "00469CA1", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A16" }, "2cc9a0fe70ef4441a9e4f55dfd64b776": { "dev_class": "lamp", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Lamp TV 025F698F", "sensors": { "electricity_consumed": 4.0, "electricity_consumed_interval": 0.58, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A15" }, "305452ce97c243c0a7b4ab2a4ebfe6e3": { "dev_class": "lamp", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Lamp piano 025F6819", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "33a1c784a9ff4c2d8766a0212714be09": { "dev_class": "lighting", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Barverlichting", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "407aa1c1099d463c9137a3a9eda787fd": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "0043B013", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "6518f3f72a82486c97b91e26f2e9bd1d": { "dev_class": "charger", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Bed 025F6768", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A14" }, "713427748874454ca1eb4488d7919cf2": { "dev_class": "freezer", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Leeg 043220D", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "71e3e65ffc5a41518b19460c6e8ee34f": { "dev_class": "tv", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Leeg 043AEC6", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": false }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "828f6ce1e36744689baacdd6ddb1d12c": { "dev_class": "washingmachine", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Wasmachine 043AEC7", "sensors": { "electricity_consumed": 3.5, "electricity_consumed_interval": 0.5, "electricity_produced": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "a28e6f5afc0e4fc68498c1f03e82a052": { "dev_class": "lamp", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Lamp bank 25F67F8", "sensors": { "electricity_consumed": 4.19, "electricity_consumed_interval": 0.62, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "bc0adbebc50d428d9444a5d805c89da9": { "dev_class": "watercooker", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Waterkoker 043AF7F", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "c71f1cb2100b42ca942f056dcb7eb01f": { "dev_class": "tv", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Tv hoek 25F6790", "sensors": { "electricity_consumed": 33.3, "electricity_consumed_interval": 4.93, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" }, "f7b145c8492f4dd7a4de760456fdef3e": { "dev_class": "switching", "members": ["407aa1c1099d463c9137a3a9eda787fd"], "model": "Switchgroup", "name": "Test", "switches": { "relay": false }, "vendor": "Plugwise" }, "fd1b74f59e234a9dae4e23b2b5cf07ed": { "dev_class": "dryer", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Wasdroger 043AECA", "sensors": { "electricity_consumed": 1.31, "electricity_consumed_interval": 0.21, "electricity_produced": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "fead900a56d3430bb2d53d891f7c0656": { "dev_class": "heater_central_plug", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "CV-ketel 25F6789", "sensors": { "electricity_consumed": 1.56, "electricity_consumed_interval": 0.04, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" } } python-plugwise-1.7.3/fixtures/stretch_v27_no_domain/000077500000000000000000000000001475766476500230015ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/stretch_v27_no_domain/data.json000066400000000000000000000171721475766476500246150ustar00rootroot00000000000000{ "0000aaaa0000aaaa0000aaaa0000aa00": { "dev_class": "gateway", "firmware": "2.7.18", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "mac_address": "01:23:45:67:89:AB", "model": "Gateway", "name": "Stretch", "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "0b078d5862614880bc670cabf9f54b4e": { "dev_class": "zz_misc", "firmware": "2011-05-13T09:19:23+02:00", "hardware": "6539-0701-4023", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "769C03", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "3b729c63ca41421b9e21264adfa0a4e7": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "261B34C", "sensors": { "electricity_consumed": 8.5, "electricity_consumed_interval": 5.19, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A06" }, "4661019bbe7b4a3bbe39f345ca5b5d98": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "25F68CC", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "553dfa416df94802851de32913f1ebd3": { "dev_class": "zz_misc", "firmware": "2011-05-13T09:19:23+02:00", "hardware": "6539-0701-4023", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "B7DEED", "sensors": { "electricity_consumed": 2.5, "electricity_consumed_interval": 1.66, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A09" }, "5ee135e752034ad2a3e38a407332757f": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "261B329", "sensors": { "electricity_consumed": 6.75, "electricity_consumed_interval": 3.98, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A03" }, "7c7f0d3da801402291b057f9ec69b5b6": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "261B34D", "sensors": { "electricity_consumed": 7.81, "electricity_consumed_interval": 4.54, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A08" }, "8b8d14b242e24cd789743c828b9a2ea9": { "dev_class": "zz_misc", "firmware": "2011-05-13T09:19:23+02:00", "hardware": "6539-0701-4022", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "76BF93", "sensors": { "electricity_consumed": 1.69, "electricity_consumed_interval": 1.14, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A05" }, "8e4ecdcc9094481387e0273437bb51f9": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "25F68C3", "sensors": { "electricity_consumed": 4.69, "electricity_consumed_interval": 2.83, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "9b9bfdb3c7ad4ca5817ccaa235f1e094": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:47:37+02:00", "hardware": "6539-0700-7326", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle+ type F", "name": "25881A2", "sensors": { "electricity_consumed": 13.3, "electricity_consumed_interval": 7.77, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "9db23f92fd114e83acce036b6cb82295": { "dev_class": "zz_misc", "firmware": "2011-05-13T09:19:23+02:00", "hardware": "6539-0701-4023", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "76B2F2", "sensors": { "electricity_consumed": 0.63, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A13" }, "ad858f416f3e42e6a25bbd6b18178b0e": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "261B2AE", "sensors": { "electricity_consumed": 6.06, "electricity_consumed_interval": 3.41, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A12" }, "d0122ac66eba47b99d8e5fbd1e2f5932": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "25F66AD", "sensors": { "electricity_consumed": 3.88, "electricity_consumed_interval": 2.21, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A10" }, "e4172142264f488a99b63c73817c9d21": { "dev_class": "zz_misc", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4026", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "261B32A", "sensors": { "electricity_consumed": 9.63, "electricity_consumed_interval": 5.84, "electricity_produced": 0.0, "electricity_produced_interval": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A11" } } python-plugwise-1.7.3/fixtures/stretch_v31/000077500000000000000000000000001475766476500207515ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/stretch_v31/data.json000066400000000000000000000072741475766476500225670ustar00rootroot00000000000000{ "0000aaaa0000aaaa0000aaaa0000aa00": { "dev_class": "gateway", "firmware": "3.1.11", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "mac_address": "01:23:45:67:89:AB", "model": "Gateway", "name": "Stretch", "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670101" }, "059e4d03c7a34d278add5c7a4a781d19": { "dev_class": "washingmachine", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Wasmachine (52AC1)", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": true, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A01" }, "5871317346d045bc9f6b987ef25ee638": { "dev_class": "water_heater_vessel", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4028", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Boiler (1EB31)", "sensors": { "electricity_consumed": 1.19, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A07" }, "aac7b735042c4832ac9ff33aae4f453b": { "dev_class": "dishwasher", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "6539-0701-4022", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Vaatwasser (2a1ab)", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.71, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A02" }, "cfe95cf3de1948c0b8955125bf754614": { "dev_class": "dryer", "firmware": "2011-06-27T10:52:18+02:00", "hardware": "0000-0440-0107", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle type F", "name": "Droger (52559)", "sensors": { "electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "ABCD012345670A04" }, "d03738edfcc947f7b8f4573571d90d2d": { "dev_class": "switching", "members": [ "059e4d03c7a34d278add5c7a4a781d19", "cfe95cf3de1948c0b8955125bf754614" ], "model": "Switchgroup", "name": "Schakel", "switches": { "relay": true }, "vendor": "Plugwise" }, "d950b314e9d8499f968e6db8d82ef78c": { "dev_class": "report", "members": [ "059e4d03c7a34d278add5c7a4a781d19", "5871317346d045bc9f6b987ef25ee638", "aac7b735042c4832ac9ff33aae4f453b", "cfe95cf3de1948c0b8955125bf754614", "e1c884e7dede431dadee09506ec4f859" ], "model": "Switchgroup", "name": "Stroomvreters", "switches": { "relay": true }, "vendor": "Plugwise" }, "e1c884e7dede431dadee09506ec4f859": { "dev_class": "refrigerator", "firmware": "2011-06-27T10:47:37+02:00", "hardware": "6539-0700-7330", "location": "0000aaaa0000aaaa0000aaaa0000aa00", "model": "Circle+ type F", "name": "Koelkast (92C4A)", "sensors": { "electricity_consumed": 50.5, "electricity_consumed_interval": 0.08, "electricity_produced": 0.0 }, "switches": { "lock": false, "relay": true }, "vendor": "Plugwise", "zigbee_mac_address": "0123456789AB" } } python-plugwise-1.7.3/fixtures/updated/000077500000000000000000000000001475766476500202325ustar00rootroot00000000000000python-plugwise-1.7.3/fixtures/updated/.exists000066400000000000000000000000001475766476500215400ustar00rootroot00000000000000python-plugwise-1.7.3/plugwise/000077500000000000000000000000001475766476500165725ustar00rootroot00000000000000python-plugwise-1.7.3/plugwise/__init__.py000066400000000000000000000421241475766476500207060ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise backend module for Home Assistant Core. """ from __future__ import annotations from plugwise.constants import ( DEFAULT_LEGACY_TIMEOUT, DEFAULT_PORT, DEFAULT_TIMEOUT, DEFAULT_USERNAME, DOMAIN_OBJECTS, LOGGER, MODULES, NONE, SMILES, STATUS, SYSTEM, GwEntityData, ThermoLoc, ) from plugwise.exceptions import ( ConnectionFailedError, DataMissingError, InvalidSetupError, PlugwiseError, ResponseError, UnsupportedDeviceError, ) from plugwise.legacy.smile import SmileLegacyAPI from plugwise.smile import SmileAPI from plugwise.smilecomm import SmileComm import aiohttp from defusedxml import ElementTree as etree from packaging.version import Version, parse class Smile(SmileComm): """The main Plugwise Smile API class.""" def __init__( self, host: str, password: str, websession: aiohttp.ClientSession, port: int = DEFAULT_PORT, username: str = DEFAULT_USERNAME, ) -> None: """Set the constructor for this class.""" self._timeout = DEFAULT_LEGACY_TIMEOUT super().__init__( host, password, port, self._timeout, username, websession, ) self._cooling_present = False self._elga = False self._is_thermostat = False self._last_active: dict[str, str | None] = {} self._loc_data: dict[str, ThermoLoc] = {} self._on_off_device = False self._opentherm_device = False self._schedule_old_states: dict[str, dict[str, str]] = {} self._smile_api: SmileAPI | SmileLegacyAPI self._stretch_v2 = False self._target_smile: str = NONE self.smile_hostname: str = NONE self.smile_hw_version: str | None = None self.smile_legacy = False self.smile_mac_address: str | None = None self.smile_model: str = NONE self.smile_model_id: str | None = None self.smile_name: str = NONE self.smile_type: str = NONE self.smile_version: Version = Version("0.0.0") self.smile_zigbee_mac_address: str | None = None @property def cooling_present(self) -> bool: """Return the cooling capability.""" return self._smile_api.cooling_present @property def gateway_id(self) -> str: """Return the gateway-id.""" return self._smile_api.gateway_id @property def heater_id(self) -> str: """Return the heater-id.""" return self._smile_api.heater_id @property def item_count(self) -> int: """Return the item-count.""" return self._smile_api.item_count @property def reboot(self) -> bool: """Return the reboot capability. All non-legacy devices support gateway-rebooting. """ return not self.smile_legacy async def connect(self) -> Version: """Connect to the Plugwise Gateway and determine its name, type, version, and other data.""" result = await self._request(DOMAIN_OBJECTS) # Work-around for Stretch fw 2.7.18 if not (vendor_names := result.findall("./module/vendor_name")): result = await self._request(MODULES) vendor_names = result.findall("./module/vendor_name") names: list[str] = [] for name in vendor_names: names.append(name.text) vendor_models = result.findall("./module/vendor_model") models: list[str] = [] for model in vendor_models: models.append(model.text) dsmrmain = result.find("./module/protocols/dsmrmain") if "Plugwise" not in names and dsmrmain is None: # pragma: no cover LOGGER.error( "Connected but expected text not returned, we got %s. Please create" " an issue on http://github.com/plugwise/python-plugwise", result, ) raise ResponseError # Check if Anna is connected to an Adam if "159.2" in models: LOGGER.error( "Your Anna is connected to an Adam, make sure to only add the Adam as integration." ) raise InvalidSetupError # Determine smile specifics await self._smile_detect(result, dsmrmain) self._smile_api = ( SmileAPI( self._cooling_present, self._elga, self._is_thermostat, self._last_active, self._loc_data, self._on_off_device, self._opentherm_device, self._request, self._schedule_old_states, self.smile_hostname, self.smile_hw_version, self.smile_mac_address, self.smile_model, self.smile_model_id, self.smile_name, self.smile_type, self.smile_version, ) if not self.smile_legacy else SmileLegacyAPI( self._is_thermostat, self._loc_data, self._on_off_device, self._opentherm_device, self._request, self._stretch_v2, self._target_smile, self.smile_hostname, self.smile_hw_version, self.smile_mac_address, self.smile_model, self.smile_name, self.smile_type, self.smile_version, self.smile_zigbee_mac_address, ) ) # Update all endpoints on first connect await self._smile_api.full_xml_update() return self.smile_version async def _smile_detect( self, result: etree.Element, dsmrmain: etree.Element ) -> None: """Helper-function for connect(). Detect which type of Plugwise Gateway is being connected. """ model: str = "Unknown" if (gateway := result.find("./gateway")) is not None: if (v_model := gateway.find("vendor_model")) is not None: model = v_model.text self.smile_version = parse(gateway.find("firmware_version").text) self.smile_hw_version = gateway.find("hardware_version").text self.smile_hostname = gateway.find("hostname").text self.smile_mac_address = gateway.find("mac_address").text self.smile_model_id = gateway.find("vendor_model").text else: model = await self._smile_detect_legacy(result, dsmrmain, model) if model == "Unknown" or self.smile_version is None: # pragma: no cover # Corner case check LOGGER.error( "Unable to find model or version information, please create" " an issue on http://github.com/plugwise/python-plugwise" ) raise UnsupportedDeviceError version_major = str(self.smile_version.major) self._target_smile = f"{model}_v{version_major}" LOGGER.debug("Plugwise identified as %s", self._target_smile) if self._target_smile not in SMILES: LOGGER.error( "Your Smile identified as %s seems unsupported by our plugin, please" " create an issue on http://github.com/plugwise/python-plugwise", self._target_smile, ) raise UnsupportedDeviceError if not self.smile_legacy: self._timeout = DEFAULT_TIMEOUT if self._target_smile in ("smile_open_therm_v2", "smile_thermo_v3"): LOGGER.error( "Your Smile identified as %s needs a firmware update as it's firmware is severely outdated", self._target_smile, ) # pragma: no cover raise UnsupportedDeviceError # pragma: no cover self.smile_model = "Gateway" self.smile_name = SMILES[self._target_smile].smile_name self.smile_type = SMILES[self._target_smile].smile_type if self.smile_type == "stretch": self._stretch_v2 = int(version_major) == 2 if self.smile_type == "thermostat": self._is_thermostat = True # For Adam, Anna, determine the system capabilities: # Find the connected heating/cooling device (heater_central), # e.g. heat-pump or gas-fired heater onoff_boiler = result.find("./module/protocols/onoff_boiler") open_therm_boiler = result.find("./module/protocols/open_therm_boiler") self._on_off_device = onoff_boiler is not None self._opentherm_device = open_therm_boiler is not None # Determine the presence of special features locator_1 = "./gateway/features/cooling" locator_2 = "./gateway/features/elga_support" if result.find(locator_1) is not None: self._cooling_present = True if result.find(locator_2) is not None: self._elga = True async def _smile_detect_legacy( self, result: etree.Element, dsmrmain: etree.Element, model: str ) -> str: """Helper-function for _smile_detect(). Detect which type of legacy Plugwise Gateway is being connected. """ return_model = model # Stretch: find the MAC of the zigbee master_controller (= Stick) if (network := result.find("./module/protocols/master_controller")) is not None: self.smile_zigbee_mac_address = network.find("mac_address").text # Find the active MAC in case there is an orphaned Stick if zb_networks := result.findall("./network"): for zb_network in zb_networks: if zb_network.find("./nodes/network_router") is not None: network = zb_network.find("./master_controller") self.smile_zigbee_mac_address = network.find("mac_address").text # Legacy Anna or Stretch: if ( result.find('./appliance[type="thermostat"]') is not None or network is not None ): system = await self._request(SYSTEM) self.smile_version = parse(system.find("./gateway/firmware").text) return_model = str(system.find("./gateway/product").text) self.smile_hostname = system.find("./gateway/hostname").text # If wlan0 contains data it's active, eth0 should be checked last as is preferred for network in ("wlan0", "eth0"): locator = f"./{network}/mac" if (net_locator := system.find(locator)) is not None: self.smile_mac_address = net_locator.text # P1 legacy: elif dsmrmain is not None: status = await self._request(STATUS) self.smile_version = parse(status.find("./system/version").text) return_model = str(status.find("./system/product").text) self.smile_hostname = status.find("./network/hostname").text self.smile_mac_address = status.find("./network/mac_address").text else: # pragma: no cover # No cornercase, just end of the line LOGGER.error( "Connected but no gateway device information found, please create" " an issue on http://github.com/plugwise/python-plugwise" ) raise ResponseError self.smile_legacy = True return return_model async def async_update(self) -> dict[str, GwEntityData]: """Update the Plughwise Gateway entities and their data and states.""" data: dict[str, GwEntityData] = {} try: data = await self._smile_api.async_update() except (DataMissingError, KeyError) as err: raise PlugwiseError("No Plugwise data received") from err return data ######################################################################################################## ### API Set and HA Service-related Functions ### ######################################################################################################## async def set_select( self, key: str, loc_id: str, option: str, state: str | None = None, ) -> None: """Set the selected option for the applicable Select.""" try: await self._smile_api.set_select(key, loc_id, option, state) except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to set select option '{option}': {str(exc)}" ) from exc async def set_schedule_state( self, loc_id: str, state: str | None, name: str | None = None, ) -> None: """Activate/deactivate the Schedule, with the given name, on the relevant Thermostat.""" try: await self._smile_api.set_schedule_state(loc_id, state, name) except ConnectionFailedError as exc: # pragma no cover raise ConnectionFailedError( f"Failed to set schedule state: {str(exc)}" ) from exc # pragma no cover async def set_preset(self, loc_id: str, preset: str) -> None: """Set the given Preset on the relevant Thermostat.""" try: await self._smile_api.set_preset(loc_id, preset) except ConnectionFailedError as exc: raise ConnectionFailedError(f"Failed to set preset: {str(exc)}") from exc async def set_temperature(self, loc_id: str, items: dict[str, float]) -> None: """Set the given Temperature on the relevant Thermostat.""" try: await self._smile_api.set_temperature(loc_id, items) except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to set temperature: {str(exc)}" ) from exc async def set_number( self, dev_id: str, key: str, temperature: float, ) -> None: """Set the maximum boiler- or DHW-setpoint on the Central Heating boiler or the temperature-offset on a Thermostat.""" try: await self._smile_api.set_number(dev_id, key, temperature) except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to set number '{key}': {str(exc)}" ) from exc async def set_temperature_offset(self, dev_id: str, offset: float) -> None: """Set the Temperature offset for thermostats that support this feature.""" try: # pragma no cover await self._smile_api.set_offset(dev_id, offset) # pragma: no cover except ConnectionFailedError as exc: # pragma no cover raise ConnectionFailedError( f"Failed to set temperature offset: {str(exc)}" ) from exc # pragma no cover async def set_switch_state( self, appl_id: str, members: list[str] | None, model: str, state: str ) -> None: """Set the given State of the relevant Switch.""" try: await self._smile_api.set_switch_state(appl_id, members, model, state) except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to set switch state: {str(exc)}" ) from exc async def set_gateway_mode(self, mode: str) -> None: """Set the gateway mode.""" try: # pragma no cover await self._smile_api.set_gateway_mode(mode) # pragma: no cover except ConnectionFailedError as exc: # pragma no cover raise ConnectionFailedError( f"Failed to set gateway mode: {str(exc)}" ) from exc # pragma no cover async def set_regulation_mode(self, mode: str) -> None: """Set the heating regulation mode.""" try: # pragma no cover await self._smile_api.set_regulation_mode(mode) # pragma: no cover except ConnectionFailedError as exc: # pragma no cover raise ConnectionFailedError( f"Failed to set regulation mode: {str(exc)}" ) from exc # pragma no cover async def set_dhw_mode(self, mode: str) -> None: """Set the domestic hot water heating regulation mode.""" try: # pragma no cover await self._smile_api.set_dhw_mode(mode) # pragma: no cover except ConnectionFailedError as exc: # pragma no cover raise ConnectionFailedError( f"Failed to set dhw mode: {str(exc)}" ) from exc # pragma no cover async def delete_notification(self) -> None: """Delete the active Plugwise Notification.""" try: await self._smile_api.delete_notification() except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to delete notification: {str(exc)}" ) from exc async def reboot_gateway(self) -> None: """Reboot the Plugwise Gateway.""" try: await self._smile_api.reboot_gateway() except ConnectionFailedError as exc: raise ConnectionFailedError( f"Failed to reboot gateway: {str(exc)}" ) from exc python-plugwise-1.7.3/plugwise/common.py000066400000000000000000000225651475766476500204460ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise Smile protocol helpers. """ from __future__ import annotations from typing import cast from plugwise.constants import ( ANNA, NONE, SPECIAL_PLUG_TYPES, SWITCH_GROUP_TYPES, ApplianceType, GwEntityData, ModuleData, ) from plugwise.util import ( check_heater_central, check_model, get_vendor_name, return_valid, ) from defusedxml import ElementTree as etree from munch import Munch def get_zigbee_data( module: etree.Element, module_data: ModuleData, legacy: bool ) -> None: """Helper-function for _get_module_data().""" if legacy: # Stretches if (router := module.find("./protocols/network_router")) is not None: module_data["zigbee_mac_address"] = router.find("mac_address").text # Also look for the Circle+/Stealth M+ if (coord := module.find("./protocols/network_coordinator")) is not None: module_data["zigbee_mac_address"] = coord.find("mac_address").text # Adam elif (zb_node := module.find("./protocols/zig_bee_node")) is not None: module_data["zigbee_mac_address"] = zb_node.find("mac_address").text module_data["reachable"] = zb_node.find("reachable").text == "true" class SmileCommon: """The SmileCommon class.""" def __init__(self) -> None: """Init.""" self._cooling_present: bool self._count: int self._domain_objects: etree.Element self._heater_id: str = NONE self._on_off_device: bool self.gw_entities: dict[str, GwEntityData] = {} self.smile_name: str self.smile_type: str @property def heater_id(self) -> str: """Return the heater-id.""" return self._heater_id def smile(self, name: str) -> bool: """Helper-function checking the smile-name.""" return self.smile_name == name def _appl_heater_central_info( self, appl: Munch, xml_1: etree.Element, legacy: bool, xml_2: etree.Element = None, xml_3: etree.Element = None, ) -> Munch: """Helper-function for _appliance_info_finder().""" # Find the valid heater_central # xml_2 self._appliances for legacy, self._domain_objects for actual xml_2 = return_valid(xml_2, self._domain_objects) self._heater_id = check_heater_central(xml_2) if self._heater_id == NONE: return Munch() # pragma: no cover # Info for On-Off device if self._on_off_device: appl.name = "OnOff" # pragma: no cover appl.model = "Unknown" # pragma: no cover appl.vendor_name = None # pragma: no cover return appl # pragma: no cover # Info for OpenTherm device appl.name = "OpenTherm" locator_1 = "./logs/point_log[type='flame_state']/boiler_state" locator_2 = "./services/boiler_state" # xml_1: appliance # xml_3: self._modules for legacy, self._domain_objects for actual xml_3 = return_valid(xml_3, self._domain_objects) module_data = self._get_module_data(xml_1, locator_1, xml_3) if not module_data["contents"]: module_data = self._get_module_data(xml_1, locator_2, xml_3) appl.vendor_name = module_data["vendor_name"] appl.hardware = module_data["hardware_version"] appl.model_id = module_data["vendor_model"] if not legacy else None appl.model = ( "Generic heater/cooler" if self._cooling_present else "Generic heater" ) return appl def _appl_thermostat_info( self, appl: Munch, xml_1: etree.Element, xml_2: etree.Element = None ) -> Munch: """Helper-function for _appliance_info_finder().""" locator = "./logs/point_log[type='thermostat']/thermostat" xml_2 = return_valid(xml_2, self._domain_objects) module_data = self._get_module_data(xml_1, locator, xml_2) appl.vendor_name = module_data["vendor_name"] appl.model = module_data["vendor_model"] if ( appl.model != "ThermoTouch" ): # model_id for Anna not present as stand-alone device appl.model_id = appl.model appl.model = check_model(appl.model, appl.vendor_name) appl.available = module_data["reachable"] appl.hardware = module_data["hardware_version"] appl.firmware = module_data["firmware_version"] appl.zigbee_mac = module_data["zigbee_mac_address"] return appl def _create_gw_entities(self, appl: Munch) -> None: """Helper-function for creating/updating gw_entities.""" self.gw_entities[appl.entity_id] = {"dev_class": appl.pwclass} self._count += 1 for key, value in { "available": appl.available, "firmware": appl.firmware, "hardware": appl.hardware, "location": appl.location, "mac_address": appl.mac, "model": appl.model, "model_id": appl.model_id, "name": appl.name, "zigbee_mac_address": appl.zigbee_mac, "vendor": appl.vendor_name, }.items(): if value is not None or key == "location": appl_key = cast(ApplianceType, key) self.gw_entities[appl.entity_id][appl_key] = value self._count += 1 def _entity_switching_group(self, entity: GwEntityData, data: GwEntityData) -> None: """Helper-function for _get_device_zone_data(). Determine switching group device data. """ if entity["dev_class"] in SWITCH_GROUP_TYPES: counter = 0 for member in entity["members"]: if self.gw_entities[member]["switches"].get("relay"): counter += 1 data["switches"]["relay"] = counter != 0 self._count += 1 def _get_group_switches(self) -> dict[str, GwEntityData]: """Helper-function for smile.py: get_all_gateway_entities(). Collect switching- or pump-group info. """ switch_groups: dict[str, GwEntityData] = {} # P1 and Anna don't have switchgroups if self.smile_type == "power" or self.smile(ANNA): return switch_groups for group in self._domain_objects.findall("./group"): members: list[str] = [] group_id = group.attrib["id"] group_name = group.find("name").text group_type = group.find("type").text group_appliances = group.findall("appliances/appliance") for item in group_appliances: # Check if members are not orphaned - stretch if item.attrib["id"] in self.gw_entities: members.append(item.attrib["id"]) if group_type in SWITCH_GROUP_TYPES and members: switch_groups[group_id] = { "dev_class": group_type, "model": "Switchgroup", "name": group_name, "members": members, "vendor": "Plugwise", } self._count += 4 return switch_groups def _get_lock_state( self, xml: etree.Element, data: GwEntityData, stretch_v2: bool = False ) -> None: """Helper-function for _get_measurement_data(). Adam & Stretches: obtain the relay-switch lock state. """ actuator = "actuator_functionalities" func_type = "relay_functionality" if stretch_v2: actuator = "actuators" func_type = "relay" if xml.find("type").text not in SPECIAL_PLUG_TYPES: locator = f"./{actuator}/{func_type}/lock" if (found := xml.find(locator)) is not None: data["switches"]["lock"] = found.text == "true" self._count += 1 def _get_module_data( self, xml_1: etree.Element, locator: str, xml_2: etree.Element = None, legacy: bool = False, ) -> ModuleData: """Helper-function for _energy_device_info_finder() and _appliance_info_finder(). Collect requested info from MODULES. """ module_data: ModuleData = { "contents": False, "firmware_version": None, "hardware_version": None, "reachable": None, "vendor_name": None, "vendor_model": None, "zigbee_mac_address": None, } if (appl_search := xml_1.find(locator)) is not None: link_tag = appl_search.tag link_id = appl_search.attrib["id"] loc = f".//services/{link_tag}[@id='{link_id}']...." # Not possible to walrus for some reason... # xml_2: self._modules for legacy, self._domain_objects for actual search = return_valid(xml_2, self._domain_objects) module = search.find(loc) if module is not None: # pylint: disable=consider-using-assignment-expr module_data["contents"] = True get_vendor_name(module, module_data) module_data["vendor_model"] = module.find("vendor_model").text module_data["hardware_version"] = module.find("hardware_version").text module_data["firmware_version"] = module.find("firmware_version").text get_zigbee_data(module, module_data, legacy) return module_data python-plugwise-1.7.3/plugwise/constants.py000066400000000000000000000407451475766476500211720ustar00rootroot00000000000000"""Plugwise Smile constants.""" from __future__ import annotations from collections import namedtuple import logging from typing import Final, Literal, TypedDict, get_args LOGGER = logging.getLogger(__name__) # Copied homeassistant.consts ATTR_NAME: Final = "name" ATTR_STATE: Final = "state" ATTR_STATE_CLASS: Final = "state_class" ATTR_UNIT_OF_MEASUREMENT: Final = "unit_of_measurement" DEGREE: Final = "°" ELECTRIC_POTENTIAL_VOLT: Final = "V" ENERGY_KILO_WATT_HOUR: Final = "kWh" ENERGY_WATT_HOUR: Final = "Wh" GATEWAY_REBOOT: Final = "/core/gateways;@reboot" PERCENTAGE: Final = "%" POWER_WATT: Final = "W" PRESET_AWAY: Final = "away" PRESSURE_BAR: Final = "bar" SIGNAL_STRENGTH_DECIBELS_MILLIWATT: Final = "dBm" TEMP_CELSIUS: Final = "°C" TEMP_KELVIN: Final = "°K" TIME_MILLISECONDS: Final = "ms" UNIT_LUMEN: Final = "lm" VOLUME_CUBIC_METERS: Final = "mÂŗ" VOLUME_CUBIC_METERS_PER_HOUR: Final = "mÂŗ/h" ADAM: Final = "Adam" ANNA: Final = "Smile Anna" DEFAULT_TIMEOUT: Final = 10 DEFAULT_LEGACY_TIMEOUT: Final = 30 DEFAULT_USERNAME: Final = "smile" DEFAULT_PORT: Final = 80 DEFAULT_PW_MAX: Final = 30.0 DEFAULT_PW_MIN: Final = 4.0 DHW_SETPOINT: Final = "domestic_hot_water_setpoint" FAKE_APPL: Final = "aaaa0000aaaa0000aaaa0000aaaa00aa" FAKE_LOC: Final = "0000aaaa0000aaaa0000aaaa0000aa00" HW_MODELS: Final[dict[str, str]] = { "143.1": "ThermoTouch", "159.2": "Adam", "106-03": "Tom/Floor", "158-01": "Lisa", "160-01": "Plug", "168-01": "Jip", "038500": "Stick", "070085": "Stick", "120002": "Stick Legrand", "120041": "Circle+ Legrand type E", "120000": "Circle+ Legrand type F", "090000": "Circle+ type B", "090007": "Circle+ type B", "090088": "Circle+ type E", "070073": "Circle+ type F", "090048": "Circle+ type G", "120049": "Stealth M+", "090188": "Stealth+", "120040": "Circle Legrand type E", "120001": "Circle Legrand type F", "090079": "Circle type B", "090087": "Circle type E", "070140": "Circle type F", "090093": "Circle type G", "100025": "Circle", "120048": "Stealth M", "120029": "Stealth Legrand", "090011": "Stealth", "001200": "Stealth", "080007": "Scan", "110028": "Scan Legrand", "070030": "Sense", "120006": "Sense Legrand", "070051": "Switch", "080029": "Switch", } MAX_SETPOINT: Final[float] = 30.0 MIN_SETPOINT: Final[float] = 4.0 MODULE_LOCATOR: Final = "./logs/point_log/*[@id]" NONE: Final = "None" OFF: Final = "off" PRIORITY_DEVICE_CLASSES = ("heater_central", "gateway") # XML data paths APPLIANCES: Final = "/core/appliances" DOMAIN_OBJECTS: Final = "/core/domain_objects" LOCATIONS: Final = "/core/locations" MODULES: Final = "/core/modules" NOTIFICATIONS: Final = "/core/notifications" RULES: Final = "/core/rules" SYSTEM: Final = "/system" STATUS: Final = "/system/status.xml" UOM = namedtuple("UOM", "unit_of_measurement") DATA = namedtuple("DATA", "name unit_of_measurement") # P1 related measurements: P1_MEASUREMENTS: Final[dict[str, UOM]] = { "electricity_consumed": UOM(POWER_WATT), "electricity_produced": UOM(POWER_WATT), "electricity_phase_one_consumed": UOM(POWER_WATT), "electricity_phase_two_consumed": UOM(POWER_WATT), "electricity_phase_three_consumed": UOM(POWER_WATT), "electricity_phase_one_produced": UOM(POWER_WATT), "electricity_phase_two_produced": UOM(POWER_WATT), "electricity_phase_three_produced": UOM(POWER_WATT), "gas_consumed": UOM(VOLUME_CUBIC_METERS), "voltage_phase_one": UOM(ELECTRIC_POTENTIAL_VOLT), "voltage_phase_two": UOM(ELECTRIC_POTENTIAL_VOLT), "voltage_phase_three": UOM(ELECTRIC_POTENTIAL_VOLT), } P1_LEGACY_MEASUREMENTS: Final[dict[str, UOM]] = { "electricity_consumed": UOM(POWER_WATT), "electricity_produced": UOM(POWER_WATT), "gas_consumed": UOM(VOLUME_CUBIC_METERS), } # Thermostat and Plug/Stretch related measurements # Excluded: # zone_thermosstat: 'temperature_offset' # radiator_valve: 'uncorrected_temperature', 'temperature_offset' DEVICE_MEASUREMENTS: Final[dict[str, DATA | UOM]] = { "humidity": UOM(NONE), # Specific for a Jip "illuminance": UOM(UNIT_LUMEN), # Specific for an Anna "temperature": UOM(TEMP_CELSIUS), # HA Core thermostat current_temperature "thermostat": DATA("setpoint", TEMP_CELSIUS), # HA Core thermostat setpoint ######################################################## # Specific for an Anna with heatpump extension installed "cooling_activation_outdoor_temperature": UOM(TEMP_CELSIUS), "cooling_deactivation_threshold": UOM(TEMP_CELSIUS), ################################## # Specific for a Lisa or Tom/Floor "battery": UOM(PERCENTAGE), "temperature_difference": UOM(DEGREE), "valve_position": UOM(PERCENTAGE), ##################### # Specific for a Plug "electricity_consumed": UOM(POWER_WATT), "electricity_produced": UOM(POWER_WATT), "relay": UOM(NONE), } # Heater Central related measurements HEATER_CENTRAL_MEASUREMENTS: Final[dict[str, DATA | UOM]] = { "boiler_state": DATA( "flame_state", NONE ), # Legacy Anna: similar to flame-state on Anna/Adam "boiler_temperature": DATA("water_temperature", TEMP_CELSIUS), "central_heating_state": DATA( "c_heating_state", NONE ), # For Elga (heatpump) use this instead of intended_central_heating_state "central_heater_water_pressure": DATA("water_pressure", PRESSURE_BAR), "compressor_state": UOM(NONE), # present with heatpump "cooling_enabled": UOM( NONE ), # Available with the Loria and Elga (newer Anna firmware) heatpumps "cooling_state": UOM(NONE), "domestic_hot_water_mode": DATA("select_dhw_mode", NONE), "domestic_hot_water_setpoint": UOM(TEMP_CELSIUS), "domestic_hot_water_state": DATA("dhw_state", NONE), "domestic_hot_water_temperature": DATA("dhw_temperature", TEMP_CELSIUS), "elga_status_code": UOM(NONE), "intended_boiler_state": DATA( "heating_state", NONE ), # Legacy Anna: shows when heating is active, we don't show dhw_state, cannot be determined reliably "flame_state": UOM(NONE), # Also present when there is a single gas-heater "intended_boiler_temperature": UOM( TEMP_CELSIUS ), # Non-zero when heating, zero when dhw-heating "intended_central_heating_state": DATA( "heating_state", NONE ), # This key shows in general the heating-behavior better than c-h_state. except when connected to a heatpump "modulation_level": UOM(PERCENTAGE), "return_water_temperature": DATA("return_temperature", TEMP_CELSIUS), "outdoor_temperature": DATA( "outdoor_air_temperature", TEMP_CELSIUS ), # Outdoor temperature from APPLIANCES - present for a heatpump "slave_boiler_state": DATA("secondary_boiler_state", NONE), "thermostat_supports_cooling": UOM(NONE), # present with heatpump } OBSOLETE_MEASUREMENTS: Final[tuple[str, ...]] = ( "central_heater_water_pressure", "outdoor_temperature", ) # Zone/climate related measurements ZONE_MEASUREMENTS: Final[dict[str, DATA | UOM]] = { "electricity_consumed": UOM(POWER_WATT), "electricity_produced": UOM(POWER_WATT), "relay": UOM(NONE), "temperature": UOM(TEMP_CELSIUS), # HA Core thermostat current_temperature "thermostat": DATA("setpoint", TEMP_CELSIUS), # HA Core thermostat setpoint } # Literals SMILE_P1 = "Smile P1" POWER = "power" STRETCH = "stretch" THERMOSTAT = "thermostat" # Known types of Smiles and Stretches SMILE = namedtuple("SMILE", "smile_type smile_name") SMILES: Final[dict[str, SMILE]] = { "smile_v2": SMILE(POWER, SMILE_P1), "smile_v3": SMILE(POWER, SMILE_P1), "smile_v4": SMILE(POWER, SMILE_P1), "smile_open_therm_v2": SMILE(THERMOSTAT, ADAM), "smile_open_therm_v3": SMILE(THERMOSTAT, ADAM), "smile_thermo_v1": SMILE(THERMOSTAT, ANNA), "smile_thermo_v3": SMILE(THERMOSTAT, ANNA), "smile_thermo_v4": SMILE(THERMOSTAT, ANNA), "stretch_v2": SMILE(STRETCH, "Stretch"), "stretch_v3": SMILE(STRETCH, "Stretch"), } REQUIRE_APPLIANCES: Final[tuple[str, ...]] = ( "smile_thermo_v1", "smile_thermo_v3", "smile_thermo_v4", "stretch_v2", "stretch_v3", ) # Class, Literal and related tuple-definitions ACTUATOR_CLASSES: Final[tuple[str, ...]] = ( "heater_central", "thermostat", "thermostatic_radiator_valve", "zone_thermometer", "zone_thermostat", ) ActuatorType = Literal[ "domestic_hot_water_setpoint", "max_dhw_temperature", "maximum_boiler_temperature", "temperature_offset", "thermostat", ] ACTIVE_ACTUATORS: Final[tuple[str, ...]] = get_args(ActuatorType) ActuatorDataType = Literal[ "lower_bound", "resolution", "setpoint", "setpoint_high", "setpoint_low", "upper_bound", ] ApplianceType = Literal[ "dev_class", "firmware", "hardware", "location", "mac_address", "members", "model", "model_id", "name", "vendor", "zigbee_mac_address", ] BinarySensorType = Literal[ "compressor_state", "cooling_enabled", "cooling_state", "dhw_state", "flame_state", "heating_state", "low_battery", "plugwise_notification", "secondary_boiler_state", ] BINARY_SENSORS: Final[tuple[str, ...]] = get_args(BinarySensorType) LIMITS: Final[tuple[str, ...]] = ( "lower_bound", "offset", "resolution", "setpoint", "upper_bound", ) SensorType = Literal[ "battery", "cooling_activation_outdoor_temperature", "cooling_deactivation_threshold", "dhw_temperature", "domestic_hot_water_setpoint", "temperature", "electricity_consumed", "electricity_consumed_interval", "electricity_consumed_off_peak_cumulative", "electricity_consumed_off_peak_interval", "electricity_consumed_off_peak_point", "electricity_consumed_peak_cumulative", "electricity_consumed_peak_interval", "electricity_consumed_peak_point", "electricity_consumed_point", "electricity_phase_one_consumed", "electricity_phase_two_consumed", "electricity_phase_three_consumed", "electricity_phase_one_produced", "electricity_phase_two_produced", "electricity_phase_three_produced", "electricity_produced", "electricity_produced_interval", "electricity_produced_off_peak_cumulative", "electricity_produced_off_peak_interval", "electricity_produced_off_peak_point", "electricity_produced_peak_cumulative", "electricity_produced_peak_interval", "electricity_produced_peak_point", "electricity_produced_point", "gas_consumed_cumulative", "gas_consumed_interval", "humidity", "illuminance", "intended_boiler_temperature", "modulation_level", "net_electricity_cumulative", "net_electricity_point", "outdoor_air_temperature", "outdoor_temperature", "return_temperature", "setpoint", "setpoint_high", "setpoint_low", "temperature_difference", "valve_position", "voltage_phase_one", "voltage_phase_two", "voltage_phase_three", "water_pressure", "water_temperature", ] SENSORS: Final[tuple[str, ...]] = get_args(SensorType) SPECIAL_PLUG_TYPES: Final[tuple[str, ...]] = ( "central_heating_pump", "heater_electric", "valve_actuator", ) SpecialType = Literal[ "c_heating_state", "thermostat_supports_cooling", ] SPECIALS: Final[tuple[str, ...]] = get_args(SpecialType) SPECIAL_FORMAT: Final[tuple[str, ...]] = (ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS) SwitchType = Literal[ "cooling_ena_switch", "dhw_cm_switch", "lock", "relay", ] SWITCHES: Final[tuple[str, ...]] = get_args(SwitchType) SWITCH_GROUP_TYPES: Final[tuple[str, ...]] = ("report", "switching") THERMOSTAT_CLASSES: Final[tuple[str, ...]] = ( "thermostat", "thermostatic_radiator_valve", "thermo_sensor", "zone_thermometer", "zone_thermostat", ) ToggleNameType = Literal[ "cooling_ena_switch", "dhw_cm_switch", ] TOGGLES: Final[dict[str, ToggleNameType]] = { "cooling_enabled": "cooling_ena_switch", "domestic_hot_water_comfort_mode": "dhw_cm_switch", } ZONE_THERMOSTATS: Final[tuple[str, ...]] = ( "thermostat", "thermostatic_radiator_valve", "zone_thermometer", "zone_thermostat", ) class ModuleData(TypedDict): """The Module data class.""" contents: bool firmware_version: str | None hardware_version: str | None reachable: bool | None vendor_model: str | None vendor_name: str | None zigbee_mac_address: str | None class SmileBinarySensors(TypedDict, total=False): """Smile Binary Sensors class.""" compressor_state: bool cooling_enabled: bool cooling_state: bool dhw_state: bool flame_state: bool heating_state: bool low_battery: bool plugwise_notification: bool secondary_boiler_state: bool class SmileSensors(TypedDict, total=False): """Smile Sensors class.""" battery: int cooling_activation_outdoor_temperature: float cooling_deactivation_threshold: float dhw_temperature: float domestic_hot_water_setpoint: float temperature: float electricity_consumed: float electricity_consumed_interval: float electricity_consumed_off_peak_cumulative: float electricity_consumed_off_peak_interval: float electricity_consumed_off_peak_point: float electricity_consumed_peak_cumulative: float electricity_consumed_peak_interval: float electricity_consumed_peak_point: float electricity_consumed_point: float electricity_phase_one_consumed: float electricity_phase_two_consumed: float electricity_phase_three_consumed: float electricity_phase_one_produced: float electricity_phase_two_produced: float electricity_phase_three_produced: float electricity_produced: float electricity_produced_interval: float electricity_produced_off_peak_cumulative: float electricity_produced_off_peak_interval: float electricity_produced_off_peak_point: float electricity_produced_peak_cumulative: float electricity_produced_peak_interval: float electricity_produced_peak_point: float electricity_produced_point: float gas_consumed_cumulative: float gas_consumed_interval: float humidity: float illuminance: float intended_boiler_temperature: float modulation_level: int net_electricity_cumulative: float net_electricity_point: float outdoor_air_temperature: float outdoor_temperature: float return_temperature: float setpoint: float setpoint_high: float setpoint_low: float temperature_difference: float valve_position: int voltage_phase_one: float voltage_phase_two: float voltage_phase_three: float water_pressure: float water_temperature: float class SmileSwitches(TypedDict, total=False): """Smile Switches class.""" cooling_ena_switch: bool dhw_cm_switch: bool lock: bool relay: bool class ThermoLoc(TypedDict, total=False): """Thermo Location class.""" name: str primary: list[str] primary_prio: int secondary: list[str] class ActuatorData(TypedDict, total=False): """Actuator data for thermostat types.""" lower_bound: float resolution: float setpoint: float setpoint_high: float setpoint_low: float upper_bound: float class GwEntityData(TypedDict, total=False): """The Gateway Entity data class. Covering the collected output-data per device or location. """ # Appliance base data dev_class: str firmware: str hardware: str location: str mac_address: str members: list[str] model: str model_id: str | None name: str vendor: str zigbee_mac_address: str # For temporary use cooling_enabled: bool domestic_hot_water_setpoint: float elga_status_code: int c_heating_state: bool thermostat_supports_cooling: bool # Device availability available: bool | None # Loria select_dhw_mode: str dhw_modes: list[str] # Gateway gateway_modes: list[str] notifications: dict[str, dict[str, str]] regulation_modes: list[str] select_gateway_mode: str select_regulation_mode: str # Thermostat-related thermostats: dict[str, list[str]] # Presets: active_preset: str | None preset_modes: list[str] | None # Schedules: available_schedules: list[str] select_schedule: str climate_mode: str # Extra for Adam Master Thermostats control_state: str # Dict-types binary_sensors: SmileBinarySensors max_dhw_temperature: ActuatorData maximum_boiler_temperature: ActuatorData sensors: SmileSensors switches: SmileSwitches temperature_offset: ActuatorData thermostat: ActuatorData python-plugwise-1.7.3/plugwise/data.py000066400000000000000000000303121475766476500200540ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise Smile protocol data-collection helpers. """ from __future__ import annotations import re from plugwise.constants import ( ADAM, ANNA, MAX_SETPOINT, MIN_SETPOINT, NONE, OFF, ActuatorData, GwEntityData, ) from plugwise.helper import SmileHelper from plugwise.util import remove_empty_platform_dicts class SmileData(SmileHelper): """The Plugwise Smile main class.""" def __init__(self) -> None: """Init.""" super().__init__() self._zones: dict[str, GwEntityData] = {} def _all_entity_data(self) -> None: """Helper-function for get_all_gateway_entities(). Collect data for each entity and add to self.gw_entities. """ self._update_gw_entities() if self.smile(ADAM): self._update_zones() self.gw_entities.update(self._zones) def _update_zones(self) -> None: """Helper-function for _all_entity_data() and async_update(). Collect data for each zone/location and add to self._zones. """ for location_id, zone in self._zones.items(): data = self._get_location_data(location_id) zone.update(data) def _update_gw_entities(self) -> None: """Helper-function for _all_entities_data() and async_update(). Collect data for each entity and add to self.gw_entities. """ mac_list: list[str] = [] for entity_id, entity in self.gw_entities.items(): data = self._get_entity_data(entity_id) if entity_id == self._gateway_id: mac_list = self._detect_low_batteries() self._add_or_update_notifications(entity_id, entity, data) entity.update(data) is_battery_low = ( mac_list and "low_battery" in entity["binary_sensors"] and entity["zigbee_mac_address"] in mac_list and entity["dev_class"] in ( "thermo_sensor", "thermostatic_radiator_valve", "zone_thermometer", "zone_thermostat", ) ) if is_battery_low: entity["binary_sensors"]["low_battery"] = True self._update_for_cooling(entity) remove_empty_platform_dicts(entity) def _detect_low_batteries(self) -> list[str]: """Helper-function updating the low-battery binary_sensor status from a Battery-is-low message.""" mac_address_list: list[str] = [] mac_pattern = re.compile(r"(?:[0-9A-F]{2}){8}") matches = ["Battery", "below"] if self._notifications: for msg_id, notification in list(self._notifications.items()): mac_address: str | None = None message: str | None = notification.get("message") warning: str | None = notification.get("warning") notify = message or warning if ( notify is not None and all(x in notify for x in matches) and (mac_addresses := mac_pattern.findall(notify)) ): mac_address = mac_addresses[0] # re.findall() outputs a list if mac_address is not None: mac_address_list.append(mac_address) if message is not None: # only block message-type notifications self._notifications.pop(msg_id) return mac_address_list def _add_or_update_notifications( self, entity_id: str, entity: GwEntityData, data: GwEntityData ) -> None: """Helper-function adding or updating the Plugwise notifications.""" if ( entity_id == self._gateway_id and (self._is_thermostat or self.smile_type == "power") ) or ( "binary_sensors" in entity and "plugwise_notification" in entity["binary_sensors"] ): data["binary_sensors"]["plugwise_notification"] = bool(self._notifications) data["notifications"] = self._notifications self._count += 2 def _update_for_cooling(self, entity: GwEntityData) -> None: """Helper-function for adding/updating various cooling-related values.""" # For Anna and heating + cooling, replace setpoint with setpoint_high/_low if ( self.smile(ANNA) and self._cooling_present and entity["dev_class"] == "thermostat" ): thermostat = entity["thermostat"] sensors = entity["sensors"] temp_dict: ActuatorData = { "setpoint_low": thermostat["setpoint"], "setpoint_high": MAX_SETPOINT, } if self._cooling_enabled: temp_dict = { "setpoint_low": MIN_SETPOINT, "setpoint_high": thermostat["setpoint"], } thermostat.pop("setpoint") temp_dict.update(thermostat) entity["thermostat"] = temp_dict if "setpoint" in sensors: sensors.pop("setpoint") sensors["setpoint_low"] = temp_dict["setpoint_low"] sensors["setpoint_high"] = temp_dict["setpoint_high"] self._count += 2 # add 4, remove 2 def _get_location_data(self, loc_id: str) -> GwEntityData: """Helper-function for _all_entity_data() and async_update(). Provide entity-data, based on Location ID (= loc_id). """ zone = self._zones[loc_id] data = self._get_zone_data(loc_id) data["control_state"] = "idle" self._count += 1 if (ctrl_state := self._control_state(data, loc_id)) and str(ctrl_state) in ( "cooling", "heating", "preheating", ): data["control_state"] = str(ctrl_state) data["sensors"].pop("setpoint") # remove, only used in _control_state() self._count -= 1 # Thermostat data (presets, temperatures etc) self._climate_data(loc_id, zone, data) return data def _get_entity_data(self, entity_id: str) -> GwEntityData: """Helper-function for _update_gw_entities() and async_update(). Provide entity-data, based on appliance_id (= entity_id). """ entity = self.gw_entities[entity_id] data = self._get_measurement_data(entity_id) # Check availability of wired-connected entities # Smartmeter self._check_availability( entity, "smartmeter", data, "P1 does not seem to be connected" ) # OpenTherm entity if entity["name"] != "OnOff": self._check_availability( entity, "heater_central", data, "no OpenTherm communication" ) # Switching groups data self._entity_switching_group(entity, data) # Adam data if self.smile(ADAM): self._get_adam_data(entity, data) # Thermostat data for Anna (presets, temperatures etc) if self.smile(ANNA) and entity["dev_class"] == "thermostat": self._climate_data(entity_id, entity, data) self._get_anna_control_state(data) return data def _check_availability( self, entity: GwEntityData, dev_class: str, data: GwEntityData, message: str ) -> None: """Helper-function for _get_entity_data(). Provide availability status for the wired-connected devices. """ if entity["dev_class"] == dev_class: data["available"] = True self._count += 1 for item in self._notifications.values(): for msg in item.values(): if message in msg: data["available"] = False break def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None: """Helper-function for _get_entity_data(). Determine Adam heating-status for on-off heating via valves, available regulations_modes and thermostat control_states, and add missing cooling_enabled when required. """ if entity["dev_class"] == "heater_central": # Indicate heating_state based on valves being open in case of city-provided heating if self._on_off_device and isinstance(self._heating_valves(), int): data["binary_sensors"]["heating_state"] = self._heating_valves() != 0 # Add cooling_enabled binary_sensor if "binary_sensors" in data: if ( "cooling_enabled" not in data["binary_sensors"] and self._cooling_present ): data["binary_sensors"]["cooling_enabled"] = self._cooling_enabled # Show the allowed regulation_modes and gateway_modes if entity["dev_class"] == "gateway": if self._reg_allowed_modes: data["regulation_modes"] = self._reg_allowed_modes self._count += 1 if self._gw_allowed_modes: data["gateway_modes"] = self._gw_allowed_modes self._count += 1 def _climate_data( self, location_id: str, entity: GwEntityData, data: GwEntityData ) -> None: """Helper-function for _get_entity_data(). Determine climate-control entity data. """ loc_id = location_id if entity.get("location") is not None: loc_id = entity["location"] # Presets data["preset_modes"] = None data["active_preset"] = None self._count += 2 if presets := self._presets(loc_id): data["preset_modes"] = list(presets) data["active_preset"] = self._preset(loc_id) # Schedule avail_schedules, sel_schedule = self._schedules(loc_id) if avail_schedules != [NONE]: data["available_schedules"] = avail_schedules data["select_schedule"] = sel_schedule self._count += 2 # Set HA climate HVACMode: auto, heat, heat_cool, cool and off data["climate_mode"] = "auto" self._count += 1 if sel_schedule in (NONE, OFF): data["climate_mode"] = "heat" if self._cooling_present: data["climate_mode"] = ( "cool" if self.check_reg_mode("cooling") else "heat_cool" ) if self.check_reg_mode("off"): data["climate_mode"] = "off" if NONE not in avail_schedules: self._get_schedule_states_with_off( loc_id, avail_schedules, sel_schedule, data ) def check_reg_mode(self, mode: str) -> bool: """Helper-function for device_data_climate().""" gateway = self.gw_entities[self._gateway_id] return ( "regulation_modes" in gateway and gateway["select_regulation_mode"] == mode ) def _get_anna_control_state(self, data: GwEntityData) -> None: """Set the thermostat control_state based on the opentherm/onoff device state.""" data["control_state"] = "idle" self._count += 1 for entity in self.gw_entities.values(): if entity["dev_class"] != "heater_central": continue binary_sensors = entity["binary_sensors"] if binary_sensors["heating_state"]: data["control_state"] = "heating" if binary_sensors.get("cooling_state"): data["control_state"] = "cooling" def _get_schedule_states_with_off( self, location: str, schedules: list[str], selected: str, data: GwEntityData ) -> None: """Collect schedules with states for each thermostat. Also, replace NONE by OFF when none of the schedules are active. """ all_off = True self._schedule_old_states[location] = {} for schedule in schedules: active: bool = schedule == selected and data["climate_mode"] == "auto" self._schedule_old_states[location][schedule] = "off" if active: self._schedule_old_states[location][schedule] = "on" all_off = False if all_off: data["select_schedule"] = OFF python-plugwise-1.7.3/plugwise/exceptions.py000066400000000000000000000021261475766476500213260ustar00rootroot00000000000000"""Plugwise Smile Exceptions.""" class PlugwiseException(Exception): """Base error class for this Plugwise library.""" class ConnectionFailedError(PlugwiseException): """Raised when unable to connect.""" class DataMissingError(PlugwiseException): """Raised when expected data is missing.""" class InvalidAuthentication(PlugwiseException): """Raised when unable to authenticate.""" class InvalidSetupError(PlugwiseException): """Raised when adding an Anna while an Adam exists.""" class PlugwiseError(PlugwiseException): """Raise when a non-specific error happens.""" class UnsupportedDeviceError(PlugwiseException): """Raised when device is not supported.""" class DeviceSetupError(PlugwiseException): """Raised when device is missing critical setup data.""" class ResponseError(PlugwiseException): """Raised when empty or error in response returned.""" class InvalidXMLError(PlugwiseException): """Raised when response holds incomplete or invalid XML data.""" class XMLDataMissingError(PlugwiseException): """Raised when xml data is empty.""" python-plugwise-1.7.3/plugwise/helper.py000066400000000000000000001154251475766476500204330ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise Smile protocol helpers. """ from __future__ import annotations import datetime as dt from typing import cast from plugwise.common import SmileCommon from plugwise.constants import ( ACTIVE_ACTUATORS, ACTUATOR_CLASSES, ADAM, ANNA, ATTR_NAME, DATA, DEVICE_MEASUREMENTS, DHW_SETPOINT, DOMAIN_OBJECTS, ENERGY_WATT_HOUR, HEATER_CENTRAL_MEASUREMENTS, LIMITS, LOCATIONS, LOGGER, MODULE_LOCATOR, NONE, OFF, P1_MEASUREMENTS, PRIORITY_DEVICE_CLASSES, TEMP_CELSIUS, THERMOSTAT_CLASSES, TOGGLES, UOM, ZONE_MEASUREMENTS, ActuatorData, ActuatorDataType, ActuatorType, GwEntityData, SensorType, ThermoLoc, ToggleNameType, ) from plugwise.util import ( check_model, collect_power_values, common_match_cases, count_data_items, format_measure, skip_obsolete_measurements, ) # Time related from dateutil import tz from dateutil.parser import parse from defusedxml import ElementTree as etree from munch import Munch from packaging import version def search_actuator_functionalities( appliance: etree.Element, actuator: str ) -> etree.Element | None: """Helper-function for finding the relevant actuator xml-structure.""" locator = f"./actuator_functionalities/{actuator}" if (search := appliance.find(locator)) is not None: return search return None class SmileHelper(SmileCommon): """The SmileHelper class.""" def __init__(self) -> None: """Set the constructor for this class.""" super().__init__() self._endpoint: str self._elga: bool self._is_thermostat: bool self._last_active: dict[str, str | None] self._loc_data: dict[str, ThermoLoc] self._schedule_old_states: dict[str, dict[str, str]] self._gateway_id: str = NONE self._zones: dict[str, GwEntityData] self.gw_entities: dict[str, GwEntityData] self.smile_hw_version: str | None self.smile_mac_address: str | None self.smile_model: str self.smile_model_id: str | None self.smile_version: version.Version @property def gateway_id(self) -> str: """Return the gateway-id.""" return self._gateway_id @property def item_count(self) -> int: """Return the item-count.""" return self._count def _all_appliances(self) -> None: """Collect all appliances with relevant info. Also, collect the P1 smartmeter info from a location as this one is not available as an appliance. """ self._count = 0 self._all_locations() for appliance in self._domain_objects.findall("./appliance"): appl = Munch() appl.pwclass = appliance.find("type").text # Don't collect data for the OpenThermGateway appliance if appl.pwclass == "open_therm_gateway": continue # Extend device_class name of Plugs (Plugwise and Aqara) - Pw-Beta Issue #739 description = appliance.find("description").text if description is not None and ( "ZigBee protocol" in description or "smart plug" in description ): appl.pwclass = f"{appl.pwclass}_plug" # Skip thermostats that have this key, should be an orphaned device (Core #81712) if ( appl.pwclass == "thermostat" and appliance.find("actuator_functionalities/") is None ): continue appl.location = None if (appl_loc := appliance.find("location")) is not None: appl.location = appl_loc.attrib["id"] # Don't assign the _home_loc_id to thermostat-devices without a location, # they are not active elif appl.pwclass not in THERMOSTAT_CLASSES: appl.location = self._home_loc_id # Don't show orphaned thermostat-types if appl.pwclass in THERMOSTAT_CLASSES and appl.location is None: continue appl.available = None appl.entity_id = appliance.attrib["id"] appl.name = appliance.find("name").text appl.model = None appl.model_id = None appl.firmware = None appl.hardware = None appl.mac = None appl.zigbee_mac = None appl.vendor_name = None # Collect appliance info, skip orphaned/removed devices if not (appl := self._appliance_info_finder(appl, appliance)): continue self._create_gw_entities(appl) if self.smile_type == "power": self._get_p1_smartmeter_info() # Sort the gw_entities self._sort_gw_entities() def _get_p1_smartmeter_info(self) -> None: """For P1 collect the connected SmartMeter info from the Home/building location. Note: For P1, the entity_id for the gateway and smartmeter are switched to maintain backward compatibility with existing implementations. """ appl = Munch() locator = MODULE_LOCATOR module_data = self._get_module_data(self._home_location, locator) if not module_data["contents"]: LOGGER.error("No module data found for SmartMeter") # pragma: no cover return # pragma: no cover appl.available = None appl.entity_id = self._gateway_id appl.firmware = module_data["firmware_version"] appl.hardware = module_data["hardware_version"] appl.location = self._home_loc_id appl.mac = None appl.model = module_data["vendor_model"] appl.model_id = None # don't use model_id for SmartMeter appl.name = "P1" appl.pwclass = "smartmeter" appl.vendor_name = module_data["vendor_name"] appl.zigbee_mac = None # Replace the entity_id of the gateway by the smartmeter location_id self.gw_entities[self._home_loc_id] = self.gw_entities.pop(self._gateway_id) self._gateway_id = self._home_loc_id self._create_gw_entities(appl) def _sort_gw_entities(self) -> None: """Place the gateway and optional heater_central entities as 1st and 2nd.""" for dev_class in PRIORITY_DEVICE_CLASSES: for entity_id, entity in dict(self.gw_entities).items(): if entity["dev_class"] == dev_class: priority_entity = entity self.gw_entities.pop(entity_id) other_entities = self.gw_entities priority_entities = {entity_id: priority_entity} self.gw_entities = {**priority_entities, **other_entities} break def _all_locations(self) -> None: """Collect all locations.""" loc = Munch() locations = self._domain_objects.findall("./location") for location in locations: loc.name = location.find("name").text loc.loc_id = location.attrib["id"] self._loc_data[loc.loc_id] = {"name": loc.name} if loc.name != "Home": continue self._home_loc_id = loc.loc_id self._home_location = self._domain_objects.find( f"./location[@id='{loc.loc_id}']" ) def _appliance_info_finder(self, appl: Munch, appliance: etree.Element) -> Munch: """Collect info for all appliances found.""" match appl.pwclass: case "gateway": # Collect gateway entity info return self._appl_gateway_info(appl, appliance) case _ as dev_class if dev_class in THERMOSTAT_CLASSES: # Collect thermostat entity info return self._appl_thermostat_info(appl, appliance) case "heater_central": # Collect heater_central entity info self._appl_heater_central_info( appl, appliance, False ) # False means non-legacy entity self._dhw_allowed_modes = self._get_appl_actuator_modes( appliance, "domestic_hot_water_mode_control_functionality" ) # Skip orphaned heater_central (Core Issue #104433) if appl.entity_id != self.heater_id: return Munch() return appl case _ as s if s.endswith("_plug"): # Collect info from plug-types (Plug, Aqara Smart Plug) locator = MODULE_LOCATOR module_data = self._get_module_data(appliance, locator) # A plug without module-data is orphaned/ no present if not module_data["contents"]: return Munch() appl.available = module_data["reachable"] appl.firmware = module_data["firmware_version"] appl.hardware = module_data["hardware_version"] appl.model_id = module_data["vendor_model"] appl.vendor_name = module_data["vendor_name"] appl.model = check_model(appl.model_id, appl.vendor_name) appl.zigbee_mac = module_data["zigbee_mac_address"] return appl case _: # pragma: no cover return Munch() def _appl_gateway_info(self, appl: Munch, appliance: etree.Element) -> Munch: """Helper-function for _appliance_info_finder().""" self._gateway_id = appliance.attrib["id"] appl.firmware = str(self.smile_version) appl.hardware = self.smile_hw_version appl.mac = self.smile_mac_address appl.model = self.smile_model appl.model_id = self.smile_model_id appl.name = self.smile_name appl.vendor_name = "Plugwise" # Adam: collect the ZigBee MAC address of the Smile if self.smile(ADAM): if ( found := self._domain_objects.find(".//protocols/zig_bee_coordinator") ) is not None: appl.zigbee_mac = found.find("mac_address").text # Also, collect regulation_modes and check for cooling, indicating cooling-mode is present self._reg_allowed_modes = self._get_appl_actuator_modes( appliance, "regulation_mode_control_functionality" ) # Finally, collect the gateway_modes self._gw_allowed_modes = [] locator = "./actuator_functionalities/gateway_mode_control_functionality[type='gateway_mode']/allowed_modes" if appliance.find(locator) is not None: # Limit the possible gateway-modes self._gw_allowed_modes = ["away", "full", "vacation"] return appl def _get_appl_actuator_modes( self, appliance: etree.Element, actuator_type: str ) -> list[str]: """Get allowed modes for the given actuator type.""" mode_list: list[str] = [] if ( search := search_actuator_functionalities(appliance, actuator_type) ) is not None and (modes := search.find("allowed_modes")) is not None: for mode in modes: mode_list.append(mode.text) return mode_list def _get_appliances_with_offset_functionality(self) -> list[str]: """Helper-function collecting all appliance that have offset_functionality.""" therm_list: list[str] = [] offset_appls = self._domain_objects.findall( './/actuator_functionalities/offset_functionality[type="temperature_offset"]/offset/../../..' ) for item in offset_appls: therm_list.append(item.attrib["id"]) return therm_list def _get_zone_data(self, loc_id: str) -> GwEntityData: """Helper-function for smile.py: _get_entity_data(). Collect the location-data based on location id. """ data: GwEntityData = {"sensors": {}} zone = self._zones[loc_id] measurements = ZONE_MEASUREMENTS if ( location := self._domain_objects.find(f'./location[@id="{loc_id}"]') ) is not None: self._appliance_measurements(location, data, measurements) self._get_actuator_functionalities(location, zone, data) return data def _get_measurement_data(self, entity_id: str) -> GwEntityData: """Helper-function for smile.py: _get_entity_data(). Collect the appliance-data based on entity_id. """ data: GwEntityData = {"binary_sensors": {}, "sensors": {}, "switches": {}} # Get P1 smartmeter data from LOCATIONS entity = self.gw_entities[entity_id] # !! DON'T CHANGE below two if-lines, will break stuff !! if self.smile_type == "power": if entity["dev_class"] == "smartmeter": data.update(self._power_data_from_location()) return data # Get non-P1 data from APPLIANCES measurements = DEVICE_MEASUREMENTS if self._is_thermostat and entity_id == self.heater_id: measurements = HEATER_CENTRAL_MEASUREMENTS # Show the allowed dhw_modes (Loria only) if self._dhw_allowed_modes: data["dhw_modes"] = self._dhw_allowed_modes # Counting of this item is done in _appliance_measurements() if ( appliance := self._domain_objects.find(f'./appliance[@id="{entity_id}"]') ) is not None: self._appliance_measurements(appliance, data, measurements) self._get_lock_state(appliance, data) for toggle, name in TOGGLES.items(): self._get_toggle_state(appliance, toggle, name, data) if appliance.find("type").text in ACTUATOR_CLASSES: self._get_actuator_functionalities(appliance, entity, data) self._get_regulation_mode(appliance, entity_id, data) self._get_gateway_mode(appliance, entity_id, data) self._get_gateway_outdoor_temp(entity_id, data) if "c_heating_state" in data: self._process_c_heating_state(data) # Remove c_heating_state after processing data.pop("c_heating_state") self._count -= 1 if self._is_thermostat and self.smile(ANNA): self._update_anna_cooling(entity_id, data) self._cleanup_data(data) return data def _power_data_from_location(self) -> GwEntityData: """Helper-function for smile.py: _get_entity_data(). Collect the power-data from the Home location. """ data: GwEntityData = {"sensors": {}} loc = Munch() log_list: list[str] = ["point_log", "cumulative_log", "interval_log"] t_string = "tariff" loc.logs = self._home_location.find("./logs") for loc.measurement, loc.attrs in P1_MEASUREMENTS.items(): for loc.log_type in log_list: collect_power_values(data, loc, t_string) self._count += len(data["sensors"]) return data def _appliance_measurements( self, appliance: etree.Element, data: GwEntityData, measurements: dict[str, DATA | UOM], ) -> None: """Helper-function for _get_measurement_data() - collect appliance measurement data.""" for measurement, attrs in measurements.items(): p_locator = f'.//logs/point_log[type="{measurement}"]/period/measurement' if (appl_p_loc := appliance.find(p_locator)) is not None: if skip_obsolete_measurements(appliance, measurement): continue if new_name := getattr(attrs, ATTR_NAME, None): measurement = new_name match measurement: case "elga_status_code": data["elga_status_code"] = int(appl_p_loc.text) case "select_dhw_mode": data["select_dhw_mode"] = appl_p_loc.text common_match_cases(measurement, attrs, appl_p_loc, data) i_locator = f'.//logs/interval_log[type="{measurement}"]/period/measurement' if (appl_i_loc := appliance.find(i_locator)) is not None: name = cast(SensorType, f"{measurement}_interval") data["sensors"][name] = format_measure( appl_i_loc.text, ENERGY_WATT_HOUR ) self._count = count_data_items(self._count, data) def _get_toggle_state( self, xml: etree.Element, toggle: str, name: ToggleNameType, data: GwEntityData ) -> None: """Helper-function for _get_measurement_data(). Obtain the toggle state of a 'toggle' = switch. """ if xml.find("type").text == "heater_central": locator = f"./actuator_functionalities/toggle_functionality[type='{toggle}']/state" if (state := xml.find(locator)) is not None: data["switches"][name] = state.text == "on" self._count += 1 def _get_plugwise_notifications(self) -> None: """Collect the Plugwise notifications.""" self._notifications = {} for notification in self._domain_objects.findall("./notification"): try: msg_id = notification.attrib["id"] msg_type = notification.find("type").text msg = notification.find("message").text self._notifications[msg_id] = {msg_type: msg} LOGGER.debug("Plugwise notifications: %s", self._notifications) except AttributeError: # pragma: no cover LOGGER.debug( "Plugwise notification present but unable to process, manually investigate: %s", f"{self._endpoint}{DOMAIN_OBJECTS}", ) def _get_actuator_functionalities( self, xml: etree.Element, entity: GwEntityData, data: GwEntityData ) -> None: """Get and process the actuator_functionalities details for an entity. Add the resulting dict(s) to the entity's data. """ for item in ACTIVE_ACTUATORS: # Skip max_dhw_temperature, not initially valid, # skip thermostat for all but zones with thermostats if item == "max_dhw_temperature" or ( item == "thermostat" and ( entity["dev_class"] != "climate" if self.smile(ADAM) else entity["dev_class"] != "thermostat" ) ): continue temp_dict: ActuatorData = {} functionality = "thermostat_functionality" if item == "temperature_offset": functionality = "offset_functionality" # When there is no updated_date-text, skip the actuator updated_date_location = f'.//actuator_functionalities/{functionality}[type="{item}"]/updated_date' if ( updated_date_key := xml.find(updated_date_location) ) is not None and updated_date_key.text is None: continue for key in LIMITS: locator = ( f'.//actuator_functionalities/{functionality}[type="{item}"]/{key}' ) if (pw_function := xml.find(locator)) is not None: if key == "offset": # Add limits and resolution for temperature_offset, # not provided by Plugwise in the XML data temp_dict["lower_bound"] = -2.0 temp_dict["resolution"] = 0.1 temp_dict["upper_bound"] = 2.0 self._count += 3 # Rename offset to setpoint key = "setpoint" act_key = cast(ActuatorDataType, key) temp_dict[act_key] = format_measure(pw_function.text, TEMP_CELSIUS) self._count += 1 if temp_dict: # If domestic_hot_water_setpoint is present as actuator, # rename and remove as sensor if item == DHW_SETPOINT: item = "max_dhw_temperature" if DHW_SETPOINT in data["sensors"]: data["sensors"].pop(DHW_SETPOINT) self._count -= 1 act_item = cast(ActuatorType, item) data[act_item] = temp_dict def _get_actuator_mode( self, appliance: etree.Element, entity_id: str, key: str ) -> str | None: """Helper-function for _get_regulation_mode and _get_gateway_mode. Collect the requested gateway mode. """ if not (self.smile(ADAM) and entity_id == self._gateway_id): return None if (search := search_actuator_functionalities(appliance, key)) is not None: return str(search.find("mode").text) return None def _get_regulation_mode( self, appliance: etree.Element, entity_id: str, data: GwEntityData ) -> None: """Helper-function for _get_measurement_data(). Adam: collect the gateway regulation_mode. """ if ( mode := self._get_actuator_mode( appliance, entity_id, "regulation_mode_control_functionality" ) ) is not None: data["select_regulation_mode"] = mode self._count += 1 self._cooling_enabled = mode == "cooling" def _get_gateway_mode( self, appliance: etree.Element, entity_id: str, data: GwEntityData ) -> None: """Helper-function for _get_measurement_data(). Adam: collect the gateway mode. """ if ( mode := self._get_actuator_mode( appliance, entity_id, "gateway_mode_control_functionality" ) ) is not None: data["select_gateway_mode"] = mode self._count += 1 def _get_gateway_outdoor_temp(self, entity_id: str, data: GwEntityData) -> None: """Adam & Anna: the Smile outdoor_temperature is present in the Home location.""" if self._is_thermostat and entity_id == self._gateway_id: locator = "./logs/point_log[type='outdoor_temperature']/period/measurement" if (found := self._home_location.find(locator)) is not None: value = format_measure(found.text, NONE) data.update({"sensors": {"outdoor_temperature": value}}) self._count += 1 def _process_c_heating_state(self, data: GwEntityData) -> None: """Helper-function for _get_measurement_data(). Process the central_heating_state value. """ # Adam or Anna + OnOff device if self._on_off_device: self._process_on_off_device_c_heating_state(data) # Anna + Elga: use central_heating_state to show heating_state if self._elga: data["binary_sensors"]["heating_state"] = data["c_heating_state"] def _process_on_off_device_c_heating_state(self, data: GwEntityData) -> None: """Adam or Anna + OnOff device - use central_heating_state to show heating/cooling_state. Solution for Core issue #81839. """ if self.smile(ANNA): data["binary_sensors"]["heating_state"] = data["c_heating_state"] if self.smile(ADAM): # First count when not present, then create and init to False. # When present init to False if "heating_state" not in data["binary_sensors"]: self._count += 1 data["binary_sensors"]["heating_state"] = False if "cooling_state" not in data["binary_sensors"]: self._count += 1 data["binary_sensors"]["cooling_state"] = False if self._cooling_enabled: data["binary_sensors"]["cooling_state"] = data["c_heating_state"] else: data["binary_sensors"]["heating_state"] = data["c_heating_state"] def _update_anna_cooling(self, entity_id: str, data: GwEntityData) -> None: """Update the Anna heater_central entity for cooling. Support added for Techneco Elga and Thercon Loria/Thermastage. """ if entity_id != self.heater_id: return if "elga_status_code" in data: self._update_elga_cooling(data) elif self._cooling_present and "cooling_state" in data["binary_sensors"]: self._update_loria_cooling(data) def _update_elga_cooling(self, data: GwEntityData) -> None: """# Anna+Elga: base cooling_state on the elga-status-code. For Elga, 'elga_status_code' in (8, 9) means cooling is enabled. 'elga_status_code' = 8 means cooling is active, 9 means idle. """ if data["thermostat_supports_cooling"]: # Techneco Elga has cooling-capability self._cooling_present = True data["model"] = "Generic heater/cooler" # Cooling_enabled in xml does NOT show the correct status! # Setting it specifically: self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data[ "elga_status_code" ] in (8, 9) data["binary_sensors"]["cooling_state"] = self._cooling_active = ( data["elga_status_code"] == 8 ) # Elga has no cooling-switch if "cooling_ena_switch" in data["switches"]: data["switches"].pop("cooling_ena_switch") self._count -= 1 data.pop("elga_status_code", None) self._count -= 1 def _update_loria_cooling(self, data: GwEntityData) -> None: """Loria/Thermastage: base cooling-related on cooling_state and modulation_level. For the Loria or Thermastage heatpump connected to an Anna cooling-enabled is indicated via the Cooling Enable switch in the Plugwise App. """ # For Loria/Thermastage it's not clear if cooling_enabled in xml shows the correct status, # setting it specifically: self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data[ "binary_sensors" ]["cooling_state"] self._cooling_active = data["sensors"]["modulation_level"] == 100 # For Loria the above does not work (pw-beta issue #301) if "cooling_ena_switch" in data["switches"]: self._cooling_enabled = data["binary_sensors"]["cooling_enabled"] = data[ "switches" ]["cooling_ena_switch"] self._cooling_active = data["binary_sensors"]["cooling_state"] def _cleanup_data(self, data: GwEntityData) -> None: """Helper-function for _get_measurement_data(). Clean up the data dict. """ # Don't show cooling-related when no cooling present, # but, keep cooling_enabled for Elga if not self._cooling_present: if "cooling_state" in data["binary_sensors"]: data["binary_sensors"].pop("cooling_state") self._count -= 1 if "cooling_ena_switch" in data["switches"]: data["switches"].pop("cooling_ena_switch") # pragma: no cover self._count -= 1 # pragma: no cover if "cooling_enabled" in data["binary_sensors"]: data["binary_sensors"].pop("cooling_enabled") # pragma: no cover self._count -= 1 # pragma: no cover if "thermostat_supports_cooling" in data: data.pop("thermostat_supports_cooling", None) self._count -= 1 def _scan_thermostats(self) -> None: """Helper-function for smile.py: get_all_entities(). Update locations with thermostat ranking results and use the result to update the device_class of secondary thermostats. """ self._thermo_locs = self._match_locations() thermo_matching: dict[str, int] = { "thermostat": 2, "zone_thermometer": 2, "zone_thermostat": 2, "thermostatic_radiator_valve": 1, } for loc_id in self._thermo_locs: for entity_id, entity in self.gw_entities.items(): self._rank_thermostat(thermo_matching, loc_id, entity_id, entity) for loc_id, loc_data in list(self._thermo_locs.items()): if loc_data["primary_prio"] != 0: self._zones[loc_id] = { "dev_class": "climate", "model": "ThermoZone", "name": loc_data["name"], "thermostats": { "primary": loc_data["primary"], "secondary": loc_data["secondary"], }, "vendor": "Plugwise", } self._count += 3 def _match_locations(self) -> dict[str, ThermoLoc]: """Helper-function for _scan_thermostats(). Match appliances with locations. """ matched_locations: dict[str, ThermoLoc] = {} for location_id, location_details in self._loc_data.items(): for appliance_details in self.gw_entities.values(): if appliance_details["location"] == location_id: location_details.update( {"primary": [], "primary_prio": 0, "secondary": []} ) matched_locations[location_id] = location_details return matched_locations def _rank_thermostat( self, thermo_matching: dict[str, int], loc_id: str, appliance_id: str, appliance_details: GwEntityData, ) -> None: """Helper-function for _scan_thermostats(). Rank the thermostat based on appliance_details: primary or secondary. Note: there can be several primary and secondary thermostats. """ appl_class = appliance_details["dev_class"] appl_d_loc = appliance_details["location"] thermo_loc = self._thermo_locs[loc_id] if loc_id == appl_d_loc and appl_class in thermo_matching: if thermo_matching[appl_class] == thermo_loc["primary_prio"]: thermo_loc["primary"].append(appliance_id) # Pre-elect new primary elif (thermo_rank := thermo_matching[appl_class]) > thermo_loc[ "primary_prio" ]: thermo_loc["primary_prio"] = thermo_rank # Demote former primary if tl_primary := thermo_loc["primary"]: thermo_loc["secondary"] += tl_primary thermo_loc["primary"] = [] # Crown primary thermo_loc["primary"].append(appliance_id) else: thermo_loc["secondary"].append(appliance_id) def _control_state(self, data: GwEntityData, loc_id: str) -> str | bool: """Helper-function for _get_adam_data(). Adam: find the thermostat control_state of a location, from DOMAIN_OBJECTS. Represents the heating/cooling demand-state of the local primary thermostat. Note: heating or cooling can still be active when the setpoint has been reached. """ locator = f'location[@id="{loc_id}"]/actuator_functionalities/thermostat_functionality[type="thermostat"]/control_state' if (ctrl_state := self._domain_objects.find(locator)) is not None: return str(ctrl_state.text) # Handle missing control_state in regulation_mode off for firmware >= 3.2.0 (issue #776) # In newer firmware versions, default to "off" when control_state is not present if self.smile_version != version.Version("0.0.0"): if self.smile_version >= version.parse("3.2.0"): return "off" # Older Adam firmware does not have the control_state xml-key # Work around this by comparing the reported temperature and setpoint for a location setpoint = data["sensors"]["setpoint"] temperature = data["sensors"]["temperature"] # No cooling available in older firmware return "heating" if temperature < setpoint else "off" return False # pragma: no cover def _heating_valves(self) -> int | bool: """Helper-function for smile.py: _get_adam_data(). Collect amount of open valves indicating active direct heating. For cases where the heat is provided from an external shared source (city heating). """ loc_found: int = 0 open_valve_count: int = 0 for appliance in self._domain_objects.findall("./appliance"): locator = './logs/point_log[type="valve_position"]/period/measurement' if (appl_loc := appliance.find(locator)) is not None: loc_found += 1 if float(appl_loc.text) > 0.0: open_valve_count += 1 return False if loc_found == 0 else open_valve_count def _preset(self, loc_id: str) -> str | None: """Helper-function for smile.py: device_data_climate(). Collect the active preset based on Location ID. """ locator = f'./location[@id="{loc_id}"]/preset' if (preset := self._domain_objects.find(locator)) is not None: return str(preset.text) return None # pragma: no cover def _presets(self, loc_id: str) -> dict[str, list[float]]: """Collect Presets for a Thermostat based on location_id.""" presets: dict[str, list[float]] = {} tag_1 = "zone_setpoint_and_state_based_on_preset" tag_2 = "Thermostat presets" if not (rule_ids := self._rule_ids_by_tag(tag_1, loc_id)): if not (rule_ids := self._rule_ids_by_name(tag_2, loc_id)): return presets # pragma: no cover for rule_id in rule_ids: directives = self._domain_objects.find(f'rule[@id="{rule_id}"]/directives') for directive in directives: preset = directive.find("then").attrib presets[directive.attrib["preset"]] = [ float(preset["heating_setpoint"]), float(preset["cooling_setpoint"]), ] return presets def _rule_ids_by_name(self, name: str, loc_id: str) -> dict[str, dict[str, str]]: """Helper-function for _presets(). Obtain the rule_id from the given name and and provide the location_id, when present. """ schedule_ids: dict[str, dict[str, str]] = {} locator = f'./contexts/context/zone/location[@id="{loc_id}"]' for rule in self._domain_objects.findall(f'./rule[name="{name}"]'): active = rule.find("active").text if rule.find(locator) is not None: schedule_ids[rule.attrib["id"]] = { "location": loc_id, "name": name, "active": active, } else: schedule_ids[rule.attrib["id"]] = { "location": NONE, "name": name, "active": active, } return schedule_ids def _rule_ids_by_tag(self, tag: str, loc_id: str) -> dict[str, dict[str, str]]: """Helper-function for _presets(), _schedules() and _last_active_schedule(). Obtain the rule_id from the given template_tag and provide the location_id, when present. """ schedule_ids: dict[str, dict[str, str]] = {} locator1 = f'./template[@tag="{tag}"]' locator2 = f'./contexts/context/zone/location[@id="{loc_id}"]' for rule in self._domain_objects.findall("./rule"): if rule.find(locator1) is not None: name = rule.find("name").text active = rule.find("active").text if rule.find(locator2) is not None: schedule_ids[rule.attrib["id"]] = { "location": loc_id, "name": name, "active": active, } else: schedule_ids[rule.attrib["id"]] = { "location": NONE, "name": name, "active": active, } return schedule_ids def _schedules(self, location: str) -> tuple[list[str], str]: """Helper-function for smile.py: _climate_data(). Obtain the available schedules/schedules. Adam: a schedule can be connected to more than one location. NEW: when a location_id is present then the schedule is active. Valid for both Adam and non-legacy Anna. """ available: list[str] = [NONE] rule_ids: dict[str, dict[str, str]] = {} selected = NONE # Adam schedules, one schedule can be linked to various locations # self._last_active contains the locations and the active schedule name per location, or None if location not in self._last_active: self._last_active[location] = None tag = "zone_preset_based_on_time_and_presence_with_override" if not (rule_ids := self._rule_ids_by_tag(tag, location)): return available, selected schedules: list[str] = [] for rule_id, data in rule_ids.items(): active = data["active"] == "true" name = data["name"] locator = f'./rule[@id="{rule_id}"]/directives' # Show an empty schedule as no schedule found if self._domain_objects.find(locator) is None: continue # pragma: no cover available.append(name) if location == data["location"] and active: selected = name self._last_active[location] = selected schedules.append(name) if schedules: available.remove(NONE) available.append(OFF) if selected == NONE: selected = OFF if self._last_active.get(location) is None: self._last_active[location] = self._last_used_schedule(schedules) return available, selected def _last_used_schedule(self, schedules: list[str]) -> str: """Helper-function for _schedules(). Determine the last-used schedule based on the modified date. """ epoch = dt.datetime(1970, 1, 1, tzinfo=tz.tzutc()) schedules_dates: dict[str, float] = {} for name in schedules: result = self._domain_objects.find(f'./rule[name="{name}"]') schedule_date = result.find("modified_date").text schedule_time = parse(schedule_date) schedules_dates[name] = (schedule_time - epoch).total_seconds() return sorted(schedules_dates.items(), key=lambda kv: kv[1])[-1][0] def _thermostat_uri(self, loc_id: str) -> str: """Helper-function for smile.py: set_temperature(). Determine the location-set_temperature uri - from LOCATIONS. """ locator = f'./location[@id="{loc_id}"]/actuator_functionalities/thermostat_functionality' thermostat_functionality_id = self._domain_objects.find(locator).attrib["id"] return f"{LOCATIONS};id={loc_id}/thermostat;id={thermostat_functionality_id}" python-plugwise-1.7.3/plugwise/legacy/000077500000000000000000000000001475766476500200365ustar00rootroot00000000000000python-plugwise-1.7.3/plugwise/legacy/data.py000066400000000000000000000061111475766476500213200ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise Smile protocol data-collection helpers for legacy devices. """ from __future__ import annotations # Dict as class # Version detection from plugwise.constants import NONE, OFF, GwEntityData from plugwise.legacy.helper import SmileLegacyHelper from plugwise.util import remove_empty_platform_dicts class SmileLegacyData(SmileLegacyHelper): """The Plugwise Smile main class.""" def _all_entity_data(self) -> None: """Helper-function for get_all_gateway_entities(). Collect data for each entity and add to self.gw_entities. """ self._update_gw_entities() def _update_gw_entities(self) -> None: """Helper-function for _all_entity_data() and async_update(). Collect data for each entity and add to self.gw_entities. """ for entity_id, entity in self.gw_entities.items(): data = self._get_entity_data(entity_id) entity.update(data) remove_empty_platform_dicts(entity) def _get_entity_data(self, entity_id: str) -> GwEntityData: """Helper-function for _all_entity_data() and async_update(). Provide entity-data, based on Location ID (= entity_id), from APPLIANCES. """ entity = self.gw_entities[entity_id] data = self._get_measurement_data(entity_id) # Switching groups data self._entity_switching_group(entity, data) # Skip obtaining data when not a thermostat if entity["dev_class"] != "thermostat": return data # Thermostat data (presets, temperatures etc) self._climate_data(entity, data) self._get_anna_control_state(data) return data def _climate_data(self, entity: GwEntityData, data: GwEntityData) -> None: """Helper-function for _get_entity_data(). Determine climate-control entity data. """ # Presets data["preset_modes"] = None data["active_preset"] = None self._count += 2 if presets := self._presets(): data["preset_modes"] = list(presets) data["active_preset"] = self._preset() # Schedule avail_schedules, sel_schedule = self._schedules() if avail_schedules != [NONE]: data["available_schedules"] = avail_schedules data["select_schedule"] = sel_schedule self._count += 2 # Set HA climate HVACMode: auto, heat data["climate_mode"] = "auto" self._count += 1 if sel_schedule in (NONE, OFF): data["climate_mode"] = "heat" def _get_anna_control_state(self, data: GwEntityData) -> None: """Set the thermostat control_state based on the opentherm/onoff device state.""" data["control_state"] = "idle" for entity in self.gw_entities.values(): if entity["dev_class"] != "heater_central": continue binary_sensors = entity["binary_sensors"] if binary_sensors["heating_state"]: data["control_state"] = "heating" python-plugwise-1.7.3/plugwise/legacy/helper.py000066400000000000000000000420111475766476500216650ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise Smile protocol helpers. """ from __future__ import annotations from typing import cast from plugwise.common import SmileCommon from plugwise.constants import ( ACTIVE_ACTUATORS, ACTUATOR_CLASSES, APPLIANCES, ATTR_NAME, DATA, DEVICE_MEASUREMENTS, ENERGY_WATT_HOUR, FAKE_APPL, FAKE_LOC, HEATER_CENTRAL_MEASUREMENTS, LIMITS, NONE, OFF, P1_LEGACY_MEASUREMENTS, PRIORITY_DEVICE_CLASSES, TEMP_CELSIUS, THERMOSTAT_CLASSES, UOM, ActuatorData, ActuatorDataType, ActuatorType, ApplianceType, GwEntityData, SensorType, ThermoLoc, ) from plugwise.util import ( collect_power_values, common_match_cases, count_data_items, format_measure, skip_obsolete_measurements, version_to_model, ) # This way of importing aiohttp is because of patch/mocking in testing (aiohttp timeouts) from defusedxml import ElementTree as etree from munch import Munch from packaging.version import Version def etree_to_dict(element: etree.Element) -> dict[str, str]: """Helper-function translating xml Element to dict.""" node: dict[str, str] = {} if element is not None: node.update(element.items()) return node class SmileLegacyHelper(SmileCommon): """The SmileLegacyHelper class.""" def __init__(self) -> None: """Set the constructor for this class.""" super().__init__() self._appliances: etree.Element self._gateway_id: str = NONE self._is_thermostat: bool self._loc_data: dict[str, ThermoLoc] self._locations: etree.Element self._modules: etree.Element self._stretch_v2: bool self.gw_entities: dict[str, GwEntityData] = {} self.smile_mac_address: str | None self.smile_model: str self.smile_version: Version self.smile_zigbee_mac_address: str | None @property def gateway_id(self) -> str: """Return the gateway-id.""" return self._gateway_id @property def item_count(self) -> int: """Return the item-count.""" return self._count def _all_appliances(self) -> None: """Collect all appliances with relevant info.""" self._count = 0 self._all_locations() self._create_legacy_gateway() # For legacy P1 collect the connected SmartMeter info if self.smile_type == "power": appl = Munch() self._p1_smartmeter_info_finder(appl) # Legacy P1 has no more devices return for appliance in self._appliances.findall("./appliance"): appl = Munch() appl.pwclass = appliance.find("type").text # Skip thermostats that have this key, should be an orphaned device (Core #81712) if ( appl.pwclass == "thermostat" and appliance.find("actuator_functionalities/") is None ): continue # pragma: no cover appl.location = self._home_loc_id appl.entity_id = appliance.attrib["id"] appl.name = appliance.find("name").text # Extend device_class name when a Circle/Stealth is type heater_central -- Pw-Beta Issue #739 if ( appl.pwclass == "heater_central" and appl.name != "Central heating boiler" ): appl.pwclass = "heater_central_plug" appl.model = appl.pwclass.replace("_", " ").title() appl.available = None appl.model_id = None appl.firmware = None appl.hardware = None appl.mac = None appl.zigbee_mac = None appl.vendor_name = None # Determine class for this appliance # Skip on heater_central when no active device present or on orphaned stretch devices if not (appl := self._appliance_info_finder(appliance, appl)): continue # Skip orphaned heater_central (Core Issue #104433) if appl.pwclass == "heater_central" and appl.entity_id != self.heater_id: continue # pragma: no cover self._create_gw_entities(appl) # Place the gateway and optional heater_central devices as 1st and 2nd for dev_class in PRIORITY_DEVICE_CLASSES: for entity_id, entity in dict(self.gw_entities).items(): if entity["dev_class"] == dev_class: tmp_entity = entity self.gw_entities.pop(entity_id) cleared_dict = self.gw_entities add_to_front = {entity_id: tmp_entity} self.gw_entities = {**add_to_front, **cleared_dict} break def _all_locations(self) -> None: """Collect all locations.""" loc = Munch() # Legacy Anna without outdoor_temp and Stretches have no locations, create fake location-data if not (locations := self._locations.findall("./location")): self._home_loc_id = FAKE_LOC self._loc_data[FAKE_LOC] = {"name": "Home"} return for location in locations: loc.name = location.find("name").text loc.loc_id = location.attrib["id"] # Filter the valid single location for P1 legacy: services not empty locator = "./services" if self.smile_type == "power" and len(location.find(locator)) == 0: continue if loc.name == "Home": self._home_loc_id = loc.loc_id # Replace location-name for P1 legacy, can contain privacy-related info if self.smile_type == "power": loc.name = "Home" self._home_loc_id = loc.loc_id self._loc_data[loc.loc_id] = {"name": loc.name} def _create_legacy_gateway(self) -> None: """Create the (missing) gateway entities for legacy Anna, P1 and Stretch. Use the home_location or FAKE_APPL as entity id. """ self._gateway_id = self._home_loc_id if self.smile_type == "power": self._gateway_id = FAKE_APPL self.gw_entities[self._gateway_id] = {"dev_class": "gateway"} self._count += 1 for key, value in { "firmware": str(self.smile_version), "location": self._home_loc_id, "mac_address": self.smile_mac_address, "model": self.smile_model, "name": self.smile_name, "zigbee_mac_address": self.smile_zigbee_mac_address, "vendor": "Plugwise", }.items(): if value is not None: gw_key = cast(ApplianceType, key) self.gw_entities[self._gateway_id][gw_key] = value self._count += 1 def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch: """Collect entity info (Smile/Stretch, Thermostats, OpenTherm/On-Off): firmware, model and vendor name.""" match appl.pwclass: # Collect thermostat entity info case _ as dev_class if dev_class in THERMOSTAT_CLASSES: return self._appl_thermostat_info(appl, appliance, self._modules) # Collect heater_central entity info case "heater_central": return self._appl_heater_central_info( appl, appliance, True, self._appliances, self._modules ) # True means legacy device # Collect info from Stretches case _: return self._energy_entity_info_finder(appliance, appl) def _energy_entity_info_finder(self, appliance: etree, appl: Munch) -> Munch: """Helper-function for _appliance_info_finder(). Collect energy entity info (Smartmeter, Circle, Stealth, etc.): firmware, model and vendor name. """ if self.smile_type in ("power", "stretch"): locator = "./services/electricity_point_meter" module_data = self._get_module_data( appliance, locator, self._modules, legacy=True ) appl.zigbee_mac = module_data["zigbee_mac_address"] # Filter appliance without zigbee_mac, it's an orphaned device if appl.zigbee_mac is None and self.smile_type != "power": return None appl.hardware = module_data["hardware_version"] appl.model = module_data["vendor_model"] appl.vendor_name = module_data["vendor_name"] if appl.hardware is not None: hw_version = appl.hardware.replace("-", "") appl.model = version_to_model(hw_version) appl.firmware = module_data["firmware_version"] return appl return appl # pragma: no cover def _p1_smartmeter_info_finder(self, appl: Munch) -> None: """Collect P1 DSMR Smartmeter info.""" loc_id = next(iter(self._loc_data.keys())) appl.available = None appl.entity_id = loc_id appl.location = loc_id appl.mac = None appl.model = self.smile_model appl.model_id = None appl.name = "P1" appl.pwclass = "smartmeter" appl.zigbee_mac = None location = self._locations.find(f'./location[@id="{loc_id}"]') appl = self._energy_entity_info_finder(location, appl) self._create_gw_entities(appl) def _get_measurement_data(self, entity_id: str) -> GwEntityData: """Helper-function for smile.py: _get_entity_data(). Collect the appliance-data based on entity_id. """ data: GwEntityData = {"binary_sensors": {}, "sensors": {}, "switches": {}} # Get P1 smartmeter data from MODULES entity = self.gw_entities[entity_id] # !! DON'T CHANGE below two if-lines, will break stuff !! if self.smile_type == "power": if entity["dev_class"] == "smartmeter": data.update(self._power_data_from_modules()) return data measurements = DEVICE_MEASUREMENTS if self._is_thermostat and entity_id == self.heater_id: measurements = HEATER_CENTRAL_MEASUREMENTS if ( appliance := self._appliances.find(f'./appliance[@id="{entity_id}"]') ) is not None: self._appliance_measurements(appliance, data, measurements) self._get_lock_state(appliance, data, self._stretch_v2) if appliance.find("type").text in ACTUATOR_CLASSES: self._get_actuator_functionalities(appliance, entity, data) # Anna: the Smile outdoor_temperature is present in the Home location # For some Anna's LOCATIONS is empty, falling back to domain_objects! if self._is_thermostat and entity_id == self._gateway_id: locator = f"./location[@id='{self._home_loc_id}']/logs/point_log[type='outdoor_temperature']/period/measurement" if (found := self._domain_objects.find(locator)) is not None: value = format_measure(found.text, NONE) data.update({"sensors": {"outdoor_temperature": value}}) self._count += 1 if "c_heating_state" in data: data.pop("c_heating_state") self._count -= 1 return data def _power_data_from_modules(self) -> GwEntityData: """Helper-function for smile.py: _get_entity_data(). Collect the power-data from MODULES (P1 legacy only). """ data: GwEntityData = {"sensors": {}} loc = Munch() mod_list: list[str] = ["interval_meter", "cumulative_meter", "point_meter"] t_string = "tariff_indicator" search = self._modules mod_logs = search.findall("./module/services") for loc.measurement, loc.attrs in P1_LEGACY_MEASUREMENTS.items(): loc.meas_list = loc.measurement.partition("_")[0::2] for loc.logs in mod_logs: for loc.log_type in mod_list: collect_power_values(data, loc, t_string, legacy=True) self._count += len(data["sensors"]) return data def _appliance_measurements( self, appliance: etree.Element, data: GwEntityData, measurements: dict[str, DATA | UOM], ) -> None: """Helper-function for _get_measurement_data() - collect appliance measurement data.""" for measurement, attrs in measurements.items(): p_locator = f'.//logs/point_log[type="{measurement}"]/period/measurement' if (appl_p_loc := appliance.find(p_locator)) is not None: if measurement == "domestic_hot_water_state": continue if skip_obsolete_measurements(appliance, measurement): continue # pragma: no cover if new_name := getattr(attrs, ATTR_NAME, None): measurement = new_name common_match_cases(measurement, attrs, appl_p_loc, data) i_locator = f'.//logs/interval_log[type="{measurement}"]/period/measurement' if (appl_i_loc := appliance.find(i_locator)) is not None: name = cast(SensorType, f"{measurement}_interval") data["sensors"][name] = format_measure( appl_i_loc.text, ENERGY_WATT_HOUR ) self._count = count_data_items(self._count, data) def _get_actuator_functionalities( self, xml: etree.Element, entity: GwEntityData, data: GwEntityData ) -> None: """Helper-function for _get_measurement_data().""" for item in ACTIVE_ACTUATORS: # Skip max_dhw_temperature, not initially valid, # skip thermostat for thermo_sensors if item == "max_dhw_temperature" or ( item == "thermostat" and entity["dev_class"] == "thermo_sensor" ): continue temp_dict: ActuatorData = {} functionality = "thermostat_functionality" # When there is no updated_date-text, skip the actuator updated_date_location = f'.//actuator_functionalities/{functionality}[type="{item}"]/updated_date' if ( updated_date_key := xml.find(updated_date_location) ) is not None and updated_date_key.text is None: continue # pragma: no cover for key in LIMITS: locator = ( f'.//actuator_functionalities/{functionality}[type="{item}"]/{key}' ) if (pw_function := xml.find(locator)) is not None: act_key = cast(ActuatorDataType, key) temp_dict[act_key] = format_measure(pw_function.text, TEMP_CELSIUS) self._count += 1 if temp_dict: act_item = cast(ActuatorType, item) data[act_item] = temp_dict def _preset(self) -> str | None: """Helper-function for smile.py: _climate_data(). Collect the active preset based on the active rule. """ locator = "./rule[active='true']/directives/when/then" if ( not (active_rule := etree_to_dict(self._domain_objects.find(locator))) or "icon" not in active_rule ): return None return active_rule["icon"] def _presets(self) -> dict[str, list[float]]: """Helper-function for presets() - collect Presets for a legacy Anna.""" presets: dict[str, list[float]] = {} for directive in self._domain_objects.findall("rule/directives/when/then"): if directive is not None and directive.get("icon") is not None: # Ensure list of heating_setpoint, cooling_setpoint presets[directive.attrib["icon"]] = [ float(directive.attrib["temperature"]), 0, ] return presets def _schedules(self) -> tuple[list[str], str]: """Collect the schedule for the legacy thermostat.""" available: list[str] = [NONE] rule_id = selected = NONE name: str | None = None search = self._domain_objects if (result := search.find("./rule[name='Thermostat schedule']")) is not None: name = "Thermostat schedule" rule_id = result.attrib["id"] log_type = "schedule_state" locator = f"./appliance[type='thermostat']/logs/point_log[type='{log_type}']/period/measurement" active = False if (result := search.find(locator)) is not None: active = result.text == "on" # Show an empty schedule as no schedule found directives = ( search.find(f'./rule[@id="{rule_id}"]/directives/when/then') is not None ) if directives and name is not None: available = [name, OFF] selected = name if active else OFF return available, selected def _thermostat_uri(self) -> str: """Determine the location-set_temperature uri - from APPLIANCES.""" locator = "./appliance[type='thermostat']" appliance_id = self._appliances.find(locator).attrib["id"] return f"{APPLIANCES};id={appliance_id}/thermostat" python-plugwise-1.7.3/plugwise/legacy/smile.py000066400000000000000000000311031475766476500215170ustar00rootroot00000000000000"""Use of this source code is governed by the MIT license found in the LICENSE file. Plugwise backend module for Home Assistant Core - covering the legacy P1, Anna, and Stretch devices. """ from __future__ import annotations from collections.abc import Awaitable, Callable import datetime as dt from typing import Any from plugwise.constants import ( APPLIANCES, DOMAIN_OBJECTS, LOCATIONS, LOGGER, MODULES, OFF, REQUIRE_APPLIANCES, RULES, GwEntityData, ThermoLoc, ) from plugwise.exceptions import ConnectionFailedError, DataMissingError, PlugwiseError from plugwise.legacy.data import SmileLegacyData from munch import Munch from packaging.version import Version class SmileLegacyAPI(SmileLegacyData): """The Plugwise SmileLegacyAPI helper class for actual Plugwise legacy devices.""" # pylint: disable=too-many-instance-attributes, too-many-public-methods def __init__( self, _is_thermostat: bool, _loc_data: dict[str, ThermoLoc], _on_off_device: bool, _opentherm_device: bool, _request: Callable[..., Awaitable[Any]], _stretch_v2: bool, _target_smile: str, smile_hostname: str, smile_hw_version: str | None, smile_mac_address: str | None, smile_model: str, smile_name: str, smile_type: str, smile_version: Version, smile_zigbee_mac_address: str | None, ) -> None: """Set the constructor for this class.""" super().__init__() self._cooling_present = False self._is_thermostat = _is_thermostat self._loc_data = _loc_data self._on_off_device = _on_off_device self._opentherm_device = _opentherm_device self._request = _request self._stretch_v2 = _stretch_v2 self._target_smile = _target_smile self.smile_hostname = smile_hostname self.smile_hw_version = smile_hw_version self.smile_mac_address = smile_mac_address self.smile_model = smile_model self.smile_name = smile_name self.smile_type = smile_type self.smile_version = smile_version self.smile_zigbee_mac_address = smile_zigbee_mac_address self._first_update = True self._previous_day_number: str = "0" @property def cooling_present(self) -> bool: """Return the cooling capability.""" return False async def full_xml_update(self) -> None: """Perform a first fetch of the Plugwise server XML data.""" self._domain_objects = await self._request(DOMAIN_OBJECTS) self._locations = await self._request(LOCATIONS) self._modules = await self._request(MODULES) # P1 legacy has no appliances if self.smile_type != "power": self._appliances = await self._request(APPLIANCES) def get_all_gateway_entities(self) -> None: """Collect the Plugwise gateway entities and their data and states from the received raw XML-data. First, collect all the connected entities and their initial data. Collect and add switching- and/or pump-group entities. Finally, collect the data and states for each entity. """ self._all_appliances() if group_data := self._get_group_switches(): self.gw_entities.update(group_data) self._all_entity_data() async def async_update(self) -> dict[str, GwEntityData]: """Perform an full update update at day-change: re-collect all gateway entities and their data and states. Otherwise perform an incremental update: only collect the entities updated data and states. """ day_number = dt.datetime.now().strftime("%w") if self._first_update or day_number != self._previous_day_number: LOGGER.info( "Performing daily full-update, reload the Plugwise integration when a single entity becomes unavailable." ) try: await self.full_xml_update() self.get_all_gateway_entities() # Detect failed data-retrieval _ = self.gw_entities[self.gateway_id]["location"] except KeyError as err: # pragma: no cover raise DataMissingError( "No (full) Plugwise legacy data received" ) from err else: try: self._domain_objects = await self._request(DOMAIN_OBJECTS) match self._target_smile: case "smile_v2": self._modules = await self._request(MODULES) case self._target_smile if self._target_smile in REQUIRE_APPLIANCES: self._appliances = await self._request(APPLIANCES) self._update_gw_entities() # Detect failed data-retrieval _ = self.gw_entities[self.gateway_id]["location"] except KeyError as err: # pragma: no cover raise DataMissingError("No legacy Plugwise data received") from err self._first_update = False self._previous_day_number = day_number return self.gw_entities ######################################################################################################## ### API Set and HA Service-related Functions ### ######################################################################################################## async def delete_notification(self) -> None: """Set-function placeholder for legacy devices.""" async def reboot_gateway(self) -> None: """Set-function placeholder for legacy devices.""" async def set_dhw_mode(self, mode: str) -> None: """Set-function placeholder for legacy devices.""" async def set_gateway_mode(self, mode: str) -> None: """Set-function placeholder for legacy devices.""" async def set_number( self, dev_id: str, key: str, temperature: float, ) -> None: """Set-function placeholder for legacy devices.""" async def set_offset(self, dev_id: str, offset: float) -> None: """Set-function placeholder for legacy devices.""" async def set_preset(self, _: str, preset: str) -> None: """Set the given Preset on the relevant Thermostat - from DOMAIN_OBJECTS.""" if (presets := self._presets()) is None: raise PlugwiseError("Plugwise: no presets available.") # pragma: no cover if preset not in list(presets): raise PlugwiseError("Plugwise: invalid preset.") locator = f'rule/directives/when/then[@icon="{preset}"].../.../...' rule_id = self._domain_objects.find(locator).attrib["id"] data = f"true" await self.call_request(RULES, method="put", data=data) async def set_regulation_mode(self, mode: str) -> None: """Set-function placeholder for legacy devices.""" async def set_select( self, key: str, loc_id: str, option: str, state: str | None ) -> None: """Set the thermostat schedule option.""" # schedule name corresponds to select option await self.set_schedule_state("dummy", state, option) async def set_schedule_state( self, _: str, state: str | None, name: str | None ) -> None: """Activate/deactivate the Schedule. Determined from - DOMAIN_OBJECTS. Used in HA Core to set the hvac_mode: in practice switch between schedule on - off. """ if state not in ("on", "off"): raise PlugwiseError("Plugwise: invalid schedule state.") # Handle no schedule-name / Off-schedule provided if name is None or name == OFF: name = "Thermostat schedule" schedule_rule_id: str | None = None for rule in self._domain_objects.findall("rule"): if rule.find("name").text == name: schedule_rule_id = rule.attrib["id"] break if schedule_rule_id is None: raise PlugwiseError( "Plugwise: no schedule with this name available." ) # pragma: no cover new_state = "false" if state == "on": new_state = "true" locator = f'.//*[@id="{schedule_rule_id}"]/template' template_id = self._domain_objects.find(locator).attrib["id"] data = ( "" f"" f"" f"