pax_global_header00006660000000000000000000000064146611672740014530gustar00rootroot0000000000000052 comment=0ad4e667e2edcf30cd42f1cbfc6941e3a9ebfb8c jabesq-org-pyatmo-6216472/000077500000000000000000000000001466116727400152665ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/.devcontainer/000077500000000000000000000000001466116727400200255ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/.devcontainer/Dockerfile.dev000066400000000000000000000016061466116727400225770ustar00rootroot00000000000000ARG VARIANT="3.10" FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} as builder SHELL ["/bin/bash", "-o", "pipefail", "-c"] WORKDIR /workspaces COPY Pipfile ./ # Create Python requirements files from pipenv (lockfile) RUN pip3 install -U pip \ && pip3 install pipenv \ && pipenv lock \ && pipenv requirements > /tmp/requirements.txt \ && pipenv requirements --dev > /tmp/requirements_dev.txt FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} COPY --from=builder /tmp/requirements.txt /tmp/ COPY --from=builder /tmp/requirements_dev.txt /tmp/ # Install Python dependencies from requirements RUN pip3 install -r /tmp/requirements.txt \ && pip3 install pdbpp \ && pip3 install -r /tmp/requirements_dev.txt \ && rm -rf /tmp/requirements.txt /tmp/requirements_dev.txt pyatmo/ # Set the default shell to bash instead of sh ENV SHELL /bin/bash jabesq-org-pyatmo-6216472/.devcontainer/devcontainer.json000066400000000000000000000022561466116727400234060ustar00rootroot00000000000000{ "name": "pyatmo Dev", "context": "..", "dockerFile": "./Dockerfile.dev", "containerEnv": { "DEVCONTAINER": "1" }, "postCreateCommand": "pip3 install -e . && pre-commit run flake8", "runArgs": [ "-e", "GIT_EDITOR=code --wait" ], "extensions": [ "ms-python.vscode-pylance", "visualstudioexptteam.vscodeintellicode", ], "settings": { "python.pythonPath": "/usr/local/bin/python", "python.defaultInterpreterPath": "/user/local/bin/python", "python.linting.pylintEnabled": true, "python.linting.enabled": true, "python.formatting.provider": "black", "python.testing.pytestArgs": [ "--no-cov" ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "editor.formatOnPaste": false, "editor.formatOnSave": true, "editor.formatOnType": true, "files.trimTrailingWhitespace": true, "terminal.integrated.profiles.linux": { "zsh": { "path": "/usr/bin/zsh" } }, "terminal.integrated.defaultProfile.linux": "zsh", } } jabesq-org-pyatmo-6216472/.github/000077500000000000000000000000001466116727400166265ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/.github/dependabot.yml000066400000000000000000000013171466116727400214600ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: # Check for updates to GitHub Actions every weekday interval: "daily" - package-ecosystem: "pip" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" # Check for pip updates on Sundays day: "sunday" jabesq-org-pyatmo-6216472/.github/workflows/000077500000000000000000000000001466116727400206635ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/.github/workflows/publish-to-pypi.yml000066400000000000000000000017521466116727400244600ustar00rootroot00000000000000name: Publish 📦 to PyPI on: push: tags: - "v*" jobs: build-n-publish: name: Build and publish 📦 to PyPI runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python 3.10 uses: actions/setup-python@v5.1.1 with: python-version: 3.10.8 - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel build - name: Build a binary wheel and a source tarball run: >- python -m build . # - name: Publish 📦 to Test PyPI # uses: pypa/gh-action-pypi-publish@master # with: # password: ${{ secrets.PYPI_TEST_TOKEN }} # repository-url: https://test.pypi.org/legacy/ - name: Publish 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.pypi_prod_token }} jabesq-org-pyatmo-6216472/.github/workflows/publish-to-test-pypi.yml000066400000000000000000000015401466116727400254300ustar00rootroot00000000000000name: Publish 📦 to TestPyPI on: push: branches: - development jobs: build-n-publish: name: Build and publish 📦 to TestPyPI runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: development fetch-depth: 0 - name: Set up Python 3.10 uses: actions/setup-python@v5.1.1 with: python-version: 3.10.8 - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel build - name: Build a binary wheel and a source tarball run: >- python -m build . - name: Publish 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_TEST_TOKEN }} repository-url: https://test.pypi.org/legacy/ jabesq-org-pyatmo-6216472/.github/workflows/pythonpackage.yml000066400000000000000000000032761466116727400242530ustar00rootroot00000000000000name: Python package on: push: branches: - master - development pull_request: branches: - master - development jobs: black: runs-on: ubuntu-latest strategy: max-parallel: 1 matrix: python-version: [3.11.4] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5.1.1 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install black - name: Check with black run: | black --check --diff src/pyatmo/ tests/ linter: runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: python-version: [3.11.4] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5.1.1 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install ruff - name: Lint with ruff run: | ruff check src/pyatmo build: runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: python-version: [3.10.8, 3.11.4] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5.1.1 with: python-version: ${{ matrix.python-version }} - name: Run tests with tox run: | pip install tox tox-gh-actions tox jabesq-org-pyatmo-6216472/.github/workflows/release_gh.yml000066400000000000000000000025441466116727400235110ustar00rootroot00000000000000# This is a basic workflow to help you get started with Actions name: Create Github Release # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the development branch on: push: # Sequence of patterns matched against refs/tags tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest permissions: contents: write # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 with: fetch-depth: 0 # Runs a single command using the runners shell - name: Create a Release uses: actions/create-release@v1.1.4 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: # The name of the tag. This should come from the webhook payload, `github.GITHUB_REF` when a user pushes a new tag tag_name: ${{ github.ref }} # The name of the release. For example, `Release v1.0.1` release_name: Release ${{ github.ref }} jabesq-org-pyatmo-6216472/.gitignore000066400000000000000000000131441466116727400172610ustar00rootroot00000000000000 build/ dist/ **/pyatmo.egg-info/ *.pyc .DS_Store access.token cov.xml venv/ .venv # Created by https://www.gitignore.io/api/python,pycharm # Edit at https://www.gitignore.io/?templates=python,pycharm ### PyCharm ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### PyCharm Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 # *.iml # modules.xml # .idea/misc.xml # *.ipr # Sonarlint plugin .idea/**/sonarlint/ # SonarQube Plugin .idea/**/sonarIssues.xml # Markdown Navigator plugin .idea/**/markdown-navigator.xml .idea/**/markdown-navigator/ ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. Pipfile.lock # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # Mr Developer .mr.developer.cfg .project .pydevproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # End of https://www.gitignore.io/api/python,pycharm # Created by https://www.gitignore.io/api/code # Edit at https://www.gitignore.io/?templates=code ### Code ### .vscode/* # End of https://www.gitignore.io/api/code # Created by https://www.gitignore.io/api/jetbrains # Edit at https://www.gitignore.io/?templates=jetbrains ### JetBrains ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### JetBrains Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 # *.iml # modules.xml # .idea/misc.xml # *.ipr # Sonarlint plugin .idea/**/sonarlint/ # SonarQube Plugin .idea/**/sonarIssues.xml # Markdown Navigator plugin .idea/**/markdown-navigator.xml .idea/**/markdown-navigator/ # End of https://www.gitignore.io/api/jetbrains .idea __version__.py jabesq-org-pyatmo-6216472/.pre-commit-config.yaml000066400000000000000000000032661466116727400215560ustar00rootroot00000000000000# Note: don't use this config for your own repositories. Instead, see # "Version control integration" in README.md. default_stages: [commit, push] exclude: ^(fixtures/) repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.4.9 hooks: - id: ruff args: - --fix - repo: https://github.com/asottile/pyupgrade rev: v3.16.0 hooks: - id: pyupgrade args: [--py310-plus] exclude: "external_src/int-tools" - repo: https://github.com/asottile/add-trailing-comma rev: v3.1.0 hooks: - id: add-trailing-comma args: [--py36-plus] exclude: "external_src/int-tools" - repo: https://github.com/asottile/yesqa rev: v1.5.0 hooks: - id: yesqa - repo: https://github.com/psf/black rev: 24.4.2 hooks: - id: black language_version: python3 - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.10.0 hooks: - id: mypy name: mypy exclude: tests/ additional_dependencies: - types-requests - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 # Use the ref you want to point at hooks: - id: check-ast - id: no-commit-to-branch args: [--branch, master, --branch, devel] - id: forbid-new-submodules - id: check-merge-conflict - id: detect-private-key - id: end-of-file-fixer - id: mixed-line-ending args: [--fix=lf] - id: trailing-whitespace - id: debug-statements - id: check-toml - repo: https://github.com/asottile/setup-cfg-fmt rev: v2.5.0 hooks: - id: setup-cfg-fmt args: [--include-version-classifiers] jabesq-org-pyatmo-6216472/.tool-versions000066400000000000000000000000161466116727400201070ustar00rootroot00000000000000python 3.11.4 jabesq-org-pyatmo-6216472/.vscode/000077500000000000000000000000001466116727400166275ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/.vscode/tasks.json000066400000000000000000000046331466116727400206550ustar00rootroot00000000000000{ "version": "2.0.0", "tasks": [ { "label": "Pytest", "detail": "Run test suite with pytest", "type": "shell", "command": "pytest tests", "dependsOn": [ "Install all Test Requirements" ], "group": { "kind": "test", "isDefault": true }, "presentation": { "reveal": "always", "panel": "new" }, "problemMatcher": [] }, { "label": "Flake8", "detail": "Run flake8 style checker", "type": "shell", "command": "pre-commit run flake8 --all-files", "group": { "kind": "test", "isDefault": true }, "presentation": { "reveal": "always", "panel": "new" }, "problemMatcher": [] }, { "label": "Pylint", "detail": "Run pylint code analysis", "type": "shell", "command": "pylint pyatmo", "dependsOn": [ "Install all Requirements" ], "group": { "kind": "test", "isDefault": true }, "presentation": { "reveal": "always", "panel": "new" }, "problemMatcher": [] }, { "label": "Code Coverage", "detail": "Generate code coverage report", "type": "shell", "command": "pytest ./tests --cov=pyatmo --cov-report term-missing", "group": { "kind": "test", "isDefault": true }, "presentation": { "reveal": "always", "panel": "new" }, "problemMatcher": [] }, { "label": "Build wheel artifacts", "command": "rm -r dist; python -m build", "type": "shell", "options": { "cwd": "${workspaceRoot}/" }, "group": { "kind": "build", "isDefault": true }, "problemMatcher": [], "presentation": { "reveal": "always", "panel": "new" } } ] } jabesq-org-pyatmo-6216472/CHANGELOG.md000066400000000000000000000201761466116727400171050ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - ### Changed - ### Deprecated - ### Removed - ### Fixed - ### Security ## [8.1.0] ### Added - Expose camera person status - Add NLE support - Add proper energy support - Add cooler support - Add BNS support ## [8.0.3] ### Added - Add NLLF centralized ventilation controller ### Fixed - Add BNSC switch capability ## [8.0.3] ### Added - Add NLLF centralized ventilation controller ### Fixed - Add BNSC switch capability ## [8.0.2] ### Fixed - Duplicates in entity names (https://github.com/home-assistant/core/issues/88792) - Add shutter capabilities to BNAB, BNAS and BNMS (https://github.com/home-assistant/core/issues/106392) ## [8.0.1] ### Added - NLFE Legrand dimmer switch evolution ## [8.0.0] ### Added - Bticino IP scopes - Bticino dimmable light (BNLD) - Start and end times to room class ### Changed - Add power data to NLPD entities ### Removed - deprecated code ## [7.6.0] ### Added - Opening category for NACamDoorTag - Schedule modification - Bticino MyHome Server 1 scopes - NLPD - Drivia dry contact - BTicino module stubs (functionality will come later) - support for Legrand garage door opener (NLJ) - support for BTicino intelligent light (BNIL) ### Removed - Support for Python 3.8 and 3.9 ### Fixed - Update functionality for NLP, NLC, NLT and NLG ## [7.5.0] ### Added - Add NLAS - wireless batteryless scene switch device type - Add BNEU, EBU, NLDD, NLAO, NLLF, NLUO, NLUP, Z3L, NLTS, NLUF ### Fixed - Update Legrand and BTicino devices - Fix broken temperature setter when OTM is in the setup ## [7.4.0] ### Added - Add NLUF device stub - Add TPSRS Somfy shutters ### Changed - Update test fixture data to be in line with HA tests ### Fixed - Handle unknown device types and log - Fix misc device types and add stubs for unknown ## [7.3.0] ### Added - Add Legrand NLUI device class ### Changed - Minor code clean ups ### Fixed - Handle invalid ip addressed from the API more gracefully - Let weather station devices register home even if home does not exist - Catch ContentTypeError error and handle more graceful - Fix key error when battery hits very_low - Response handling issues ## [7.2.0] ### Added - Add NLPO Legrand contactor - Add NLD Legrand Double On/Off dimmer remote - Add NLFE Legrand On-Off dimmer switch - Add BTicino device support for BNCX, BNDL, BNSL ## [7.1.1] ### Fixed - Fix Netatmo radiator valves (NRV) set termpature ## [7.1.0] - 2022-10-03 ### Added - Adds Legrand NLIS double switches - Adds Legrand NLPT relay/teleruptor ### Fixed - Use dimmer type for Legrand NLF dimmers ## [7.0.1] - 2022-06-05 ### Deprecated - The following modules are deprecated and will be removed in pyatmo 8.0.0 - camera - home_coach - public_data - thermostat - weather_station ## [7.0.0] - 2022-06-05 ### Added - Adds support for Netatmo modulating thermostat - Adds support for Netatmo doorbell - Adds support for shutters, lights, energy meters and switches - Adds support for 3rd party devices from different Legrand brands such as BTicinio, Bubendorff, Smarther, CX3 - Fetch favorite weather sensors - Add support for third-party Netatmo devices (see `base_url` and `user_prefix` parameters) ### Changed - Replace freezegun with time-machine ### Deprecated - The following modules are deprecated and will be removed in pyatmo 8.0.0 - camera - home_coach - public_data - thermostat - weather_station ### Removed - ### Fixed - Use async fixture decorators ### Security - ## [6.2.4] - 2022-01-31 ### Fixed - Crash when home does not contain valid devices ## [6.2.2] - 2021-12-29 ### Fixed - Use ID if schedule name is missing ## [6.2.1] - 2021-12-18 ### Fixed - Catch when no body is contained in the response ## [6.2.0] - 2021-11-19 ### Added - Add support for python3.20 - Introduce climate module #156 ### Changed - Use assignment expressions ## [6.1.0] - 2021-10-03 ### Added - Provide a VS Code devcontainer ### Changed - Provide separate method for image retrival - Minor f-string conversions ## [6.0.0] - 2021-09-10 ### Changed - Ensure camera name is not None - Split persons by home - BREAKING: Require home_id for person related methods - version is now managed by setuptools scm ## [5.2.3] - 2021-07-22 ### Fixed - Ignore if API omits unimportant attributes in response ## [5.2.2] - 2021-07-21 ### Fixed - Ignore if API omits unimportant attributes in response ## [5.2.1] - 2021-07-10 ### Added - Distribute type information ### Changed - Update type annotations ## [5.2.0] - 2021-06-30 ### Changed - [BREAKING] Fix parameter order of set person home/away methods - Refactor camera person detection checks ## [5.1.0] - 2021-06-14 ### Fixed - Handle error when camera is not reachable more graceful - Update selfcheck to use the new update methods - Fix false positive errors when no climate devices are registered ### Security - Upgrade aiohttp to 3.7.4 or later to fix vulnerability ## [4.2.3] - 2021-05-17 ### Fixed - Extraction of climate schedules was looking for the wrong attribute (Backported from [5.0.1]) ## [5.0.1] - 2021-05-09 ### Fixed - Extraction of climate schedules was looking for the wrong attribute ## [5.0.0] - 2021-04-26 ### Added - Async support ### Changed - [BREAKING] Data retrival extracted into separate update method ## [4.2.2] - 2021-01-20 ### Fixed - Fix error when camera does not return a local url ## [4.2.1] - 2020-12-03 ### Changed - Improve CI & deployment ## [4.2.0] - 2020-11-02 ### Changed - Improve CI & deployment ### Fixed - Set station name if not contained in the backend data ### Removed - Remove min and max from weather station ## [4.1.0] - 2020-10-07 ### Fixed - Fix crash when station name is not contained in the backend data [unreleased]: https://github.com/jabesq/pyatmo/compare/v8.0.3...HEAD [8.0.3]: https://github.com/jabesq/pyatmo/compare/v8.0.2...v8.0.3 [8.0.2]: https://github.com/jabesq/pyatmo/compare/v8.0.1...v8.0.2 [8.0.1]: https://github.com/jabesq/pyatmo/compare/v8.0.0...v8.0.1 [8.0.0]: https://github.com/jabesq/pyatmo/compare/v7.6.0...v8.0.0 [7.6.0]: https://github.com/jabesq/pyatmo/compare/v7.5.0...v7.6.0 [7.5.0]: https://github.com/jabesq/pyatmo/compare/v7.4.0...v7.5.0 [7.4.0]: https://github.com/jabesq/pyatmo/compare/v7.3.0...v7.4.0 [7.3.0]: https://github.com/jabesq/pyatmo/compare/v7.2.0...v7.3.0 [7.2.0]: https://github.com/jabesq/pyatmo/compare/v7.1.1...v7.2.0 [7.1.1]: https://github.com/jabesq/pyatmo/compare/v7.1.0...v7.1.1 [7.1.0]: https://github.com/jabesq/pyatmo/compare/v7.0.1...v7.1.0 [7.0.1]: https://github.com/jabesq/pyatmo/compare/v7.0.0...v7.0.1 [7.0.0]: https://github.com/jabesq/pyatmo/compare/v6.2.4...v7.0.0 [6.2.4]: https://github.com/jabesq/pyatmo/compare/v6.2.2...v6.2.4 [6.2.2]: https://github.com/jabesq/pyatmo/compare/v6.2.1...v6.2.2 [6.2.1]: https://github.com/jabesq/pyatmo/compare/v6.2.0...v6.2.1 [6.2.0]: https://github.com/jabesq/pyatmo/compare/v6.1.0...v6.2.0 [6.1.0]: https://github.com/jabesq/pyatmo/compare/v6.0.0...v6.1.0 [6.0.0]: https://github.com/jabesq/pyatmo/compare/v5.2.3...v6.0.0 [5.2.3]: https://github.com/jabesq/pyatmo/compare/v5.2.2...v5.2.3 [5.2.2]: https://github.com/jabesq/pyatmo/compare/v5.2.1...v5.2.2 [5.2.1]: https://github.com/jabesq/pyatmo/compare/v5.2.0...v5.2.1 [5.2.0]: https://github.com/jabesq/pyatmo/compare/v5.1.0...v5.2.0 [5.1.0]: https://github.com/jabesq/pyatmo/compare/v5.0.1...v5.1.0 [5.0.1]: https://github.com/jabesq/pyatmo/compare/v5.0.0...v5.0.1 [5.0.1]: https://github.com/jabesq/pyatmo/compare/v4.2.2...v5.0.0 [4.2.3]: https://github.com/jabesq/pyatmo/compare/v4.2.2...v4.2.3 [4.2.2]: https://github.com/jabesq/pyatmo/compare/v4.2.1...v4.2.2 [4.2.1]: https://github.com/jabesq/pyatmo/compare/v4.2.0...v4.2.1 [4.2.0]: https://github.com/jabesq/pyatmo/compare/v4.1.0...v4.2.0 [4.1.0]: https://github.com/jabesq/pyatmo/compare/v4.0.0...v4.1.0 [4.0.0]: https://github.com/jabesq/pyatmo/compare/v3.3.1...v4.0.0 [3.3.1]: https://github.com/jabesq/pyatmo/releases/tag/v3.3.1 jabesq-org-pyatmo-6216472/CODEOWNERS000066400000000000000000000003371466116727400166640ustar00rootroot00000000000000# These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, # @jabesq and @cgtobi will be requested for # review when someone opens a pull request. * @jabesq @cgtobi jabesq-org-pyatmo-6216472/CODE_OF_CONDUCT.md000066400000000000000000000121221466116727400200630ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at . All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. jabesq-org-pyatmo-6216472/LICENSE.txt000066400000000000000000000020541466116727400171120ustar00rootroot00000000000000MIT License Copyright (c) 2018 Hugo DUPRAS 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. jabesq-org-pyatmo-6216472/MANIFEST.in000066400000000000000000000000461466116727400170240ustar00rootroot00000000000000include README.md include LICENSE.txt jabesq-org-pyatmo-6216472/Pipfile000066400000000000000000000006261466116727400166050ustar00rootroot00000000000000[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] black = "*" bleach = "~=6.1" docutils = "*" time-machine = "*" mypy = "*" pre-commit = "*" pytest = "*" pytest-asyncio = "*" pytest-cov = "*" pytest-mock = "*" requests-mock = "*" ruff = "*" tox = ">=3.25" twine = "*" no-implicit-optional = "*" [packages] requests = "*" requests-oauthlib = "*" aiohttp = ">3.8.1" jabesq-org-pyatmo-6216472/README.md000066400000000000000000000046221466116727400165510ustar00rootroot00000000000000# pyatmo [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) [![GitHub Actions](https://github.com/jabesq/pyatmo/workflows/Python%20package/badge.svg)](https://github.com/jabesq/pyatmo/actions?workflow=Python+package) [![PyPi](https://img.shields.io/pypi/v/pyatmo.svg)](https://pypi.python.org/pypi/pyatmo) [![license](https://img.shields.io/pypi/l/pyatmo.svg)](https://github.com/jabesq/pyatmo/blob/master/LICENSE.txt) > **Warning:** > Due to personal reasons, I am currently unable to dedicate sufficient time to effectively manage this repository. Consequently, no attention will be given to existing or forthcoming issues until further notice. **However**, I want to assure you that I will continue to merge any pull requests that are submitted, provided they successfully pass the continuous integration tests and do not exhibit any glaring issues. > > I apologize for any inconvenience this may cause, and I sincerely hope to have the capacity to allocate more time to this repository in the near future. Your understanding is greatly appreciated. --- Simple API to access Netatmo devices and data like weather station or camera data from Python 3. For more detailed information see [dev.netatmo.com](http://dev.netatmo.com) This project has no relation with the Netatmo company. ## Install To install pyatmo simply run: pip install pyatmo Depending on your permissions you might be required to use sudo. Once installed you can simply add `pyatmo` to your Python 3 scripts by including: import pyatmo ## Note The module requires a valid user account and a registered application. Be aware that the module may stop working if Netatmo decides to change their API. ## Development Clone the repo and install dependencies: git clone cd pyatmo pipenv install --dev To add the pre-commit hook to your environment run: pip install pre-commit pre-commit install ## Testing To run the full suite simply run the following command from within the virtual environment: pytest or python -m pytest tests/ To generate code coverage xml (e.g. for use in VSCode) run python -m pytest --cov-report xml:cov.xml --cov pyatmo --cov-append tests/ Another way to run the tests is by using `tox`. This runs the tests against the installed package and multiple versions of python. tox or by specifying a python version tox -e py310 jabesq-org-pyatmo-6216472/fixtures/000077500000000000000000000000001466116727400171375ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/fixtures/archive/000077500000000000000000000000001466116727400205605ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/fixtures/archive/camera_data_empty.json000066400000000000000000000001301466116727400251040ustar00rootroot00000000000000{ "status": "ok", "time_exec": 0.03621506690979, "time_server": 1560626960 }jabesq-org-pyatmo-6216472/fixtures/archive/camera_data_events_until.json000066400000000000000000000105661466116727400265030ustar00rootroot00000000000000{ "body": { "events_list": [ { "id": "a1b2c3d4e5f6abcdef123461", "type": "person", "time": 1560706232, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "video_status": "deleted", "is_arrival": true, "message": "John Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123462", "type": "person_away", "time": 1560706237, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "message": "John Doe hat das Haus verlassen", "sub_message": "John Doe gilt als „Abwesend“, da das mit diesem Profil verbundene Telefon den Bereich des Hauses verlassen hat." }, { "id": "a1b2c3d4e5f6abcdef123463", "type": "person", "time": 1560706241, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827375-7e04-5298-83ae-a0cb8372dff2", "snapshot": { "id": "19b13efa945ec892c6da2a8c", "version": 1, "key": "1704853cfc9571bd10618591dc9035e5bc0fa3203f44739c49a5b26d2f7ad67f", "url": "https://netatmocameraimage.blob.core.windows.net/production/5ecfa94c6da5e5bc0fa3203f3cfdc903489219b13e2a8c548547b26d2f7ad6717039c49ac9571bd10618591f" }, "video_id": "f914-aa7da416643-4744-82f9-4e7d4440b", "video_status": "available", "is_arrival": false, "message": "Jane Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123464", "type": "wifi_status", "time": 1560706271, "camera_id": "12:34:56:00:8b:a2", "device_id": "12:34:56:00:8b:a2", "sub_type": 1, "message": "Hall:WLAN-Verbindung erfolgreich hergestellt" }, { "id": "a1b2c3d4e5f6abcdef123465", "type": "outdoor", "time": 1560706283, "camera_id": "12:34:56:00:a5:a4", "device_id": "12:34:56:00:a5:a4", "video_id": "string", "video_status": "available", "event_list": [ { "type": "string", "time": 1560706283, "offset": 0, "id": "c81bcf7b-2cfg-4ac9-8455-487ed00c0001", "message": "Animal détecté", "snapshot": { "id": "5715e16849c75xxxx00000000xxxxx", "version": 1, "key": "7ac578d05030d0e170643a787ee0a29663dxxx00000xxxxx00000", "url": "https://netatmocameraimage.blob.core.windows.net/production/1aa" }, "vignette": { "id": "5715e16849c75xxxx00000000xxxxx", "version": 1, "key": "7ac578d05030d0e170643a787ee0a29663dxxx00000xxxxx00000", "url": "https://netatmocameraimage.blob.core.windows.net/production/1aa00000" } }, { "type": "string", "time": 1560706283, "offset": 0, "id": "c81bcf7b-2cfg-4ac9-8455-487ed00c0002", "message": "Animal détecté", "snapshot": { "filename": "vod\/af74631d-8311-42dc-825b-82e3abeaab09\/events\/c53b-aze7a.jpg" }, "vignette": { "filename": "vod\/af74631d-8311-42dc-825b-82e3abeaab09\/events\/c5.jpg" } } ] } ] }, "status": "ok", "time_exec": 0.03666909215079, "time_server": 15607062321 }jabesq-org-pyatmo-6216472/fixtures/archive/camera_home_data.json000066400000000000000000000400221466116727400247020ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8b", "name": "MYHOME", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "last_seen": 1557071156, "out_of_sight": true, "face": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7" }, "pseudo": "John Doe" }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "last_seen": 1560600726, "out_of_sight": true, "face": { "id": "d74fad765b9100ef480720a9", "version": 3, "key": "a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, "pseudo": "Jane Doe" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "last_seen": 1560626666, "out_of_sight": false, "face": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8" }, "pseudo": "Richard Doe" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff4", "last_seen": 1560621666, "out_of_sight": true, "face": { "id": "d0ef44fad765b980720710a9", "version": 1, "key": "ab029da89f84a95c2d1730fb67fc40cb2d74b80869ecdf2bb8b72039d2c69928", "url": "https://netatmocameraimage.blob.core.windows.net/production/d0ef44fad765b980720710a9ab029da89f84a95c2d1730fb67fc40cb2d74b80869ecdf2bb8b72039d2c69928" } } ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin" }, "cameras": [ { "id": "12:34:56:00:f1:62", "type": "NACamera", "status": "on", "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.248.91/6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTg,,", "is_local": true, "sd_status": "on", "alim_status": "on", "name": "Hall", "modules": [ { "id": "12:34:56:00:f2:f1", "type": "NIS", "battery_percent": 84, "rf": 68, "status": "no_news", "monitoring": "on", "alim_source": "battery", "tamper_detection_enabled": true, "name": "Welcome's Siren" } ], "use_pin_code": false, "last_setup": 1544828430 }, { "id": "12:34:56:00:a5:a4", "type": "NOC", "status": "on", "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.248.91/6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTw,,", "is_local": true, "sd_status": "on", "alim_status": "on", "name": "Garden", "last_setup": 1563737661, "light_mode_status": "auto" } ], "smokedetectors": [ { "id": "12:34:56:00:8b:a2", "type": "NSD", "last_setup": 1567261859, "name": "Hall" }, { "id": "12:34:56:00:8b:ac", "type": "NSD", "last_setup": 1567262759, "name": "Kitchen" } ], "events": [ { "id": "a1b2c3d4e5f6abcdef123456", "type": "person", "time": 1560604700, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "video_status": "deleted", "is_arrival": false, "message": "John Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123457", "type": "person_away", "time": 1560602400, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "message": "John Doe hat das Haus verlassen", "sub_message": "John Doe gilt als abwesend, da das mit diesem Profil verbundene Telefon den Bereich des Hauses verlassen hat." }, { "id": "a1b2c3d4e5f6abcdef123458", "type": "person", "time": 1560601200, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "video_status": "deleted", "is_arrival": false, "message": "John Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123459", "type": "person", "time": 1560600100, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827375-7e04-5298-83ae-a0cb8372dff2", "snapshot": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, "video_id": "12345678-36bc-4b9a-9762-5194e707ed51", "video_status": "available", "is_arrival": false, "message": "Jane Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef12345a", "type": "person", "time": 1560603600, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827375-7e04-5298-83ae-a0cb8372dff3", "snapshot": { "id": "532dde8d17554c022ab071b8", "version": 1, "key": "9fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28", "url": "https://netatmocameraimage.blob.core.windows.net/production/532dde8d17554c022ab071b89fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28" }, "video_id": "12345678-1234-46cb-ad8f-23d893874099", "video_status": "available", "is_arrival": false, "message": "Bewegung erkannt" }, { "id": "a1b2c3d4e5f6abcdef12345b", "type": "movement", "time": 1560506200, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "category": "human", "snapshot": { "id": "532dde8d17554c022ab071b9", "version": 1, "key": "8fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28", "url": "https://netatmocameraimage.blob.core.windows.net/production/532dde8d17554c022ab071b98fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28" }, "vignette": { "id": "5dc021b5dea854bd2321707a", "version": 1, "key": "58c5a05bd6bd908f6bf368865ef7355231c44215f8eb7ae458c919b2c67b4944", "url": "https://netatmocameraimage.blob.core.windows.net/production/5dc021b5dea854bd2321707a58c5a05bd6bd908f6bf368865ef7355231c44215f8eb7ae458c919b2c67b4944" }, "video_id": "12345678-1234-46cb-ad8f-23d89387409a", "video_status": "available", "message": "Bewegung erkannt" }, { "id": "a1b2c3d4e5f6abcdef12345c", "type": "sound_test", "time": 1560506210, "camera_id": "12:34:56:00:8b:a2", "device_id": "12:34:56:00:8b:a2", "sub_type": 0, "message": "Hall: Alarmton erfolgreich getestet" }, { "id": "a1b2c3d4e5f6abcdef12345d", "type": "wifi_status", "time": 1560506220, "camera_id": "12:34:56:00:8b:a2", "device_id": "12:34:56:00:8b:a2", "sub_type": 1, "message": "Hall:WLAN-Verbindung erfolgreich hergestellt" }, { "id": "a1b2c3d4e5f6abcdef12345e", "type": "outdoor", "time": 1560643100, "camera_id": "12:34:56:00:a5:a4", "device_id": "12:34:56:00:a5:a4", "video_id": "string", "video_status": "available", "event_list": [ { "type": "string", "time": 1560643100, "offset": 0, "id": "c81bcf7b-2cfg-4ac9-8455-487ed00c0000", "message": "Animal détecté", "snapshot": { "id": "5715e16849c75xxxx00000000xxxxx", "version": 1, "key": "7ac578d05030d0e170643a787ee0a29663dxxx00000xxxxx00000", "url": "https://netatmocameraimage.blob.core.windows.net/production/1aa" }, "vignette": { "id": "5715e16849c75xxxx00000000xxxxx", "version": 1, "key": "7ac578d05030d0e170643a787ee0a29663dxxx00000xxxxx00000", "url": "https://netatmocameraimage.blob.core.windows.net/production/1aa00000" } }, { "type": "string", "time": 1560506222, "offset": 0, "id": "c81bcf7b-2cfg-4ac9-8455-487ed00c0000", "message": "Animal détecté", "snapshot": { "filename": "vod\/af74631d-8311-42dc-825b-82e3abeaab09\/events\/c53b-aze7a.jpg" }, "vignette": { "filename": "vod\/af74631d-8311-42dc-825b-82e3abeaab09\/events\/c5.jpg" } } ] } ] }, { "id": "91763b24c43d3e344f424e8c", "persons": [], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin" }, "cameras": [ { "id": "12:34:56:00:a5:a5", "type": "NOC", "status": "on", "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.248.91/6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTz,,", "is_local": true, "sd_status": "on", "alim_status": "on", "name": "Street", "last_setup": 1563737561, "light_mode_status": "auto" }, { "id": "12:34:56:00:a5:a6", "type": "NOC", "status": "on", "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.248.91/6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTz,,", "is_local": true, "sd_status": "on", "alim_status": "on", "last_setup": 1563737561, "light_mode_status": "auto" } ], "smokedetectors": [] }, { "id": "91763b24c43d3e344f424e8d", "persons": [], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin" }, "cameras": [], "smokedetectors": [] } ], "user": { "reg_locale": "de-DE", "lang": "de-DE", "country": "DE", "mail": "john@doe.com" }, "global_info": { "show_tags": true } }, "status": "ok", "time_exec": 0.03621506690979, "time_server": 1560626960 }jabesq-org-pyatmo-6216472/fixtures/archive/camera_home_data_disconnected.json000066400000000000000000000221631466116727400274320ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8b", "name": "MYHOME", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "last_seen": 1557071156, "out_of_sight": true, "face": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7" }, "pseudo": "John Doe" }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "last_seen": 1560600726, "out_of_sight": true, "face": { "id": "d74fad765b9100ef480720a9", "version": 3, "key": "a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, "pseudo": "Jane Doe" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "last_seen": 1560626666, "out_of_sight": false, "face": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8" }, "pseudo": "Richard Doe" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff4", "last_seen": 1560621666, "out_of_sight": true, "face": { "id": "d0ef44fad765b980720710a9", "version": 1, "key": "ab029da89f84a95c2d1730fb67fc40cb2d74b80869ecdf2bb8b72039d2c69928", "url": "https://netatmocameraimage.blob.core.windows.net/production/d0ef44fad765b980720710a9ab029da89f84a95c2d1730fb67fc40cb2d74b80869ecdf2bb8b72039d2c69928" } } ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin" }, "cameras": [ { "id": "12:34:56:00:f1:62", "type": "NACamera", "status": "disconnected", "sd_status": "on", "alim_status": "on", "name": "Hall", "use_pin_code": false, "last_setup": 1544828430 } ], "smokedetectors": [], "events": [ { "id": "a1b2c3d4e5f6abcdef123456", "type": "person", "time": 1560604700, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "video_status": "deleted", "is_arrival": false, "message": "John Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123457", "type": "person_away", "time": 1560602400, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "message": "John Doe hat das Haus verlassen", "sub_message": "John Doe gilt als abwesend, da das mit diesem Profil verbundene Telefon den Bereich des Hauses verlassen hat." }, { "id": "a1b2c3d4e5f6abcdef123458", "type": "person", "time": 1560601200, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "video_status": "deleted", "is_arrival": false, "message": "John Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef123459", "type": "person", "time": 1560600100, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827375-7e04-5298-83ae-a0cb8372dff2", "snapshot": { "id": "d74fad765b9100ef480720a9", "version": 1, "key": "a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, "video_id": "12345678-36bc-4b9a-9762-5194e707ed51", "video_status": "available", "is_arrival": false, "message": "Jane Doe gesehen" }, { "id": "a1b2c3d4e5f6abcdef12345a", "type": "person", "time": 1560603600, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "person_id": "91827375-7e04-5298-83ae-a0cb8372dff3", "snapshot": { "id": "532dde8d17554c022ab071b8", "version": 1, "key": "9fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28", "url": "https://netatmocameraimage.blob.core.windows.net/production/532dde8d17554c022ab071b89fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28" }, "video_id": "12345678-1234-46cb-ad8f-23d893874099", "video_status": "available", "is_arrival": false, "message": "Bewegung erkannt" }, { "id": "a1b2c3d4e5f6abcdef12345b", "type": "movement", "time": 1560506200, "camera_id": "12:34:56:00:f1:62", "device_id": "12:34:56:00:f1:62", "category": "human", "snapshot": { "id": "532dde8d17554c022ab071b9", "version": 1, "key": "8fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28", "url": "https://netatmocameraimage.blob.core.windows.net/production/532dde8d17554c022ab071b98fbe490fffacf45b8416241946541b031a004a09b6747feb6c38c3ccbc456b28" }, "vignette": { "id": "5dc021b5dea854bd2321707a", "version": 1, "key": "58c5a05bd6bd908f6bf368865ef7355231c44215f8eb7ae458c919b2c67b4944", "url": "https://netatmocameraimage.blob.core.windows.net/production/5dc021b5dea854bd2321707a58c5a05bd6bd908f6bf368865ef7355231c44215f8eb7ae458c919b2c67b4944" }, "video_id": "12345678-1234-46cb-ad8f-23d89387409a", "video_status": "available", "message": "Bewegung erkannt" } ] } ], "user": { "reg_locale": "de-DE", "lang": "de-DE", "country": "DE", "mail": "john@doe.com" }, "global_info": { "show_tags": true } }, "status": "ok", "time_exec": 0.03621506690979, "time_server": 1560626960 }jabesq-org-pyatmo-6216472/fixtures/archive/camera_home_data_no_homes.json000066400000000000000000000005401466116727400265720ustar00rootroot00000000000000{ "body": { "homes": [], "user": { "reg_locale": "de-DE", "lang": "de-DE", "country": "DE", "mail": "john@doe.com" }, "global_info": { "show_tags": true } }, "status": "ok", "time_exec": 0.03621506690979, "time_server": 1560626960 }jabesq-org-pyatmo-6216472/fixtures/archive/camera_image_sample.jpg000066400000000000000000000012371466116727400252200ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ "ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?Åñ´fˆz¥È*òû£µsæ(²x¯ñŸøNµNå±þB¹WfÞÜž§½ÿÙjabesq-org-pyatmo-6216472/fixtures/archive/camera_ping.json000066400000000000000000000001631466116727400237200ustar00rootroot00000000000000{ "local_url": "http://192.168.0.123/678460a0d47e5618699fb31169e2b47d", "product_name": "Welcome Netatmo" }jabesq-org-pyatmo-6216472/fixtures/archive/camera_set_state_error.json000066400000000000000000000001461466116727400261700ustar00rootroot00000000000000{ "error": { "code": 21, "message": "Invalid device_id, 12:34:56:00:f1:ff" } }jabesq-org-pyatmo-6216472/fixtures/archive/camera_set_state_error_already_on.json000066400000000000000000000005601466116727400303650ustar00rootroot00000000000000{ "status": "ok", "time_server": 1582932399, "body": { "home": { "id": "91763b24c43d3e344f424e8b" }, "errors": [ { "code": 23, "message": "Already on", "id": "12:34:56:00:f1:62", "command": "command/changestatus" } ] } }jabesq-org-pyatmo-6216472/fixtures/archive/camera_set_state_error_wrong_parameter.json000066400000000000000000000001751466116727400314460ustar00rootroot00000000000000{ "error": { "code": 21, "message": "cannot set property floodlight for module 12:34:56:00:f1:62" } }jabesq-org-pyatmo-6216472/fixtures/archive/camera_set_state_ok.json000066400000000000000000000000651466116727400254500ustar00rootroot00000000000000{ "status": "ok", "time_server": 1582932411 }jabesq-org-pyatmo-6216472/fixtures/archive/error_scope.json000066400000000000000000000001221466116727400237700ustar00rootroot00000000000000{"error":{"code":13,"message":"Application does not have the good scope rights"}} jabesq-org-pyatmo-6216472/fixtures/archive/home_coach_no_devices.json000066400000000000000000000007371466116727400257450ustar00rootroot00000000000000{ "body": { "devices": [], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.05824708938598633, "time_server": 1565377059 }jabesq-org-pyatmo-6216472/fixtures/archive/home_coach_simple.json000066400000000000000000000153641466116727400251220ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:26:69:0c", "cipher_id": "enc:16:1UqwQlYV5AY2pfyEi5H47dmmFOOL3mCUo+KAkchL4A2CLI5u0e45Xr5jeAswO+XO", "date_setup": 1544560184, "last_setup": 1544560184, "type": "NHC", "last_status_store": 1558268332, "firmware": 45, "last_upgrade": 1544560186, "wifi_status": 58, "reachable": false, "co2_calibrating": false, "station_name": "Bedroom", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:25:cf:a8", "cipher_id": "enc:16:A+Jm0yFWBwUyKinFDutPZK7I2PuHN1fqaE9oB/KF+McbFs3oN9CKpR/dYbqL4om2", "date_setup": 1544562192, "last_setup": 1544562192, "type": "NHC", "last_status_store": 1559198922, "firmware": 45, "last_upgrade": 1544562194, "wifi_status": 41, "reachable": true, "co2_calibrating": false, "station_name": "Kitchen", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:26:65:14", "cipher_id": "enc:16:7kK6ZzG4L7NgfZZ6+dMvNxw4l6vXu+88SEJkCUklNdPa4KYIHmsfa1moOilEK61i", "date_setup": 1544564061, "last_setup": 1544564061, "type": "NHC", "last_status_store": 1559067159, "firmware": 45, "last_upgrade": 1544564302, "wifi_status": 66, "reachable": true, "co2_calibrating": false, "station_name": "Livingroom", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:3e:c5:46", "station_name": "Parents Bedroom", "date_setup": 1570732241, "last_setup": 1570732241, "type": "NHC", "last_status_store": 1572073818, "module_name": "Indoor", "firmware": 45, "wifi_status": 67, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1572073816, "Temperature": 20.3, "CO2": 494, "Humidity": 63, "Noise": 42, "Pressure": 1014.5, "AbsolutePressure": 1004.1, "health_idx": 1, "min_temp": 20.3, "max_temp": 21.6, "date_max_temp": 1572059333, "date_min_temp": 1572073816 } }, { "_id": "12:34:56:26:68:92", "station_name": "Baby Bedroom", "date_setup": 1571342643, "last_setup": 1571342643, "type": "NHC", "last_status_store": 1572073995, "module_name": "Indoor", "firmware": 45, "wifi_status": 68, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1572073994, "Temperature": 21.6, "CO2": 1053, "Humidity": 66, "Noise": 45, "Pressure": 1021.4, "AbsolutePressure": 1011, "health_idx": 1, "min_temp": 20.9, "max_temp": 21.6, "date_max_temp": 1572073690, "date_min_temp": 1572064254 } } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.095954179763794, "time_server": 1559463229 }jabesq-org-pyatmo-6216472/fixtures/archive/home_data_empty.json000066400000000000000000000001511466116727400246070ustar00rootroot00000000000000{ "body": {}, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/archive/home_data_no_devices.json000066400000000000000000000015111466116727400255700ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8c", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "therm_setpoint_default_duration": 180, "therm_mode": "schedule" } ], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/archive/home_data_no_homes.json000066400000000000000000000006611466116727400252660ustar00rootroot00000000000000{ "body": { "homes": [], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/archive/home_data_nohomename.json000066400000000000000000000371671466116727400256200ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8b", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "rooms": [ { "id": "2746182631", "name": "Livingroom", "type": "livingroom", "module_ids": [ "12:34:56:00:01:ae" ] }, { "id": "3688132631", "name": "Hall", "type": "custom", "module_ids": [ "12:34:56:00:f1:62" ] } ], "modules": [ { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "name": "Thermostat", "setup_date": 1494963356, "modules_bridged": [ "12:34:56:00:01:ae" ] }, { "id": "12:34:56:00:01:ae", "type": "NATherm1", "name": "Livingroom", "setup_date": 1494963356, "room_id": "2746182631", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:00:f1:62", "type": "NACamera", "name": "Hall", "setup_date": 1544828430, "room_id": "3688132631" } ], "therm_schedules": [ { "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0 }, { "type": 1, "name": "Night", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1 }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4 } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Default", "selected": true, "id": "591b54a2764ff4d50d8b5795", "type": "therm" } ], "therm_setpoint_default_duration": 120, "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "pseudo": "John Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7" }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "pseudo": "Jane Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "pseudo": "Richard Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8" } ], "schedules": [ { "zones": [ { "type": 0, "name": "Komfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 21 } ] }, { "type": 1, "name": "Nacht", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 17 } ] }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 17 } ] } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Default", "id": "591b54a2764ff4d50d8b5795", "selected": true, "type": "therm" } ], "therm_mode": "schedule" } ], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/archive/home_data_simple.json000066400000000000000000000556271466116727400247640ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8b", "name": "MYHOME", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "rooms": [ { "id": "2746182631", "name": "Livingroom", "type": "livingroom", "module_ids": [ "12:34:56:00:01:ae" ] }, { "id": "3688132631", "name": "Hall", "type": "custom", "module_ids": [ "12:34:56:00:f1:62" ] }, { "id": "2833524037", "name": "Entrada", "type": "lobby", "module_ids": [ "12:34:56:03:a5:54" ] }, { "id": "2940411577", "name": "Cocina", "type": "kitchen", "module_ids": [ "12:34:56:03:a0:ac" ] } ], "modules": [ { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "name": "Thermostat", "setup_date": 1494963356, "modules_bridged": [ "12:34:56:00:01:ae", "12:34:56:03:a0:ac", "12:34:56:03:a5:54" ] }, { "id": "12:34:56:00:01:ae", "type": "NATherm1", "name": "Livingroom", "setup_date": 1494963356, "room_id": "2746182631", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:03:a5:54", "type": "NRV", "name": "Valve1", "setup_date": 1554549767, "room_id": "2833524037", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:03:a0:ac", "type": "NRV", "name": "Valve2", "setup_date": 1554554444, "room_id": "2940411577", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:00:f1:62", "type": "NACamera", "name": "Hall", "setup_date": 1544828430, "room_id": "3688132631" } ], "therm_schedules": [ { "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0 }, { "type": 1, "name": "Night", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1 }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4 } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Default", "selected": true, "id": "591b54a2764ff4d50d8b5795", "type": "therm" }, { "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0 }, { "type": 1, "name": "Night", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1 }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4 } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Winter", "id": "b1b54a2f45795764f59d50d8", "type": "therm" } ], "therm_setpoint_default_duration": 120, "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "pseudo": "John Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7" }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "pseudo": "Jane Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "pseudo": "Richard Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8" } ], "schedules": [ { "zones": [ { "type": 0, "name": "Komfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 21 } ] }, { "type": 1, "name": "Nacht", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 17 } ] }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4, "rooms": [ { "id": "2746182631", "therm_setpoint_temperature": 17 } ] } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Default", "id": "591b54a2764ff4d50d8b5795", "selected": true, "type": "therm" } ], "therm_mode": "schedule" }, { "id": "91763b24c43d3e344f424e8c", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "therm_setpoint_default_duration": 180, "therm_mode": "schedule" } ], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_empty.json000066400000000000000000000001051466116727400252200ustar00rootroot00000000000000{ "status": "ok", "time_server": 1559292039, "body": {} }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_error_and_data.json000066400000000000000000000074701466116727400270420ustar00rootroot00000000000000{ "status": "ok", "time_server": 1559292039, "body": { "home": { "modules": [ { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "firmware_revision": 174, "rf_strength": 107, "wifi_strength": 42 }, { "id": "12:34:56:00:01:ae", "reachable": true, "type": "NATherm1", "firmware_revision": 65, "rf_strength": 58, "battery_level": 3793, "boiler_valve_comfort_boost": false, "boiler_status": false, "anticipating": false, "bridge": "12:34:56:00:fa:d0", "battery_state": "high" }, { "id": "12:34:56:03:a5:54", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 51, "battery_level": 3025, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" }, { "id": "12:34:56:03:a0:ac", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 59, "battery_level": 3029, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" } ], "rooms": [ { "id": "2746182631", "reachable": true, "therm_measured_temperature": 19.8, "therm_setpoint_temperature": 12, "therm_setpoint_mode": "away", "therm_setpoint_start_time": 1559229567, "therm_setpoint_end_time": 0 }, { "id": "2940411577", "reachable": true, "therm_measured_temperature": 27, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false }, { "id": "2833524037", "reachable": true, "therm_measured_temperature": 24.5, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false } ], "id": "91763b24c43d3e344f424e8b", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "last_seen": 1557071156, "out_of_sight": true }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "last_seen": 1559282761, "out_of_sight": false }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "last_seen": 1559224132, "out_of_sight": true } ] }, "errors": [ { "code": 6, "id": "12:34:56:00:f1:62" } ] } }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_error_invalid_id.json000066400000000000000000000001141466116727400273750ustar00rootroot00000000000000{ "error": { "code": 21, "message": "Invalid id" } }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_error_missing_home_id.json000066400000000000000000000001211466116727400304260ustar00rootroot00000000000000{ "error": { "code": 10, "message": "Missing home_id" } }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_error_missing_parameters.json000066400000000000000000000001241466116727400311700ustar00rootroot00000000000000{ "error": { "code": 10, "message": "Missing parameters" } }jabesq-org-pyatmo-6216472/fixtures/archive/home_status_error_mode_not_authorized.json000066400000000000000000000001251466116727400313370ustar00rootroot00000000000000{ "error": { "code": 21, "message": "mode not authorized" } }jabesq-org-pyatmo-6216472/fixtures/archive/invalid_grant.json000066400000000000000000000000401466116727400242660ustar00rootroot00000000000000{ "error": "invalid_grant" }jabesq-org-pyatmo-6216472/fixtures/archive/oauth2_token.json000066400000000000000000000006361466116727400240620ustar00rootroot00000000000000{ "access_token": "91763b24c43d3e344f424e8b|880b55a08c758e87ff8755a00c6b8a12", "refresh_token": "91763b24c43d3e344f424e8b|87ff8755a00c6b8a120b55a08c758e93", "scope": [ "read_station", "read_camera", "access_camera", "read_thermostat", "write_thermostat", "read_presence", "access_presence" ], "expires_in": 10800, "expire_in": 10800 }jabesq-org-pyatmo-6216472/fixtures/archive/public_data_error_mongo.json000066400000000000000000000002631466116727400263330ustar00rootroot00000000000000{ "error": { "message": "failed to connect to server [localhost:27020] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27020]", "code": 0 } } jabesq-org-pyatmo-6216472/fixtures/archive/public_data_simple.json000066400000000000000000000263141466116727400253010ustar00rootroot00000000000000{ "status": "ok", "time_server": 1560248397, "time_exec": 0, "body": [ { "_id": "70:ee:50:36:94:7c", "place": { "location": [ 8.791382999999996, 50.2136394 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 132 }, "mark": 14, "measures": { "02:00:00:36:f2:94": { "res": { "1560248022": [ 21.4, 62 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:36:94:7c": { "res": { "1560248030": [ 1010.6 ] }, "type": [ "pressure" ] }, "05:00:00:05:33:84": { "rain_60min": 0.2, "rain_24h": 12.322000000000001, "rain_live": 0.5, "rain_timeutc": 1560248022 } }, "modules": [ "05:00:00:05:33:84", "02:00:00:36:f2:94" ], "module_types": { "05:00:00:05:33:84": "NAModule3", "02:00:00:36:f2:94": "NAModule1" } }, { "_id": "70:ee:50:1f:68:9e", "place": { "location": [ 8.795445200000017, 50.2130169 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 125 }, "mark": 14, "measures": { "02:00:00:1f:82:28": { "res": { "1560248312": [ 21.1, 69 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:1f:68:9e": { "res": { "1560248344": [ 1007.3 ] }, "type": [ "pressure" ] }, "05:00:00:02:bb:6e": { "rain_60min": 0, "rain_24h": 9.999, "rain_live": 0, "rain_timeutc": 1560248344 } }, "modules": [ "02:00:00:1f:82:28", "05:00:00:02:bb:6e" ], "module_types": { "02:00:00:1f:82:28": "NAModule1", "05:00:00:02:bb:6e": "NAModule3" } }, { "_id": "70:ee:50:27:25:b0", "place": { "location": [ 8.7807159, 50.1946167 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 112 }, "mark": 14, "measures": { "02:00:00:27:19:b2": { "res": { "1560247889": [ 23.2, 60 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:27:25:b0": { "res": { "1560247907": [ 1012.8 ] }, "type": [ "pressure" ] }, "05:00:00:03:5d:2e": { "rain_60min": 0, "rain_24h": 11.716000000000001, "rain_live": 0, "rain_timeutc": 1560247896 } }, "modules": [ "02:00:00:27:19:b2", "05:00:00:03:5d:2e" ], "module_types": { "02:00:00:27:19:b2": "NAModule1", "05:00:00:03:5d:2e": "NAModule3" } }, { "_id": "70:ee:50:04:ed:7a", "place": { "location": [ 8.785034, 50.192169 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 112 }, "mark": 14, "measures": { "02:00:00:04:c2:2e": { "res": { "1560248137": [ 19.8, 76 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:04:ed:7a": { "res": { "1560248152": [ 1005.4 ] }, "type": [ "pressure" ] } }, "modules": [ "02:00:00:04:c2:2e" ], "module_types": { "02:00:00:04:c2:2e": "NAModule1" } }, { "_id": "70:ee:50:27:9f:2c", "place": { "location": [ 8.785342, 50.193573 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 116 }, "mark": 1, "measures": { "02:00:00:27:aa:70": { "res": { "1560247821": [ 25.5, 56 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:27:9f:2c": { "res": { "1560247853": [ 1010.6 ] }, "type": [ "pressure" ] } }, "modules": [ "02:00:00:27:aa:70" ], "module_types": { "02:00:00:27:aa:70": "NAModule1" } }, { "_id": "70:ee:50:01:20:fa", "place": { "location": [ 8.7953, 50.195241 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 119 }, "mark": 1, "measures": { "02:00:00:00:f7:ba": { "res": { "1560247831": [ 27.4, 58 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:01:20:fa": { "res": { "1560247876": [ 1014.4 ] }, "type": [ "pressure" ] } }, "modules": [ "02:00:00:00:f7:ba" ], "module_types": { "02:00:00:00:f7:ba": "NAModule1" } }, { "_id": "70:ee:50:3c:02:78", "place": { "location": [ 8.795953681700666, 50.19530139868166 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 119 }, "mark": 7, "measures": { "02:00:00:3c:21:f2": { "res": { "1560248225": [ 23.3, 58 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:3c:02:78": { "res": { "1560248270": [ 1011.7 ] }, "type": [ "pressure" ] } }, "modules": [ "02:00:00:3c:21:f2" ], "module_types": { "02:00:00:3c:21:f2": "NAModule1" } }, { "_id": "70:ee:50:36:a9:fc", "place": { "location": [ 8.801164269110814, 50.19596181704958 ], "timezone": "Europe/Berlin", "country": "DE", "altitude": 113 }, "mark": 14, "measures": { "02:00:00:36:a9:50": { "res": { "1560248145": [ 20.1, 67 ] }, "type": [ "temperature", "humidity" ] }, "70:ee:50:36:a9:fc": { "res": { "1560248191": [ 1010 ] }, "type": [ "pressure" ] }, "05:00:00:02:92:82": { "rain_60min": 0, "rain_24h": 11.009, "rain_live": 0, "rain_timeutc": 1560248184 }, "06:00:00:03:19:76": { "wind_strength": 15, "wind_angle": 17, "gust_strength": 31, "gust_angle": 217, "wind_timeutc": 1560248190 } }, "modules": [ "05:00:00:02:92:82", "02:00:00:36:a9:50", "06:00:00:03:19:76" ], "module_types": { "05:00:00:02:92:82": "NAModule3", "02:00:00:36:a9:50": "NAModule1", "06:00:00:03:19:76": "NAModule2" } } ] }jabesq-org-pyatmo-6216472/fixtures/archive/thermostat_data_simple.json000066400000000000000000000255241466116727400262170ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:00:fa:d0", "firmware": 174, "last_bilan": { "y": 2019, "m": 4 }, "last_setup": 1494963356, "last_status_store": 1559297986, "place": { "altitude": 112, "city": "Berlin", "country": "DE", "improveLocProposed": true, "location": [ 52.516263, 13.377726 ], "timezone": "Europe/Berlin", "trust_location": true }, "plug_connected_boiler": 1, "type": "NAPlug", "udp_conn": true, "wifi_status": 42, "modules": [ { "_id": "12:34:56:00:01:ae", "module_name": "Livingroom", "type": "NATherm1", "firmware": 65, "last_message": 1559297976, "rf_status": 59, "battery_vp": 3798, "therm_orientation": 3, "therm_relay_cmd": 0, "anticipating": false, "battery_percent": 53, "event_history": { "boiler_not_responding_events": [ { "K": 1506103090 }, { "K": 1514496738 }, { "K": 1514583682 }, { "K": 1518695843 }, { "K": 1518813960 } ], "boiler_responding_events": [ { "K": 1506281109 }, { "K": 1514552830 }, { "K": 1514757686 }, { "K": 1518798339 }, { "K": 1518965265 } ] }, "setpoint_history": [ { "setpoint": { "setpoint_mode": "hg" }, "timestamp": 1559229554 }, { "setpoint": { "setpoint_mode": "program" }, "timestamp": 1559229565 }, { "setpoint": { "setpoint_mode": "away" }, "timestamp": 1559229567 } ], "last_therm_seen": 1559297976, "setpoint": { "setpoint_mode": "away" }, "therm_program_list": [ { "zones": [ { "type": 0, "name": "Comfort", "id": 0, "temp": 21 }, { "type": 1, "name": "Night", "id": 1, "temp": 17 }, { "type": 5, "name": "Eco", "id": 4, "temp": 17 }, { "type": 2, "id": 2, "temp": 14 }, { "type": 3, "id": 3, "temp": 7 } ], "timetable": [ { "m_offset": 0, "id": 1 }, { "m_offset": 360, "id": 0 }, { "m_offset": 420, "id": 4 }, { "m_offset": 960, "id": 0 }, { "m_offset": 1410, "id": 1 }, { "m_offset": 1800, "id": 0 }, { "m_offset": 1860, "id": 4 }, { "m_offset": 2400, "id": 0 }, { "m_offset": 2850, "id": 1 }, { "m_offset": 3240, "id": 0 }, { "m_offset": 3300, "id": 4 }, { "m_offset": 3840, "id": 0 }, { "m_offset": 4290, "id": 1 }, { "m_offset": 4680, "id": 0 }, { "m_offset": 4740, "id": 4 }, { "m_offset": 5280, "id": 0 }, { "m_offset": 5730, "id": 1 }, { "m_offset": 6120, "id": 0 }, { "m_offset": 6180, "id": 4 }, { "m_offset": 6720, "id": 0 }, { "m_offset": 7170, "id": 1 }, { "m_offset": 7620, "id": 0 }, { "m_offset": 8610, "id": 1 }, { "m_offset": 9060, "id": 0 }, { "m_offset": 10050, "id": 1 } ], "name": "Default", "program_id": "591b54a2764ff4d50d8b5795", "selected": true } ], "measured": { "time": 1559297836, "temperature": 19.8, "setpoint_temp": 12 } } ], "station_name": "Thermostat", "last_plug_seen": 1559297986 } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.12061500549316, "time_server": 1559300497 }jabesq-org-pyatmo-6216472/fixtures/archive/too_many_connections.json000066400000000000000000000000471466116727400257030ustar00rootroot00000000000000{ "error": "too_many_connections" }jabesq-org-pyatmo-6216472/fixtures/archive/weatherstation_data_simple.json000066400000000000000000000551761466116727400270740ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:37:11:ca", "cipher_id": "enc:16:zjiZF/q8jTScXVdDa/kvhUAIUPGeYszaD1ClEf8byAJkRjxc5oth7cAocrMUIApX", "date_setup": 1544558432, "last_setup": 1544558432, "type": "NAMain", "last_status_store": 1559413181, "module_name": "NetatmoIndoor", "firmware": 137, "last_upgrade": 1544558433, "wifi_status": 45, "reachable": true, "co2_calibrating": false, "station_name": "MyStation", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 664, "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1559413171, "Temperature": 24.6, "CO2": 749, "Humidity": 36, "Noise": 37, "Pressure": 1017.3, "AbsolutePressure": 939.7, "min_temp": 23.4, "max_temp": 25.6, "date_min_temp": 1559371924, "date_max_temp": 1559411964, "temp_trend": "stable", "pressure_trend": "down" }, "modules": [ { "_id": "12:34:56:36:fc:de", "type": "NAModule1", "module_name": "NetatmoOutdoor", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1544558433, "reachable": true, "dashboard_data": { "time_utc": 1559413157, "Temperature": 28.6, "Humidity": 24, "min_temp": 16.9, "max_temp": 30.3, "date_min_temp": 1559365579, "date_max_temp": 1559404698, "temp_trend": "down" }, "firmware": 46, "last_message": 1559413177, "last_seen": 1559413157, "rf_status": 65, "battery_vp": 5738, "battery_percent": 87 }, { "_id": "12:34:56:07:bb:3e", "type": "NAModule4", "module_name": "Kitchen", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548956696, "reachable": true, "dashboard_data": { "time_utc": 1559413125, "Temperature": 28, "CO2": 503, "Humidity": 26, "min_temp": 25, "max_temp": 28, "date_min_temp": 1559371577, "date_max_temp": 1559412561, "temp_trend": "up" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 73, "battery_vp": 5687, "battery_percent": 83 }, { "_id": "12:34:56:07:bb:0e", "type": "NAModule4", "module_name": "Livingroom", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548957209, "reachable": true, "dashboard_data": { "time_utc": 1559413093, "Temperature": 26.4, "CO2": 451, "Humidity": 31, "min_temp": 25.1, "max_temp": 26.4, "date_min_temp": 1559365290, "date_max_temp": 1559413093, "temp_trend": "stable" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413093, "rf_status": 84, "battery_vp": 5626, "battery_percent": 79 }, { "_id": "12:34:56:03:1b:e4", "type": "NAModule2", "module_name": "Garden", "data_type": [ "Wind" ], "last_setup": 1549193862, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "WindStrength": 4, "WindAngle": 217, "GustStrength": 9, "GustAngle": 206, "max_wind_str": 21, "max_wind_angle": 217, "date_max_wind_str": 1559386669 }, "firmware": 19, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 59, "battery_vp": 5689, "battery_percent": 85 }, { "_id": "12:34:56:05:51:20", "type": "NAModule3", "module_name": "Yard", "data_type": [ "Rain" ], "last_setup": 1549194580, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "Rain": 0, "sum_rain_24": 0, "sum_rain_1": 0 }, "firmware": 8, "last_message": 1559413177, "last_seen": 1559413170, "rf_status": 67, "battery_vp": 5860, "battery_percent": 93 } ] }, { "_id": "12 :34: 56:36:fd:3c", "station_name": "Valley Road", "date_setup": 1545897146, "last_setup": 1545897146, "type": "NAMain", "last_status_store": 1581835369, "firmware": 137, "last_upgrade": 1545897125, "wifi_status": 53, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 69, "city": "Valley", "country": "AU", "timezone": "Australia/Hobart", "location": [ 148.444226, -41.721282 ] }, "read_only": true, "dashboard_data": { "time_utc": 1581835330, "Temperature": 22.4, "CO2": 471, "Humidity": 46, "Noise": 47, "Pressure": 1011.5, "AbsolutePressure": 1002.8, "min_temp": 18.1, "max_temp": 22.5, "date_max_temp": 1581829891, "date_min_temp": 1581794878, "temp_trend": "stable", "pressure_trend": "stable" }, "modules": [ { "_id": "12 :34: 56:36:e6:c0", "type": "NAModule1", "module_name": "Module", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1545897146, "battery_percent": 22, "reachable": false, "firmware": 46, "last_message": 1572497781, "last_seen": 1572497742, "rf_status": 88, "battery_vp": 4118 }, { "_id": "12:34:56:05:25:6e", "type": "NAModule3", "module_name": "Rain Gauge", "data_type": [ "Rain" ], "last_setup": 1553997427, "battery_percent": 82, "reachable": true, "firmware": 8, "last_message": 1581835362, "last_seen": 1581835354, "rf_status": 78, "battery_vp": 5594, "dashboard_data": { "time_utc": 1581835329, "Rain": 0, "sum_rain_1": 0, "sum_rain_24": 0 } } ] }, { "_id": "12:34:56:32:a7:60", "home_name": "Ateljen", "date_setup": 1566714693, "last_setup": 1566714693, "type": "NAMain", "last_status_store": 1588481079, "module_name": "Indoor", "firmware": 177, "last_upgrade": 1566714694, "wifi_status": 50, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481073, "Temperature": 18.2, "CO2": 542, "Humidity": 45, "Noise": 45, "Pressure": 1013, "AbsolutePressure": 1001.9, "min_temp": 18.2, "max_temp": 19.5, "date_max_temp": 1588456861, "date_min_temp": 1588479561, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:32:db:06", "type": "NAModule1", "last_setup": 1587635819, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 100, "reachable": false, "firmware": 255, "last_message": 0, "last_seen": 0, "rf_status": 255, "battery_vp": 65535 } ] }, { "_id": "12:34:56:1c:68:2e", "station_name": "Bol\u00e5s", "date_setup": 1470935400, "last_setup": 1470935400, "type": "NAMain", "last_status_store": 1588481399, "module_name": "Inne - Nere", "firmware": 177, "last_upgrade": 1470935401, "wifi_status": 13, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481387, "Temperature": 20.8, "CO2": 674, "Humidity": 41, "Noise": 34, "Pressure": 1012.1, "AbsolutePressure": 1001, "min_temp": 20.8, "max_temp": 22.2, "date_max_temp": 1588456859, "date_min_temp": 1588480176, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:02:b3:da", "type": "NAModule3", "module_name": "Regnm\u00e4tare", "last_setup": 1470937706, "data_type": [ "Rain" ], "battery_percent": 81, "reachable": true, "firmware": 12, "last_message": 1588481393, "last_seen": 1588481386, "rf_status": 67, "battery_vp": 5582, "dashboard_data": { "time_utc": 1588481386, "Rain": 0, "sum_rain_1": 0, "sum_rain_24": 0.1 } }, { "_id": "12:34:56:03:76:60", "type": "NAModule4", "module_name": "Inne - Uppe", "last_setup": 1470938089, "data_type": [ "Temperature", "CO2", "Humidity" ], "battery_percent": 14, "reachable": true, "firmware": 50, "last_message": 1588481393, "last_seen": 1588481374, "rf_status": 70, "battery_vp": 4448, "dashboard_data": { "time_utc": 1588481374, "Temperature": 19.6, "CO2": 696, "Humidity": 41, "min_temp": 19.6, "max_temp": 20.5, "date_max_temp": 1588456817, "date_min_temp": 1588481374, "temp_trend": "stable" } }, { "_id": "12:34:56:32:db:06", "type": "NAModule1", "module_name": "Ute", "last_setup": 1566326027, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 81, "reachable": true, "firmware": 50, "last_message": 1588481393, "last_seen": 1588481380, "rf_status": 61, "battery_vp": 5544, "dashboard_data": { "time_utc": 1588481380, "Temperature": 6.4, "Humidity": 91, "min_temp": 3.6, "max_temp": 6.4, "date_max_temp": 1588481380, "date_min_temp": 1588471383, "temp_trend": "up" } } ] }, { "_id": "12:34:56:1d:68:2e", "date_setup": 1470935500, "last_setup": 1470935500, "type": "NAMain", "last_status_store": 1588481399, "module_name": "Basisstation", "firmware": 177, "last_upgrade": 1470935401, "wifi_status": 13, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481387, "Temperature": 20.8, "CO2": 674, "Humidity": 41, "Noise": 34, "Pressure": 1012.1, "AbsolutePressure": 1001, "min_temp": 20.8, "max_temp": 22.2, "date_max_temp": 1588456859, "date_min_temp": 1588480176, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [] }, { "_id": "12:34:56:58:c8:54", "date_setup": 1605594014, "last_setup": 1605594014, "type": "NAMain", "last_status_store": 1605878352, "firmware": 178, "wifi_status": 47, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 65, "city": "Njurunda District", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 17.123456, 62.123456 ] }, "station_name": "Njurunda (Indoor)", "home_id": "5fb36b9ec68fd10c6467ca65", "home_name": "Njurunda", "dashboard_data": { "time_utc": 1605878349, "Temperature": 19.7, "CO2": 993, "Humidity": 40, "Noise": 40, "Pressure": 1015.6, "AbsolutePressure": 1007.8, "min_temp": 19.7, "max_temp": 20.4, "date_max_temp": 1605826917, "date_min_temp": 1605873207, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:58:e6:38", "type": "NAModule1", "last_setup": 1605594034, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 100, "reachable": true, "firmware": 50, "last_message": 1605878347, "last_seen": 1605878328, "rf_status": 62, "battery_vp": 6198, "dashboard_data": { "time_utc": 1605878328, "Temperature": 0.6, "Humidity": 77, "min_temp": -2.1, "max_temp": 1.5, "date_max_temp": 1605865920, "date_min_temp": 1605826904, "temp_trend": "down" } } ] } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.91107702255249, "time_server": 1559413602 }jabesq-org-pyatmo-6216472/fixtures/archive/weatherstation_data_unreachable_station.json000066400000000000000000000245331466116727400316060ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:37:11:ca", "cipher_id": "enc:16:zjiZF/q8jTScXVdDa/kvhUAIUPGeYszaD1ClEf8byAJkRjxc5oth7cAocrMUIApX", "date_setup": 1544558432, "last_setup": 1544558432, "type": "NAMain", "last_status_store": 1559413181, "module_name": "NetatmoIndoor", "firmware": 137, "last_upgrade": 1544558433, "wifi_status": 45, "reachable": true, "co2_calibrating": false, "station_name": "MyStation", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 664, "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1559413171, "Temperature": 24.6, "CO2": 749, "Humidity": 36, "Noise": 37, "Pressure": 1017.3, "AbsolutePressure": 939.7, "min_temp": 23.4, "max_temp": 25.6, "date_min_temp": 1559371924, "date_max_temp": 1559411964, "temp_trend": "stable", "pressure_trend": "down" }, "modules": [ { "_id": "12:34:56:36:fc:de", "type": "NAModule1", "module_name": "NetatmoOutdoor", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1544558433, "reachable": true, "dashboard_data": { "time_utc": 1559413157, "Temperature": 28.6, "Humidity": 24, "min_temp": 16.9, "max_temp": 30.3, "date_min_temp": 1559365579, "date_max_temp": 1559404698, "temp_trend": "down" }, "firmware": 46, "last_message": 1559413177, "last_seen": 1559413157, "rf_status": 65, "battery_vp": 5738, "battery_percent": 87 }, { "_id": "12:34:56:07:bb:3e", "type": "NAModule4", "module_name": "Kitchen", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548956696, "reachable": true, "dashboard_data": { "time_utc": 1559413125, "Temperature": 28, "CO2": 503, "Humidity": 26, "min_temp": 25, "max_temp": 28, "date_min_temp": 1559371577, "date_max_temp": 1559412561, "temp_trend": "up" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 73, "battery_vp": 5687, "battery_percent": 83 }, { "_id": "12:34:56:07:bb:0e", "type": "NAModule4", "module_name": "Livingroom", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548957209, "reachable": true, "dashboard_data": { "time_utc": 1559413093, "Temperature": 26.4, "CO2": 451, "Humidity": 31, "min_temp": 25.1, "max_temp": 26.4, "date_min_temp": 1559365290, "date_max_temp": 1559413093, "temp_trend": "stable" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413093, "rf_status": 84, "battery_vp": 5626, "battery_percent": 79 }, { "_id": "12:34:56:03:1b:e4", "type": "NAModule2", "module_name": "Garden", "data_type": [ "Wind" ], "last_setup": 1549193862, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "WindStrength": 4, "WindAngle": 217, "GustStrength": 9, "GustAngle": 206, "max_wind_str": 21, "max_wind_angle": 217, "date_max_wind_str": 1559386669 }, "firmware": 19, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 59, "battery_vp": 5689, "battery_percent": 85 }, { "_id": "12:34:56:05:51:20", "type": "NAModule3", "module_name": "Yard", "data_type": [ "Rain" ], "last_setup": 1549194580, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "Rain": 0, "sum_rain_24": 0, "sum_rain_1": 0 }, "firmware": 8, "last_message": 1559413177, "last_seen": 1559413170, "rf_status": 67, "battery_vp": 5860, "battery_percent": 93 } ] }, { "_id": "12:34:56:00:aa:01", "station_name": "MyRemoteStation", "date_setup": 1499189962, "last_setup": 1499189962, "type": "NAMain", "last_status_store": 1554506294, "module_name": "Indoor", "firmware": 132, "last_upgrade": 1499189915, "wifi_status": 46, "reachable": false, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 6, "city": "Harstad", "country": "NO", "timezone": "Europe/Oslo", "location": [ 59.895000, 10.620000 ] }, "modules": [ { "_id": "12:34:56:00:aa:02", "type": "NAModule1", "module_name": "Outdoor", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1499189902, "battery_percent": 17, "reachable": false, "firmware": 44, "last_message": 1536805739, "last_seen": 1536696388, "rf_status": 87, "battery_vp": 4018, "main_device": "12:34:56:00:aa:01" }, { "_id": "12:34:56:00:aa:03", "type": "NAModule2", "module_name": "Wind Gauge", "data_type": [ "Wind" ], "last_setup": 1499190606, "battery_percent": 3, "reachable": false, "firmware": 18, "last_message": 1537259554, "last_seen": 1537259554, "rf_status": 74, "battery_vp": 4013, "main_device": "12:34:56:00:aa:01" } ] } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.91107702255249, "time_server": 1559413602 }jabesq-org-pyatmo-6216472/fixtures/archive/weatherstation_measure.json000066400000000000000000000014121466116727400262330ustar00rootroot00000000000000{ "body": { "1544558433": [ 28.1 ], "1544558449": [ 28.4 ], "1544558504": [ 27 ], "1544558807": [ 24 ], "1544559062": [ 23.8 ], "1544559211": [ 26.1 ], "1544559308": [ 24.9 ], "1544559415": [ 24.6 ], "1544559576": [ 24.2 ], "1544559974": [ 26.9 ], "1544560021": [ 27.1 ], "1544560058": [ 27.4 ], "1544560361": [ 26 ] }, "status": "ok", "time_exec": 0.33915495872498, "time_server": 1560590041 }jabesq-org-pyatmo-6216472/fixtures/getevents.json000066400000000000000000000151741466116727400220460ustar00rootroot00000000000000{ "body": { "home": { "id": "91763b24c43d3e344f424e8b", "events": [ { "id": "11111111111111111f7763a6d", "type": "outdoor", "time": 1645794709, "module_id": "12:34:56:10:b9:0e", "video_id": "11111111-2222-3333-4444-b42f0fc4cfad", "video_status": "available", "subevents": [ { "id": "11111111-2222-3333-4444-013560107fce", "type": "human", "time": 1645794709, "verified": true, "offset": 0, "snapshot": { "url": "https://netatmocameraimage.blob.core.windows.net/production/000000a722374" }, "vignette": { "url": "https://netatmocameraimage.blob.core.windows.net/production/0000009625c0f" }, "message": "Person erfasst" }, { "id": "11111111-2222-3333-4444-0b0bc962df43", "type": "vehicle", "time": 1645794716, "verified": true, "offset": 15, "snapshot": { "url": "https://netatmocameraimage.blob.core.windows.net/production/00000033f9f96" }, "vignette": { "url": "https://netatmocameraimage.blob.core.windows.net/production/000000cba08af" }, "message": "Fahrzeug erfasst" }, { "id": "11111111-2222-3333-4444-129e72195968", "type": "human", "time": 1645794716, "verified": true, "offset": 15, "snapshot": { "filename": "vod/11111/events/22222/snapshot_129e72195968.jpg" }, "vignette": { "filename": "vod/11111/events/22222/vignette_129e72195968.jpg" }, "message": "Person erfasst" }, { "id": "11111111-2222-3333-4444-dae4d7e4f24e", "type": "human", "time": 1645794718, "verified": true, "offset": 17, "snapshot": { "filename": "vod/11111/events/22222/snapshot_dae4d7e4f24e.jpg" }, "vignette": { "filename": "vod/11111/events/22222/vignette_dae4d7e4f24e.jpg" }, "message": "Person erfasst" } ] }, { "id": "1111111111111111e7e40c353", "type": "connection", "time": 1645784799, "module_id": "12:34:56:10:b9:0e", "message": "Front verbunden" }, { "id": "11111111111111144e3115860", "type": "boot", "time": 1645784775, "module_id": "12:34:56:10:b9:0e", "message": "Front gestartet" }, { "id": "11111111111111169804049ca", "type": "disconnection", "time": 1645773806, "module_id": "12:34:56:10:b9:0e", "message": "Front getrennt" }, { "id": "1111111111111117cb8147ffd", "type": "outdoor", "time": 1645712826, "module_id": "12:34:56:10:b9:0e", "video_id": "11111111-2222-3333-4444-5091e1903f8d", "video_status": "available", "subevents": [ { "id": "11111111-2222-3333-4444-b7d28e3ccc38", "type": "human", "time": 1645712826, "verified": true, "offset": 0, "snapshot": { "url": "https://netatmocameraimage.blob.core.windows.net/production/000000a0ca642" }, "vignette": { "url": "https://netatmocameraimage.blob.core.windows.net/production/00000031b0ed4" }, "message": "Person erfasst" } ] }, { "id": "1111111111111119df3d2de6", "type": "person_home", "time": 1645902000, "module_id": "12:34:56:00:f1:62", "message": "Home Assistant Cloud definiert John Doe und Jane Doe als \"Zu Hause\"" }, { "id": "1111111111111112c91b3628", "type": "person", "time": 1645901266, "module_id": "12:34:56:00:f1:62", "snapshot": { "url": "https://netatmocameraimage.blob.core.windows.net/production/0000081d4f42875d9" }, "video_id": "11111111-2222-3333-4444-314d161525db", "video_status": "available", "message": "John Doe gesehen", "person_id": "91827374-7e04-5298-83ad-a0cb8372dff1", "out_of_sight": false }, { "id": "1111111111111115166b1283", "type": "tag_open", "time": 1645897638, "module_id": "12:34:56:00:86:99", "message": "Window Hall: immer noch offen" } ] } }, "status": "ok", "time_exec": 0.24369096755981445, "time_server": 1645897231 }jabesq-org-pyatmo-6216472/fixtures/gethomecoachsdata.json000066400000000000000000000153641466116727400235060ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:26:69:0c", "cipher_id": "enc:16:1UqwQlYV5AY2pfyEi5H47dmmFOOL3mCUo+KAkchL4A2CLI5u0e45Xr5jeAswO+XO", "date_setup": 1544560184, "last_setup": 1544560184, "type": "NHC", "last_status_store": 1558268332, "firmware": 45, "last_upgrade": 1544560186, "wifi_status": 58, "reachable": false, "co2_calibrating": false, "station_name": "Bedroom", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:25:cf:a8", "cipher_id": "enc:16:A+Jm0yFWBwUyKinFDutPZK7I2PuHN1fqaE9oB/KF+McbFs3oN9CKpR/dYbqL4om2", "date_setup": 1544562192, "last_setup": 1544562192, "type": "NHC", "last_status_store": 1559198922, "firmware": 45, "last_upgrade": 1544562194, "wifi_status": 41, "reachable": true, "co2_calibrating": false, "station_name": "Kitchen", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:26:65:14", "cipher_id": "enc:16:7kK6ZzG4L7NgfZZ6+dMvNxw4l6vXu+88SEJkCUklNdPa4KYIHmsfa1moOilEK61i", "date_setup": 1544564061, "last_setup": 1544564061, "type": "NHC", "last_status_store": 1559067159, "firmware": 45, "last_upgrade": 1544564302, "wifi_status": 66, "reachable": true, "co2_calibrating": false, "station_name": "Livingroom", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] } }, { "_id": "12:34:56:3e:c5:46", "station_name": "Parents Bedroom", "date_setup": 1570732241, "last_setup": 1570732241, "type": "NHC", "last_status_store": 1572073818, "module_name": "Indoor", "firmware": 45, "wifi_status": 67, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1572073816, "Temperature": 20.3, "CO2": 494, "Humidity": 63, "Noise": 42, "Pressure": 1014.5, "AbsolutePressure": 1004.1, "health_idx": 1, "min_temp": 20.3, "max_temp": 21.6, "date_max_temp": 1572059333, "date_min_temp": 1572073816 } }, { "_id": "12:34:56:26:68:92", "station_name": "Baby Bedroom", "date_setup": 1571342643, "last_setup": 1571342643, "type": "NHC", "last_status_store": 1572073995, "module_name": "Indoor", "firmware": 45, "wifi_status": 68, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure", "health_idx" ], "place": { "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1572073994, "Temperature": 21.6, "CO2": 1053, "Humidity": 66, "Noise": 45, "Pressure": 1021.4, "AbsolutePressure": 1011, "health_idx": 1, "min_temp": 20.9, "max_temp": 21.6, "date_max_temp": 1572073690, "date_min_temp": 1572064254 } } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.095954179763794, "time_server": 1559463229 }1c1d1694c91210991f1b006755f6bde04cf29a93.paxheader00006660000000000000000000000276146611672740020311xustar00rootroot00000000000000190 path=jabesq-org-pyatmo-6216472/fixtures/getmeasure_sum_energy_buy_from_grid,sum_energy_buy_from_grid$0,sum_energy_buy_from_grid$1,sum_energy_buy_from_grid$2_12_34_56_00_00_a1_4c_da.json 1c1d1694c91210991f1b006755f6bde04cf29a93.data000066400000000000000000000315701466116727400171500ustar00rootroot00000000000000{ "body": [ { "beg_time": 1644049789, "step_time": 3600, "value": [ [ null, 197 ,null, null], [null, 262 ,null, null], [null, 168 ,null, null], [null, 219 ,null, null], [null, 224 ,null, null], [null, 299 ,null, null], [null, 343 ,null, null], [null, 443 ,null, null], [null, 317 ,null, null], [null, 229 ,null, null], [null, 147 ,null, null], [null, 178 ,null, null], [null, 340 ,null, null], [null, 536 ,null, null], [null, 471 ,null, null], [null, 397 ,null, null], [null, 290 ,null, null], [null, 302 ,null, null], [null, 309 ,null, null], [null, 219 ,null, null], [null, 154 ,null, null], [null, 163 ,null, null], [null, 146 ,null, null], [null, 189 ,null, null], [null, 256 ,null, null], [null, 162 ,null, null], [null, 1288 ,null, null], [null, 256 ,null, null], [null, 709 ,null, null], [null, 310 ,null, null], [null, 379 ,null, null], [null, 296 ,null, null], [null, 230 ,null, null], [null, 505 ,null, null], [null, 362 ,null, null], [null, 611 ,null, null], [null, 597 ,null, null], [null, 505 ,null, null], [null, 431 ,null, null], [null, 1538 ,null, null], [null, 265 ,null, null], [null, 187 ,null, null], [null, 162 ,null, null], [null, 150 ,null, null], [null, 155 ,null, null], [null, 147 ,null, null], [null, 211 ,null, null], [null, 211 ,null, null], [null, 272 ,null, null], [null, 271 ,null, null], [null, 331 ,null, null], [null, 180 ,null, null], [null, 184 ,null, null], [null, 182 ,null, null], [null, 232 ,null, null], [null, 288 ,null, null], [null, 266 ,null, null], [null, 256 ,null, null], [null, 249 ,null, null], [null, 372 ,null, null], [null, 379 ,null, null], [null, 585 ,null, null], [null, 387 ,null, null], [null, 277 ,null, null], [null, 223 ,null, null], [null, 202 ,null, null], [null, 163 ,null, null], [null, 143 ,null, null], [null, 158 ,null, null], [null, 145 ,null, null], [null, 232 ,null, null], [null, 231 ,null, null], [null, 160 ,null, null], [null, 261 ,null, null], [null, 376 ,null, null], [null, 216 ,null, null], [null, 202 ,null, null], [null, 295 ,null, null], [null, 310 ,null, null], [null, 235 ,null, null], [null, 188 ,null, null], [null, 269 ,null, null], [null, 250 ,null, null], [null, 334 ,null, null], [null, 434 ,null, null], [null, 353 ,null, null], [null, 279 ,null, null], [null, 266 ,null, null], [null, 226 ,null, null], [null, 179 ,null, null], [null, 149 ,null, null], [null, 146 ,null, null], [null, 143 ,null, null], [null, 136 ,null, null], [null, 173 ,null, null], [null, 221 ,null, null], [null, 190 ,null, null], [null, 177 ,null, null], [null, 290 ,null, null], [null, 352 ,null, null], [null, 252 ,null, null], [null, 284 ,null, null], [null, 173 ,null, null], [null, 165 ,null, null], [null, 144 ,null, null], [null, 175 ,null, null], [null, 268 ,null, null], [null, 363 ,null, null], [null, 544 ,null, null], [null, 515 ,null, null], [null, 525 ,null, null], [null, 431 ,null, null], [null, 225 ,null, null], [null, 183 ,null, null], [null, 178 ,null, null], [null, 155 ,null, null], [null, 170 ,null, null], [null, 156 ,null, null], [null, 169 ,null, null], [null, 226 ,null, null], [null, 255 ,null, null], [null, 273 ,null, null], [null, 466 ,null, null], [null, 406 ,null, null], [null, 333 ,null, null], [null, 194 ,null, null], [null, 234 ,null, null], [null, 271 ,null, null], [null, 238 ,null, null], [null, 221 ,null, null], [null, 205 ,null, null], [null, 258 ,null, null], [null, 430 ,null, null], [null, 446 ,null, null], [null, 390 ,null, null], [null, 306 ,null, null], [null, 223 ,null, null], [null, 165 ,null, null], [null, 154 ,null, null], [null, 147 ,null, null], [null, 155 ,null, null], [null, 140 ,null, null], [null, 153 ,null, null], [null, 228 ,null, null], [null, 237 ,null, null], [null, 201 ,null, null], [null, 183 ,null, null], [null, 194 ,null, null], [null, 135 ,null, null], [null, 206 ,null, null], [null, 215 ,null, null], [null, 147 ,null, null], [null, 159 ,null, null], [null, 185 ,null, null], [null, 168 ,null, null], [null, 257 ,null, null], [null, 262 ,null, null], [null, 141 ,null, null], [null, 151 ,null, null], [null, 157 ,null, null], [null, 133 ,null, null], [null, 147 ,null, null], [null, 135 ,null, null], [null, 139 ,null, null], [null, 136 ,null, null], [null, 127 ,null, null], [null, 169 ,null, null], [null, 259, null, null ] ] } ], "status": "ok", "time_exec": 0.5533828735351562, "time_server": 1647935044 } 3e11402ef9fbb9a2e47a347e9c1af2d87701f522.paxheader00006660000000000000000000000276146611672740020533xustar00rootroot00000000000000190 path=jabesq-org-pyatmo-6216472/fixtures/getmeasure_sum_energy_buy_from_grid,sum_energy_buy_from_grid$0,sum_energy_buy_from_grid$1,sum_energy_buy_from_grid$2_98_76_54_32_10_00_00_69.json 3e11402ef9fbb9a2e47a347e9c1af2d87701f522.data000066400000000000000000000065261466116727400173750ustar00rootroot00000000000000{ "body": [ { "beg_time": 1721772900, "step_time": 1800, "value": [ [ null, 20, null, null ], [ null, 19, null, null ], [ null, 16, null, null ], [ null, 11, null, null ], [ null, 18, null, null ], [ null, 14, null, null ], [ null, 14, null, null ], [ null, 64, null, null ], [ null, 100, null, null ], [ null, 58, null, null ], [ null, 39, null, null ], [ null, 24, null, null ], [ null, 19, null, null ], [ null, 19, null, null ], [ null, 712, null, null ], [ null, 724, null, null ], [ null, 711, null, null ], [ null, 498, 212, null ], [ null, null, 717, null ], [ null, null, 714, null ], [ null, null, 714, null ], [ null, null, 711, null ], [ null, null, 706, null ], [ null, null, 704, null ], [ null, null, 706, null ], [ null, null, 709, null ], [ null, null, 714, null ], [ null, null, 712, null ], [ null, null, 238, 477 ], [ null, null, null, 714 ], [ null, null, null, 722 ], [ null, null, null, 713 ], [ null, null, null, 709 ], [ null, null, null, 714 ], [ null, null, 477, 241 ], [ null, null, 710, null ], [ null, null, 710, null ], [ null, null, 707, null ], [ null, null, 16, null ] ] } ], "status": "ok", "time_exec": 0.025647878646850586, "time_server": 1721852913 }jabesq-org-pyatmo-6216472/fixtures/getpublicdata.json000066400000000000000000000157671466116727400226620ustar00rootroot00000000000000{ "status": "ok", "time_server": 1560248397, "time_exec": 0, "body": [ { "_id": "70:ee:50:36:94:7c", "place": { "location": [8.791382999999996, 50.2136394], "timezone": "Europe/Berlin", "country": "DE", "altitude": 132 }, "mark": 14, "measures": { "02:00:00:36:f2:94": { "res": { "1560248022": [21.4, 62] }, "type": ["temperature", "humidity"] }, "70:ee:50:36:94:7c": { "res": { "1560248030": [1010.6] }, "type": ["pressure"] }, "05:00:00:05:33:84": { "rain_60min": 0.2, "rain_24h": 12.322000000000001, "rain_live": 0.5, "rain_timeutc": 1560248022 } }, "modules": ["05:00:00:05:33:84", "02:00:00:36:f2:94"], "module_types": { "05:00:00:05:33:84": "NAModule3", "02:00:00:36:f2:94": "NAModule1" } }, { "_id": "70:ee:50:1f:68:9e", "place": { "location": [8.795445200000017, 50.2130169], "timezone": "Europe/Berlin", "country": "DE", "altitude": 125 }, "mark": 14, "measures": { "02:00:00:1f:82:28": { "res": { "1560248312": [21.1, 69] }, "type": ["temperature", "humidity"] }, "70:ee:50:1f:68:9e": { "res": { "1560248344": [1007.3] }, "type": ["pressure"] }, "05:00:00:02:bb:6e": { "rain_60min": 0, "rain_24h": 9.999, "rain_live": 0, "rain_timeutc": 1560248344 } }, "modules": ["02:00:00:1f:82:28", "05:00:00:02:bb:6e"], "module_types": { "02:00:00:1f:82:28": "NAModule1", "05:00:00:02:bb:6e": "NAModule3" } }, { "_id": "70:ee:50:27:25:b0", "place": { "location": [8.7807159, 50.1946167], "timezone": "Europe/Berlin", "country": "DE", "altitude": 112 }, "mark": 14, "measures": { "02:00:00:27:19:b2": { "res": { "1560247889": [23.2, 60] }, "type": ["temperature", "humidity"] }, "70:ee:50:27:25:b0": { "res": { "1560247907": [1012.8] }, "type": ["pressure"] }, "05:00:00:03:5d:2e": { "rain_60min": 0, "rain_24h": 11.716000000000001, "rain_live": 0, "rain_timeutc": 1560247896 } }, "modules": ["02:00:00:27:19:b2", "05:00:00:03:5d:2e"], "module_types": { "02:00:00:27:19:b2": "NAModule1", "05:00:00:03:5d:2e": "NAModule3" } }, { "_id": "70:ee:50:04:ed:7a", "place": { "location": [8.785034, 50.192169], "timezone": "Europe/Berlin", "country": "DE", "altitude": 112 }, "mark": 14, "measures": { "02:00:00:04:c2:2e": { "res": { "1560248137": [19.8, 76] }, "type": ["temperature", "humidity"] }, "70:ee:50:04:ed:7a": { "res": { "1560248152": [1005.4] }, "type": ["pressure"] } }, "modules": ["02:00:00:04:c2:2e"], "module_types": { "02:00:00:04:c2:2e": "NAModule1" } }, { "_id": "70:ee:50:27:9f:2c", "place": { "location": [8.785342, 50.193573], "timezone": "Europe/Berlin", "country": "DE", "altitude": 116 }, "mark": 1, "measures": { "02:00:00:27:aa:70": { "res": { "1560247821": [25.5, 56] }, "type": ["temperature", "humidity"] }, "70:ee:50:27:9f:2c": { "res": { "1560247853": [1010.6] }, "type": ["pressure"] } }, "modules": ["02:00:00:27:aa:70"], "module_types": { "02:00:00:27:aa:70": "NAModule1" } }, { "_id": "70:ee:50:01:20:fa", "place": { "location": [8.7953, 50.195241], "timezone": "Europe/Berlin", "country": "DE", "altitude": 119 }, "mark": 1, "measures": { "02:00:00:00:f7:ba": { "res": { "1560247831": [27.4, 58] }, "type": ["temperature", "humidity"] }, "70:ee:50:01:20:fa": { "res": { "1560247876": [1014.4] }, "type": ["pressure"] } }, "modules": ["02:00:00:00:f7:ba"], "module_types": { "02:00:00:00:f7:ba": "NAModule1" } }, { "_id": "70:ee:50:3c:02:78", "place": { "location": [8.795953681700666, 50.19530139868166], "timezone": "Europe/Berlin", "country": "DE", "altitude": 119 }, "mark": 7, "measures": { "02:00:00:3c:21:f2": { "res": { "1560248225": [23.3, 58] }, "type": ["temperature", "humidity"] }, "70:ee:50:3c:02:78": { "res": { "1560248270": [1011.7] }, "type": ["pressure"] } }, "modules": ["02:00:00:3c:21:f2"], "module_types": { "02:00:00:3c:21:f2": "NAModule1" } }, { "_id": "70:ee:50:36:a9:fc", "place": { "location": [8.801164269110814, 50.19596181704958], "timezone": "Europe/Berlin", "country": "DE", "altitude": 113 }, "mark": 14, "measures": { "02:00:00:36:a9:50": { "res": { "1560248145": [20.1, 67] }, "type": ["temperature", "humidity"] }, "70:ee:50:36:a9:fc": { "res": { "1560248191": [1010] }, "type": ["pressure"] }, "05:00:00:02:92:82": { "rain_60min": 0, "rain_24h": 11.009, "rain_live": 0, "rain_timeutc": 1560248184 }, "06:00:00:03:19:76": { "wind_strength": 15, "wind_angle": 17, "gust_strength": 31, "gust_angle": 217, "wind_timeutc": 1560248190 } }, "modules": [ "05:00:00:02:92:82", "02:00:00:36:a9:50", "06:00:00:03:19:76" ], "module_types": { "05:00:00:02:92:82": "NAModule3", "02:00:00:36:a9:50": "NAModule1", "06:00:00:03:19:76": "NAModule2" } } ] } jabesq-org-pyatmo-6216472/fixtures/getstationsdata.json000066400000000000000000000512741466116727400232410ustar00rootroot00000000000000{ "body": { "devices": [ { "_id": "12:34:56:37:11:ca", "cipher_id": "enc:16:zjiZF/q8jTScXVdDa/kvhUAIUPGeYszaD1ClEf8byAJkRjxc5oth7cAocrMUIApX", "date_setup": 1544558432, "last_setup": 1544558432, "type": "NAMain", "last_status_store": 1559413181, "module_name": "NetatmoIndoor", "firmware": 137, "last_upgrade": 1544558433, "wifi_status": 45, "reachable": true, "co2_calibrating": false, "station_name": "MyStation", "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 664, "city": "Frankfurt", "country": "DE", "timezone": "Europe/Berlin", "location": [ 52.516263, 13.377726 ] }, "dashboard_data": { "time_utc": 1559413171, "Temperature": 24.6, "CO2": 749, "Humidity": 36, "Noise": 37, "Pressure": 1017.3, "AbsolutePressure": 939.7, "min_temp": 23.4, "max_temp": 25.6, "date_min_temp": 1559371924, "date_max_temp": 1559411964, "temp_trend": "stable", "pressure_trend": "down" }, "modules": [ { "_id": "12:34:56:36:fc:de", "type": "NAModule1", "module_name": "NetatmoOutdoor", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1544558433, "reachable": true, "dashboard_data": { "time_utc": 1559413157, "Temperature": 28.6, "Humidity": 24, "min_temp": 16.9, "max_temp": 30.3, "date_min_temp": 1559365579, "date_max_temp": 1559404698, "temp_trend": "down" }, "firmware": 46, "last_message": 1559413177, "last_seen": 1559413157, "rf_status": 65, "battery_vp": 5738, "battery_percent": 87 }, { "_id": "12:34:56:07:bb:3e", "type": "NAModule4", "module_name": "Kitchen", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548956696, "reachable": true, "dashboard_data": { "time_utc": 1559413125, "Temperature": 28, "CO2": 503, "Humidity": 26, "min_temp": 25, "max_temp": 28, "date_min_temp": 1559371577, "date_max_temp": 1559412561, "temp_trend": "up" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 73, "battery_vp": 5687, "battery_percent": 83 }, { "_id": "12:34:56:07:bb:0e", "type": "NAModule4", "module_name": "Livingroom", "data_type": [ "Temperature", "CO2", "Humidity" ], "last_setup": 1548957209, "reachable": true, "dashboard_data": { "time_utc": 1559413093, "Temperature": 26.4, "CO2": 451, "Humidity": 31, "min_temp": 25.1, "max_temp": 26.4, "date_min_temp": 1559365290, "date_max_temp": 1559413093, "temp_trend": "stable" }, "firmware": 44, "last_message": 1559413177, "last_seen": 1559413093, "rf_status": 84, "battery_vp": 5626, "battery_percent": 79 }, { "_id": "12:34:56:03:1b:e5", "type": "NAModule2", "module_name": "Garden", "data_type": [ "Wind" ], "last_setup": 1549193862, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "WindStrength": 4, "WindAngle": 217, "GustStrength": 9, "GustAngle": 206, "max_wind_str": 21, "max_wind_angle": 217, "date_max_wind_str": 1559386669 }, "firmware": 19, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 59, "battery_vp": 5689, "battery_percent": 85 }, { "_id": "12:34:56:05:51:20", "type": "NAModule3", "module_name": "Yard", "data_type": [ "Rain" ], "last_setup": 1549194580, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "Rain": 0, "sum_rain_24": 0, "sum_rain_1": 0 }, "firmware": 8, "last_message": 1559413177, "last_seen": 1559413170, "rf_status": 67, "battery_vp": 5860, "battery_percent": 93 } ] }, { "_id": "12 :34: 56:36:fd:3c", "station_name": "Valley Road", "date_setup": 1545897146, "last_setup": 1545897146, "type": "NAMain", "last_status_store": 1581835369, "firmware": 137, "last_upgrade": 1545897125, "wifi_status": 53, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 69, "city": "Valley", "country": "AU", "timezone": "Australia/Hobart", "location": [ 148.444226, -41.721282 ] }, "read_only": true, "dashboard_data": { "time_utc": 1581835330, "Temperature": 22.4, "CO2": 471, "Humidity": 46, "Noise": 47, "Pressure": 1011.5, "AbsolutePressure": 1002.8, "min_temp": 18.1, "max_temp": 22.5, "date_max_temp": 1581829891, "date_min_temp": 1581794878, "temp_trend": "stable", "pressure_trend": "stable" }, "modules": [ { "_id": "12 :34: 56:36:e6:c0", "type": "NAModule1", "module_name": "Module", "data_type": [ "Temperature", "Humidity" ], "last_setup": 1545897146, "battery_percent": 22, "reachable": false, "firmware": 46, "last_message": 1572497781, "last_seen": 1572497742, "rf_status": 88, "battery_vp": 4118 }, { "_id": "12:34:56:05:25:6e", "type": "NAModule3", "module_name": "Rain Gauge", "data_type": [ "Rain" ], "last_setup": 1553997427, "battery_percent": 82, "reachable": true, "firmware": 8, "last_message": 1581835362, "last_seen": 1581835354, "rf_status": 78, "battery_vp": 5594, "dashboard_data": { "time_utc": 1581835329, "Rain": 0, "sum_rain_1": 0, "sum_rain_24": 0 } } ] }, { "_id": "12:34:56:32:a7:60", "home_name": "Ateljen", "date_setup": 1566714693, "last_setup": 1566714693, "type": "NAMain", "last_status_store": 1588481079, "module_name": "Indoor", "firmware": 177, "last_upgrade": 1566714694, "wifi_status": 50, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481073, "Temperature": 18.2, "CO2": 542, "Humidity": 45, "Noise": 45, "Pressure": 1013, "AbsolutePressure": 1001.9, "min_temp": 18.2, "max_temp": 19.5, "date_max_temp": 1588456861, "date_min_temp": 1588479561, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:32:db:06", "type": "NAModule1", "last_setup": 1587635819, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 100, "reachable": false, "firmware": 255, "last_message": 0, "last_seen": 0, "rf_status": 255, "battery_vp": 65535 } ] }, { "_id": "12:34:56:1c:68:2e", "station_name": "Bol\u00e5s", "date_setup": 1470935400, "last_setup": 1470935400, "type": "NAMain", "last_status_store": 1588481399, "module_name": "Inne - Nere", "firmware": 177, "last_upgrade": 1470935401, "wifi_status": 13, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481387, "Temperature": 20.8, "CO2": 674, "Humidity": 41, "Noise": 34, "Pressure": 1012.1, "AbsolutePressure": 1001, "min_temp": 20.8, "max_temp": 22.2, "date_max_temp": 1588456859, "date_min_temp": 1588480176, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:02:b3:da", "type": "NAModule3", "module_name": "Regnm\u00e4tare", "last_setup": 1470937706, "data_type": [ "Rain" ], "battery_percent": 81, "reachable": true, "firmware": 12, "last_message": 1588481393, "last_seen": 1588481386, "rf_status": 67, "battery_vp": 5582, "dashboard_data": { "time_utc": 1588481386, "Rain": 0, "sum_rain_1": 0, "sum_rain_24": 0.1 } }, { "_id": "12:34:56:03:76:60", "type": "NAModule4", "module_name": "Inne - Uppe", "last_setup": 1470938089, "data_type": [ "Temperature", "CO2", "Humidity" ], "battery_percent": 14, "reachable": true, "firmware": 50, "last_message": 1588481393, "last_seen": 1588481374, "rf_status": 70, "battery_vp": 4448, "dashboard_data": { "time_utc": 1588481374, "Temperature": 19.6, "CO2": 696, "Humidity": 41, "min_temp": 19.6, "max_temp": 20.5, "date_max_temp": 1588456817, "date_min_temp": 1588481374, "temp_trend": "stable" } }, { "_id": "12:34:56:32:db:06", "type": "NAModule1", "module_name": "Ute", "last_setup": 1566326027, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 81, "reachable": true, "firmware": 50, "last_message": 1588481393, "last_seen": 1588481380, "rf_status": 61, "battery_vp": 5544, "dashboard_data": { "time_utc": 1588481380, "Temperature": 6.4, "Humidity": 91, "min_temp": 3.6, "max_temp": 6.4, "date_max_temp": 1588481380, "date_min_temp": 1588471383, "temp_trend": "up" } } ] }, { "_id": "12:34:56:1d:68:2e", "date_setup": 1470935500, "last_setup": 1470935500, "type": "NAMain", "last_status_store": 1588481399, "module_name": "Basisstation", "firmware": 177, "last_upgrade": 1470935401, "wifi_status": 13, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 93, "city": "Gothenburg", "country": "SE", "timezone": "Europe/Stockholm", "location": [ 11.6136629, 57.7006827 ] }, "dashboard_data": { "time_utc": 1588481387, "Temperature": 20.8, "CO2": 674, "Humidity": 41, "Noise": 34, "Pressure": 1012.1, "AbsolutePressure": 1001, "min_temp": 20.8, "max_temp": 22.2, "date_max_temp": 1588456859, "date_min_temp": 1588480176, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [] }, { "_id": "12:34:56:80:bb:26", "station_name": "MYHOME (Palier)", "date_setup": 1558709904, "last_setup": 1558709904, "type": "NAMain", "last_status_store": 1644582700, "module_name": "Palier", "firmware": 181, "last_upgrade": 1558709906, "wifi_status": 57, "reachable": true, "co2_calibrating": false, "data_type": [ "Temperature", "CO2", "Humidity", "Noise", "Pressure" ], "place": { "altitude": 329, "city": "Someplace", "country": "FR", "timezone": "Europe/Paris", "location": [ 6.1234567, 46.123456 ] }, "home_id": "91763b24c43d3e344f424e8b", "home_name": "MYHOME", "dashboard_data": { "time_utc": 1644582694, "Temperature": 21.1, "CO2": 1339, "Humidity": 45, "Noise": 35, "Pressure": 1026.8, "AbsolutePressure": 974.5, "min_temp": 21, "max_temp": 21.8, "date_max_temp": 1644534255, "date_min_temp": 1644550420, "temp_trend": "stable", "pressure_trend": "up" }, "modules": [ { "_id": "12:34:56:80:1c:42", "type": "NAModule1", "module_name": "Outdoor", "last_setup": 1558709954, "data_type": [ "Temperature", "Humidity" ], "battery_percent": 27, "reachable": false, "firmware": 50, "last_message": 1644582699, "last_seen": 1644582699, "rf_status": 68, "battery_vp": 4678 }, { "_id": "12:34:56:80:c1:ea", "type": "NAModule3", "module_name": "Rain", "last_setup": 1563734531, "data_type": [ "Rain" ], "battery_percent": 21, "reachable": true, "firmware": 12, "last_message": 1644582699, "last_seen": 1644582699, "rf_status": 79, "battery_vp": 4256, "dashboard_data": { "time_utc": 1644582686, "Rain": 3.7, "sum_rain_1": 0, "sum_rain_24": 6.9 } }, { "_id": "12:34:56:80:44:92", "type": "NAModule4", "module_name": "Bedroom", "last_setup": 1575915890, "data_type": [ "Temperature", "CO2", "Humidity" ], "battery_percent": 28, "reachable": true, "firmware": 51, "last_message": 1644582699, "last_seen": 1644582654, "rf_status": 67, "battery_vp": 4695, "dashboard_data": { "time_utc": 1644582654, "Temperature": 19.3, "CO2": 1076, "Humidity": 53, "min_temp": 19.2, "max_temp": 19.7, "date_max_temp": 1644534243, "date_min_temp": 1644553418, "temp_trend": "stable" } }, { "_id": "12:34:56:80:7e:18", "type": "NAModule4", "module_name": "Bathroom", "last_setup": 1575915955, "data_type": [ "Temperature", "CO2", "Humidity" ], "battery_percent": 55, "reachable": true, "firmware": 51, "last_message": 1644582699, "last_seen": 1644582654, "rf_status": 59, "battery_vp": 5184, "dashboard_data": { "time_utc": 1644582654, "Temperature": 19.4, "CO2": 1930, "Humidity": 55, "min_temp": 19.4, "max_temp": 21.8, "date_max_temp": 1644534224, "date_min_temp": 1644582039, "temp_trend": "stable" } }, { "_id": "12:34:56:03:1b:e4", "type": "NAModule2", "module_name": "Garden", "data_type": [ "Wind" ], "last_setup": 1549193862, "reachable": true, "dashboard_data": { "time_utc": 1559413170, "WindStrength": 4, "WindAngle": 217, "GustStrength": 9, "GustAngle": 206, "max_wind_str": 21, "max_wind_angle": 217, "date_max_wind_str": 1559386669 }, "firmware": 19, "last_message": 1559413177, "last_seen": 1559413177, "rf_status": 59, "battery_vp": 5689, "battery_percent": 85 } ] }, { "_id": "00:11:22:2c:be:c8", "station_name": "Zuhause (Kinderzimmer)", "type": "NAMain", "last_status_store": 1649146022, "reachable": true, "favorite": true, "data_type": [ "Pressure" ], "place": { "altitude": 127, "city": "Wiesbaden", "country": "DE", "timezone": "Europe/Berlin", "location": [ 8.238054275512695, 50.07585525512695 ] }, "read_only": true, "dashboard_data": { "time_utc": 1649146022, "Pressure": 1015.6, "AbsolutePressure": 1000.4, "pressure_trend": "stable" }, "modules": [ { "_id": "00:11:22:2c:ce:b6", "type": "NAModule1", "data_type": [ "Temperature", "Humidity" ], "reachable": true, "last_message": 1649146022, "last_seen": 1649145996, "dashboard_data": { "time_utc": 1649145996, "Temperature": 7.8, "Humidity": 87, "min_temp": 6.5, "max_temp": 7.8, "date_max_temp": 1649145996, "date_min_temp": 1649118465, "temp_trend": "up" } } ] } ], "user": { "mail": "john@doe.com", "administrative": { "lang": "de-DE", "reg_locale": "de-DE", "country": "DE", "unit": 0, "windunit": 0, "pressureunit": 0, "feel_like_algo": 0 } } }, "status": "ok", "time_exec": 0.91107702255249, "time_server": 1559413602 } jabesq-org-pyatmo-6216472/fixtures/home_multi_status_error_disconnected.json000066400000000000000000000003561466116727400275360ustar00rootroot00000000000000{ "status":"ok", "body":{ "errors":[ { "code":6, "id":"aa:aa:aa:aa:aa:aa" } ], "home":{ "id":"aaaaaaaaaaabbbbbbbbbbccc" } }, "time_server":1559292039 }jabesq-org-pyatmo-6216472/fixtures/home_status_error_disconnected.json000066400000000000000000000003561466116727400263240ustar00rootroot00000000000000{ "status":"ok", "body":{ "errors":[ { "code":6, "id":"12:34:56:00:fa:d0" } ], "home":{ "id":"91763b24c43d3e344f424e8b" } }, "time_server":1559292039 }jabesq-org-pyatmo-6216472/fixtures/home_status_error_invalid_schedule_id.json000066400000000000000000000001571466116727400276370ustar00rootroot00000000000000{ "error": { "code": 21, "message": "schedule is not therm schedule" } }jabesq-org-pyatmo-6216472/fixtures/home_status_error_mode_is_missing.json000066400000000000000000000001211466116727400270200ustar00rootroot00000000000000{ "error": { "code": 10, "message": "mode is missing" } }jabesq-org-pyatmo-6216472/fixtures/home_status_simple.json000066400000000000000000000102311466116727400237330ustar00rootroot00000000000000{ "status": "ok", "time_server": 1559292039, "body": { "home": { "modules": [ { "id": "12:34:56:00:f1:62", "type": "NACamera", "monitoring": "on", "sd_status": 4, "alim_status": 2, "locked": false, "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.123.45/609e27de5699fb18147ab47d06846631/MTRPn_BeWCav5RBq4U1OMDruTW4dkQ0NuMwNDAw11g,,", "is_local": true }, { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "firmware_revision": 174, "rf_strength": 107, "wifi_strength": 42 }, { "id": "12:34:56:00:01:ae", "reachable": true, "type": "NATherm1", "firmware_revision": 65, "rf_strength": 58, "battery_level": 3780, "boiler_valve_comfort_boost": false, "boiler_status": true, "anticipating": false, "bridge": "12:34:56:00:fa:d0", "battery_state": "high" }, { "id": "12:34:56:03:a5:54", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 51, "battery_level": 3025, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" }, { "id": "12:34:56:03:a0:ac", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 59, "battery_level": 3029, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" } ], "rooms": [ { "id": "2746182631", "reachable": true, "therm_measured_temperature": 19.8, "therm_setpoint_temperature": 12, "therm_setpoint_mode": "away", "therm_setpoint_start_time": 1559229567, "therm_setpoint_end_time": 0 }, { "id": "2940411577", "reachable": true, "therm_measured_temperature": 27, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false }, { "id": "2833524037", "reachable": true, "therm_measured_temperature": 24.5, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false } ], "id": "91763b24c43d3e344f424e8b", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "last_seen": 1557071156, "out_of_sight": true }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "last_seen": 1559282761, "out_of_sight": false }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "last_seen": 1559224132, "out_of_sight": true } ] } } }jabesq-org-pyatmo-6216472/fixtures/homesdata.json000066400000000000000000000563711466116727400220130ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "91763b24c43d3e344f424e8b", "name": "MYHOME", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "rooms": [ { "id": "2746182631", "name": "Livingroom", "type": "livingroom", "module_ids": [ "12:34:56:00:01:ae" ] }, { "id": "3688132631", "name": "Hall", "type": "custom", "module_ids": [ "12:34:56:00:f1:62", "12:34:56:10:f1:66", "12:34:56:00:e3:9b", "0009999992", "0009999993" ] }, { "id": "2833524037", "name": "Entrada", "type": "lobby", "module_ids": [ "12:34:56:03:a5:54" ] }, { "id": "2940411577", "name": "Cocina", "type": "kitchen", "module_ids": [ "12:34:56:03:a0:ac" ] }, { "id": "222452125", "name": "Bureau", "type": "electrical_cabinet", "module_ids": [ "12:34:56:20:f5:44", "12:34:56:20:f5:8c" ], "modules": [ "12:34:56:20:f5:44", "12:34:56:20:f5:8c" ], "therm_relay": "12:34:56:20:f5:44", "true_temperature_available": true }, { "id": "100007519", "name": "Cabinet", "type": "electrical_cabinet", "module_ids": [ "12:34:56:00:16:0e", "12:34:56:00:16:0e#0", "12:34:56:00:16:0e#1", "12:34:56:00:16:0e#2", "12:34:56:00:16:0e#3", "12:34:56:00:16:0e#4", "12:34:56:00:16:0e#5", "12:34:56:00:16:0e#6", "12:34:56:00:16:0e#7", "12:34:56:00:16:0e#8" ] }, { "id": "1002003001", "name": "Corridor", "type": "corridor", "module_ids": [ "10:20:30:bd:b8:1e" ] }, { "id": "100007520", "name": "Toilettes", "type": "toilets", "module_ids": [ "00:11:22:33:00:11:45:fe" ] } ], "modules": [ { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "name": "Thermostat", "setup_date": 1494963356, "modules_bridged": [ "12:34:56:00:01:ae", "12:34:56:03:a0:ac", "12:34:56:03:a5:54" ] }, { "id": "12:34:56:00:01:ae", "type": "NATherm1", "name": "Livingroom", "setup_date": 1494963356, "room_id": "2746182631", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:03:a5:54", "type": "NRV", "name": "Valve1", "setup_date": 1554549767, "room_id": "2833524037", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:03:a0:ac", "type": "NRV", "name": "Valve2", "setup_date": 1554554444, "room_id": "2940411577", "bridge": "12:34:56:00:fa:d0" }, { "id": "12:34:56:00:f1:62", "type": "NACamera", "name": "Hall", "setup_date": 1544828430, "room_id": "3688132631", "modules_bridged": [ "12:34:56:00:86:99", "12:34:56:00:e3:9b" ] }, { "id": "12:34:56:10:f1:66", "type": "NDB", "name": "Netatmo-Doorbell", "setup_date": 1602691361, "room_id": "3688132631", "reachable": true, "hk_device_id": "123456007df1", "customer_id": "1000010", "network_lock": false, "quick_display_zone": 62 }, { "id": "12:34:56:10:b9:0e", "type": "NOC", "name": "Front", "setup_date": 1509290599, "reachable": true, "customer_id": "A00010", "network_lock": false, "use_pincode": false }, { "id": "12:34:56:20:f5:44", "type": "OTH", "name": "Modulating Relay", "setup_date": 1607443936, "room_id": "222452125", "reachable": true, "modules_bridged": [ "12:34:56:20:f5:8c" ], "hk_device_id": "12:34:56:20:d0:c5", "capabilities": [ { "name": "automatism", "available": true } ], "max_modules_nb": 21 }, { "id": "12:34:56:20:f5:8c", "type": "OTM", "name": "Bureau Modulate", "setup_date": 1607443939, "room_id": "222452125", "bridge": "12:34:56:20:f5:44" }, { "id": "12:34:56:30:d5:d4", "type": "NBG", "name": "module iDiamant", "setup_date": 1562262465, "room_id": "222452125", "modules_bridged": [ "0009999992", "0009999993" ] }, { "id": "0009999992", "type": "NBR", "name": "Entrance Blinds", "setup_date": 1578551339, "room_id": "3688132631", "bridge": "12:34:56:30:d5:d4" }, { "id": "0009999993", "type": "NBO", "name": "Bubendorff blind", "setup_date": 1594132017, "room_id": "3688132631", "bridge": "12:34:56:30:d5:d4" }, { "id": "12:34:56:80:bb:26", "type": "NAMain", "name": "Villa", "setup_date": 1419453350, "room_id": "4122897288", "reachable": true, "modules_bridged": [ "12:34:56:80:44:92", "12:34:56:80:7e:18", "12:34:56:80:1c:42", "12:34:56:80:c1:ea" ], "customer_id": "C00016", "hardware_version": 251, "public_ext_data": false, "public_ext_counter": 0, "alarm_config": { "default_alarm": [ { "db_alarm_number": 0 }, { "db_alarm_number": 1 }, { "db_alarm_number": 2 }, { "db_alarm_number": 6 }, { "db_alarm_number": 4 }, { "db_alarm_number": 5 }, { "db_alarm_number": 7 }, { "db_alarm_number": 22 } ], "personnalized": [ { "threshold": 20, "data_type": 1, "direction": 0, "db_alarm_number": 8 }, { "threshold": 17, "data_type": 1, "direction": 1, "db_alarm_number": 9 }, { "threshold": 65, "data_type": 4, "direction": 0, "db_alarm_number": 16 }, { "threshold": 19, "data_type": 8, "direction": 0, "db_alarm_number": 22 } ] }, "module_offset": { "12:34:56:80:bb:26": { "a": 0.1 }, "03:00:00:03:1b:0e": { "a": 0 } } }, { "id": "12:34:56:80:1c:42", "type": "NAModule1", "name": "Outdoor", "setup_date": 1448565785, "bridge": "12:34:56:80:bb:26" }, { "id": "12:34:56:80:c1:ea", "type": "NAModule3", "name": "Rain", "setup_date": 1591770206, "bridge": "12:34:56:80:bb:26" }, { "id": "12:34:56:80:44:92", "type": "NAModule4", "name": "Bedroom", "setup_date": 1484997703, "bridge": "12:34:56:80:bb:26" }, { "id": "12:34:56:80:7e:18", "type": "NAModule4", "name": "Bathroom", "setup_date": 1543579864, "bridge": "12:34:56:80:bb:26" }, { "id": "12:34:56:03:1b:e4", "type": "NAModule2", "name": "Garden", "setup_date": 1543579864, "bridge": "12:34:56:80:bb:26" }, { "id": "12:34:56:80:60:40", "type": "NLG", "name": "Prise Control", "setup_date": 1641841257, "room_id": "1310352496", "modules_bridged": [ "12:34:56:80:00:12:ac:f2", "12:34:56:80:00:c3:69:3c", "12:34:56:00:00:a1:4c:da", "12:34:56:00:01:01:01:a1", "00:11:22:33:00:11:45:fe", "12:34:56:00:01:01:01:b1" ] }, { "id": "12:34:56:80:00:12:ac:f2", "type": "NLP", "name": "Prise", "setup_date": 1641841262, "room_id": "1310352496", "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:80:00:c3:69:3c", "type": "NLT", "name": "Commande sans fil", "setup_date": 1641841262, "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:00:86:99", "type": "NACamDoorTag", "name": "Window Hall", "setup_date": 1581177375, "bridge": "12:34:56:00:f1:62", "category": "window" }, { "id": "12:34:56:00:e3:9b", "type": "NIS", "setup_date": 1620479901, "bridge": "12:34:56:00:f1:62", "name": "Sirene in hall" }, { "id": "12:34:56:00:16:0e", "type": "NLE", "name": "Écocompteur", "setup_date": 1644496884, "room_id": "100007519", "modules_bridged": [ "12:34:56:00:16:0e#0", "12:34:56:00:16:0e#1", "12:34:56:00:16:0e#2", "12:34:56:00:16:0e#3", "12:34:56:00:16:0e#4", "12:34:56:00:16:0e#5", "12:34:56:00:16:0e#6", "12:34:56:00:16:0e#7", "12:34:56:00:16:0e#8" ] }, { "id": "12:34:56:00:16:0e#0", "type": "NLE", "name": "Line 1", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#1", "type": "NLE", "name": "Line 2", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#2", "type": "NLE", "name": "Line 3", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#3", "type": "NLE", "name": "Line 4", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#4", "type": "NLE", "name": "Line 5", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#5", "type": "NLE", "name": "Total", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#6", "type": "NLE", "name": "Gas", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#7", "type": "NLE", "name": "Hot water", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#8", "type": "NLE", "name": "Cold water", "setup_date": 1644496886, "room_id": "100007519", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:00:a1:4c:da", "type": "NLPC", "name": "Consumption meter", "setup_date": 1638376602, "room_id": "100008999", "bridge": "12:34:56:80:60:40" }, { "id": "10:20:30:bd:b8:1e", "type": "BNS", "name": "Smarther", "setup_date": 1638022197, "room_id": "1002003001" }, { "id": "00:11:22:33:00:11:45:fe", "type": "NLF", "on": false, "brightness": 63, "firmware_revision": 57, "last_seen": 1657086939, "power": 0, "reachable": true, "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:00:01:01:01:a1", "type": "NLFN", "name": "Bathroom light", "setup_date": 1598367404, "room_id": "1002003001", "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:00:01:01:01:b1", "type": "NLLF", "name": "Centralized ventilation controler", "setup_date": 1598367504, "room_id": "1002003001", "bridge": "12:34:56:80:60:40" } ], "schedules": [ { "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0 }, { "type": 1, "name": "Night", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1 }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4 } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Default", "selected": true, "id": "591b54a2764ff4d50d8b5795", "type": "therm" }, { "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [ { "temp": 21, "room_id": "2746182631" } ], "id": 0 }, { "type": 1, "name": "Night", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 1 }, { "type": 5, "name": "Eco", "rooms_temp": [ { "temp": 17, "room_id": "2746182631" } ], "id": 4 } ], "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1410 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2850 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4290 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5730 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7170 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 1, "m_offset": 8610 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 1, "m_offset": 10050 } ], "hg_temp": 7, "away_temp": 14, "name": "Winter", "id": "b1b54a2f45795764f59d50d8", "type": "therm" } ], "therm_setpoint_default_duration": 120, "temperature_control_mode": "cooling", "cooling_mode": "schedule", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "pseudo": "John Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d7" }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "pseudo": "Jane Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c24b808a89f8d1730039d2c69928b029d67fc40cb2d7fb69ecdf2bb8b72" }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "pseudo": "Richard Doe", "url": "https://netatmocameraimage.blob.core.windows.net/production/d74fad765b9100ef480720a9a4a95c2d1730fb69ecdf2bb8b72039d2c69928b029d67fc40cb2d74b808a89f8" } ], "therm_mode": "schedule" }, { "id": "91763b24c43d3e344f424e8c", "altitude": 112, "coordinates": [ 52.516263, 13.377726 ], "country": "DE", "timezone": "Europe/Berlin", "therm_setpoint_default_duration": 180, "therm_mode": "schedule" } ], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "all_linked": false, "type": "netatmo", "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 } jabesq-org-pyatmo-6216472/fixtures/homesdata_emtpy_home.json000066400000000000000000000217731466116727400242370ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "111111111111111111111401", "name": "Home with no modules", "altitude": 9, "coordinates": [ 1.23456789, 50.0987654 ], "country": "BE", "timezone": "Europe/Brussels", "rooms": [ { "id": "1111111401", "name": "Livingroom", "type": "livingroom" } ], "temperature_control_mode": "heating", "therm_mode": "away", "therm_setpoint_default_duration": 120, "cooling_mode": "schedule", "schedules": [ { "away_temp": 14, "hg_temp": 7, "name": "Week", "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 6, "m_offset": 420 }, { "zone_id": 4, "m_offset": 450 }, { "zone_id": 5, "m_offset": 720 }, { "zone_id": 4, "m_offset": 780 }, { "zone_id": 0, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1320 }, { "zone_id": 6, "m_offset": 1860 }, { "zone_id": 4, "m_offset": 1890 }, { "zone_id": 5, "m_offset": 2160 }, { "zone_id": 4, "m_offset": 2220 }, { "zone_id": 0, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2760 }, { "zone_id": 6, "m_offset": 3300 }, { "zone_id": 4, "m_offset": 3330 }, { "zone_id": 5, "m_offset": 3600 }, { "zone_id": 4, "m_offset": 3660 }, { "zone_id": 0, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4200 }, { "zone_id": 6, "m_offset": 4740 }, { "zone_id": 4, "m_offset": 4770 }, { "zone_id": 5, "m_offset": 5040 }, { "zone_id": 4, "m_offset": 5100 }, { "zone_id": 0, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5640 }, { "zone_id": 6, "m_offset": 6180 }, { "zone_id": 4, "m_offset": 6210 }, { "zone_id": 5, "m_offset": 6480 }, { "zone_id": 4, "m_offset": 6540 }, { "zone_id": 0, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 7080 }, { "zone_id": 6, "m_offset": 7620 }, { "zone_id": 5, "m_offset": 7800 }, { "zone_id": 0, "m_offset": 8100 }, { "zone_id": 1, "m_offset": 8550 }, { "zone_id": 6, "m_offset": 9060 }, { "zone_id": 5, "m_offset": 9240 }, { "zone_id": 0, "m_offset": 9540 }, { "zone_id": 1, "m_offset": 9990 } ], "zones": [ { "type": 0, "name": "Comfort", "rooms_temp": [], "id": 0, "rooms": [] }, { "type": 1, "name": "Nacht", "rooms_temp": [], "id": 1, "rooms": [] }, { "type": 5, "name": "Eco", "rooms_temp": [], "id": 4, "rooms": [] }, { "type": 4, "name": "Tussenin", "rooms_temp": [], "id": 5, "rooms": [] }, { "type": 4, "name": "Ochtend", "rooms_temp": [], "id": 6, "rooms": [] } ], "id": "700000000000000000000401", "selected": true, "type": "therm" } ] } ], "user": { "email": "john@doe.com", "language": "de-DE", "locale": "de-DE", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "91763b24c43d3e344f424e8b" } }, "status": "ok", "time_exec": 0.056135892868042, "time_server": 1559171003 }jabesq-org-pyatmo-6216472/fixtures/homesdata_multi.json000066400000000000000000006073331466116727400232250ustar00rootroot00000000000000{ "body": { "homes": [ { "id": "aaaaaaaaaaabbbbbbbbbbccc", "name": "A BIG HOME", "altitude": 284, "coordinates": [ 26.234678, 83.234678 ], "country": "FR", "timezone": "Europe/Paris", "rooms": [ { "id": "3707962039", "name": "Cuisine", "type": "kitchen", "module_ids": [ "98:76:54:32:10:00:00:03", "98:76:54:32:10:00:00:05", "98:76:54:32:10:00:00:06", "98:76:54:32:10:00:00:07", "98:76:54:32:10:00:00:09", "98:76:54:32:10:00:00:28", "98:76:54:32:10:00:00:37", "98:76:54:32:10:00:00:38", "98:76:54:32:10:00:00:40", "98:76:54:32:10:00:00:50" ] }, { "id": "596817675", "name": "Vestibule", "type": "lobby", "module_ids": [ "98:76:54:32:10:00:00:01", "98:76:54:32:10:00:00:02", "98:76:54:32:10:00:00:08", "98:76:54:32:10:00:00:13", "98:76:54:32:10:00:00:14", "98:76:54:32:10:00:00:15", "98:76:54:32:10:00:00:16", "98:76:54:32:10:00:00:27", "98:76:54:32:10:00:00:29", "98:76:54:32:10:00:00:32", "98:76:54:32:10:00:00:36", "98:76:54:32:10:00:00:39" ] }, { "id": "1462100035", "name": "Salon", "type": "livingroom", "module_ids": [ "98:76:54:32:10:00:00:04", "98:76:54:32:10:00:00:24#1", "98:76:54:32:10:00:00:34", "98:76:54:32:10:00:00:52", "98:76:54:32:10:00:00:60", "98:76:54:32:10:00:00:63", "98:76:54:32:10:00:00:66", "98:76:54:32:10:00:00:73", "98:76:54:32:10:00:00:75" ] }, { "id": "3435163850", "name": "Chambre A", "type": "bedroom", "module_ids": [ "98:76:54:32:10:00:00:26", "98:76:54:32:10:00:00:51" ] }, { "id": "737850817", "name": "Extérieur", "type": "outdoor", "module_ids": [ "98:76:54:32:10:00:00:10", "98:76:54:32:10:00:00:41", "98:76:54:32:10:00:00:42", "98:76:54:32:10:00:00:53", "98:76:54:32:10:00:00:54", "98:76:54:32:10:00:00:55", "98:76:54:32:10:00:00:56" ] }, { "id": "842662884", "name": "Bibliothèque", "type": "home_office", "module_ids": [ "98:76:54:32:10:00:00:11", "98:76:54:32:10:00:00:12", "98:76:54:32:10:00:00:24#2", "98:76:54:32:10:00:00:25" ] }, { "id": "3194154910", "name": "Salle à manger", "type": "dining_room", "module_ids": [ "98:76:54:32:10:00:00:30", "98:76:54:32:10:00:00:31", "98:76:54:32:10:00:00:33", "98:76:54:32:10:00:00:72" ] }, { "id": "2370728183", "name": "Atelier", "type": "custom", "module_ids": [ "98:76:54:32:10:00:00:18", "98:76:54:32:10:00:00:23" ] }, { "id": "2042969726", "name": "Chambre B", "type": "bedroom", "module_ids": [ "98:76:54:32:10:00:00:19", "98:76:54:32:10:00:00:20", "98:76:54:32:10:00:00:46" ] }, { "id": "2754296835", "name": "Placard Technique", "type": "electrical_cabinet", "module_ids": [ "aa:aa:aa:aa:aa:aa", "98:76:54:32:10:00:00:22", "98:76:54:32:10:00:00:48", "98:76:54:32:10:00:00:59", "98:76:54:32:10:00:00:67", "98:76:54:32:10:00:00:68", "98:76:54:32:10:00:00:69", "98:76:54:32:10:00:00:77", "98:76:54:32:10:00:00:78", "98:76:54:32:10:00:00:79" ] }, { "id": "1662974901", "name": "Dressing", "type": "custom", "module_ids": [ "98:76:54:32:10:00:00:21", "98:76:54:32:10:00:00:35" ] }, { "id": "873035982", "name": "Chambre C", "type": "bedroom", "module_ids": [ "98:76:54:32:10:00:00:17", "98:76:54:32:10:00:00:43", "98:76:54:32:10:00:00:76" ] }, { "id": "3795659199", "name": "Chambre D", "type": "bedroom", "module_ids": [ "98:76:54:32:10:00:00:57" ] }, { "id": "2102454491", "name": "Buanderie", "type": "custom", "module_ids": [ "98:76:54:32:10:00:00:45" ] }, { "id": "93888250", "name": "Salle de bains Des Enfants", "type": "bathroom", "module_ids": [ "98:76:54:32:10:00:00:44" ] }, { "id": "3497055021", "name": "Chambre Brice", "type": "bedroom", "module_ids": [ "98:76:54:32:10:00:00:47", "98:76:54:32:10:00:00:74" ] }, { "id": "2061006239", "name": "Pool house", "type": "custom", "module_ids": [ "98:76:54:32:10:00:00:58", "98:76:54:32:10:00:00:61", "98:76:54:32:10:00:00:62", "98:76:54:32:10:00:00:64", "98:76:54:32:10:00:00:65", "98:76:54:32:10:00:00:71" ] }, { "id": "927970817", "name": "Salle de bains Des Parents", "type": "bathroom", "module_ids": [ "98:76:54:32:10:00:00:49" ] }, { "id": "1641945290", "name": "Salle de bains D’Arthur", "type": "bathroom", "module_ids": [ "98:76:54:32:10:00:00:70" ] } ], "modules": [ { "id": "aa:aa:aa:aa:aa:aa", "type": "NLG", "name": "Legrand Gateway", "setup_date": 1572624665, "room_id": "2754296835", "modules_bridged": [ "98:76:54:32:10:00:00:01", "98:76:54:32:10:00:00:02", "98:76:54:32:10:00:00:03", "98:76:54:32:10:00:00:04", "98:76:54:32:10:00:00:05", "98:76:54:32:10:00:00:06", "98:76:54:32:10:00:00:07", "98:76:54:32:10:00:00:08", "98:76:54:32:10:00:00:09", "98:76:54:32:10:00:00:10", "98:76:54:32:10:00:00:11", "98:76:54:32:10:00:00:12", "98:76:54:32:10:00:00:13", "98:76:54:32:10:00:00:14", "98:76:54:32:10:00:00:15", "98:76:54:32:10:00:00:16", "98:76:54:32:10:00:00:17", "98:76:54:32:10:00:00:18", "98:76:54:32:10:00:00:19", "98:76:54:32:10:00:00:20", "98:76:54:32:10:00:00:21", "98:76:54:32:10:00:00:22", "98:76:54:32:10:00:00:23", "98:76:54:32:10:00:00:24", "98:76:54:32:10:00:00:24#1", "98:76:54:32:10:00:00:24#2", "98:76:54:32:10:00:00:25", "98:76:54:32:10:00:00:26", "98:76:54:32:10:00:00:27", "98:76:54:32:10:00:00:28", "98:76:54:32:10:00:00:29", "98:76:54:32:10:00:00:30", "98:76:54:32:10:00:00:31", "98:76:54:32:10:00:00:32", "98:76:54:32:10:00:00:33", "98:76:54:32:10:00:00:34", "98:76:54:32:10:00:00:35", "98:76:54:32:10:00:00:36", "98:76:54:32:10:00:00:37", "98:76:54:32:10:00:00:38", "98:76:54:32:10:00:00:39", "98:76:54:32:10:00:00:40", "98:76:54:32:10:00:00:41", "98:76:54:32:10:00:00:42", "98:76:54:32:10:00:00:43", "98:76:54:32:10:00:00:44", "98:76:54:32:10:00:00:45", "98:76:54:32:10:00:00:46", "98:76:54:32:10:00:00:47", "98:76:54:32:10:00:00:48", "98:76:54:32:10:00:00:49", "98:76:54:32:10:00:00:50", "98:76:54:32:10:00:00:51", "98:76:54:32:10:00:00:52", "98:76:54:32:10:00:00:53", "98:76:54:32:10:00:00:54", "98:76:54:32:10:00:00:55", "98:76:54:32:10:00:00:03#1", "98:76:54:32:10:00:00:03#2", "98:76:54:32:10:00:00:07#1", "98:76:54:32:10:00:00:07#2", "98:76:54:32:10:00:00:08#1", "98:76:54:32:10:00:00:08#2", "98:76:54:32:10:00:00:28#1", "98:76:54:32:10:00:00:28#2", "98:76:54:32:10:00:00:29#1", "98:76:54:32:10:00:00:29#2", "98:76:54:32:10:00:00:30#1", "98:76:54:32:10:00:00:30#2", "98:76:54:32:10:00:00:50#1", "98:76:54:32:10:00:00:50#2", "98:76:54:32:10:00:00:56", "98:76:54:32:10:00:00:57", "98:76:54:32:10:00:00:58", "98:76:54:32:10:00:00:59", "98:76:54:32:10:00:00:60", "98:76:54:32:10:00:00:61", "98:76:54:32:10:00:00:62", "98:76:54:32:10:00:00:63", "98:76:54:32:10:00:00:63#1", "98:76:54:32:10:00:00:63#2", "98:76:54:32:10:00:00:64", "98:76:54:32:10:00:00:64#1", "98:76:54:32:10:00:00:64#2", "98:76:54:32:10:00:00:65", "98:76:54:32:10:00:00:65#1", "98:76:54:32:10:00:00:65#2", "98:76:54:32:10:00:00:66", "98:76:54:32:10:00:00:66#1", "98:76:54:32:10:00:00:66#2", "98:76:54:32:10:00:00:67", "98:76:54:32:10:00:00:68", "98:76:54:32:10:00:00:69", "98:76:54:32:10:00:00:70", "98:76:54:32:10:00:00:71", "98:76:54:32:10:00:00:72", "98:76:54:32:10:00:00:73", "98:76:54:32:10:00:00:74", "98:76:54:32:10:00:00:75", "98:76:54:32:10:00:00:76", "98:76:54:32:10:00:00:77", "98:76:54:32:10:00:00:78", "98:76:54:32:10:00:00:79" ] }, { "id": "98:76:54:32:10:00:00:01", "type": "NLP", "name": "Buffet", "setup_date": 1572624686, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "light" }, { "id": "98:76:54:32:10:00:00:02", "type": "NLT", "name": "Commande entrée sortie principale", "setup_date": 1572624686, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:03", "type": "NLD", "name": "Boutons Cuisine Haut", "setup_date": 1572629067, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:04", "type": "NLV", "name": "volet", "setup_date": 1572798965, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:05", "type": "NLM", "name": "Verrière", "setup_date": 1574591975, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:06", "type": "NLM", "name": "ilot", "setup_date": 1574591975, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:07", "type": "NLD", "name": "Bouton Cuisine milieu", "setup_date": 1574592863, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:08", "type": "NLD", "name": "Entrée Bouton Portail et dehors", "setup_date": 1574593140, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:09", "type": "NLT", "name": "Bouton pour exterieur porte fenetre", "setup_date": 1605358560, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:10", "type": "NLM", "name": "Olivier", "setup_date": 1605359274, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:11", "type": "NLP", "name": "Lampadaire", "setup_date": 1605369621, "room_id": "842662884", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "light" }, { "id": "98:76:54:32:10:00:00:12", "type": "NLT", "name": "Bouton Bibliotheque", "setup_date": 1607175439, "room_id": "842662884", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:13", "type": "NLF", "name": "Couloir enfants", "setup_date": 1612299365, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:14", "type": "NLT", "name": "Couloir enfants 2", "setup_date": 1612299777, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:15", "type": "NLT", "name": "Couloir enfants 3", "setup_date": 1612299852, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:16", "type": "NLT", "name": "Couloir enfants 1", "setup_date": 1613565493, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:17", "type": "NLF", "name": "Lumière C", "setup_date": 1617390843, "room_id": "873035982", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:18", "type": "NLM", "name": "Néon", "setup_date": 1643544945, "room_id": "2370728183", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:19", "type": "NLT", "name": "Couloir A interrupteur", "setup_date": 1643794135, "room_id": "2042969726", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:20", "type": "NLF", "name": "Couloir A", "setup_date": 1643794453, "room_id": "2042969726", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:21", "type": "NLPT", "name": "Dressing", "setup_date": 1643809582, "room_id": "1662974901", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:22", "type": "NLPM", "name": "Onduleur Serveurs Mais Local Technique", "setup_date": 1643911516, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "other" }, { "id": "98:76:54:32:10:00:00:23", "type": "NLT", "name": "Interrupteur neon", "setup_date": 1644008400, "room_id": "2370728183", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:24", "type": "NLIS", "setup_date": 1645651106, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:24#1", "type": "NLIS", "name": "Niche", "setup_date": 1645651106, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:24#2", "type": "NLIS", "name": "Escalier", "setup_date": 1645651106, "room_id": "842662884", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:25", "type": "NLT", "name": "Bouton Escalier", "setup_date": 1645651356, "room_id": "842662884", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:26", "type": "NLPT", "name": "Lumière Chambre E", "setup_date": 1645657974, "room_id": "3435163850", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:27", "type": "NLPT", "name": "Entrée", "setup_date": 1645658118, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:28", "type": "NLD", "name": "Bouton cuisine bas", "setup_date": 1645659939, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:29", "type": "NLD", "name": "Bouton double entrée porte", "setup_date": 1645660346, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:30", "type": "NLD", "name": "Bouton double salle à manger", "setup_date": 1645660684, "room_id": "3194154910", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:31", "type": "NLF", "name": "Placard", "setup_date": 1645662093, "room_id": "3194154910", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:32", "type": "NLT", "name": "Bouton plafond entrée couloir", "setup_date": 1645662629, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:33", "type": "NLPT", "name": "Table", "setup_date": 1645889017, "room_id": "3194154910", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:34", "type": "NLPT", "name": "Baie Vitrée", "setup_date": 1645889069, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:35", "type": "NLC", "name": "Radiateur Dressing", "setup_date": 1645894862, "room_id": "1662974901", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:36", "type": "NLC", "name": "Radiateur Entrée", "setup_date": 1645899253, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:37", "type": "NLC", "name": "Radiateur Cuisine Dressing", "setup_date": 1645902157, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:38", "type": "NLC", "name": "Radiateur Cuisine Entrée", "setup_date": 1645902199, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:39", "type": "NLT", "name": "Commande sans fil couloir enfant pour entrée", "setup_date": 1646074736, "room_id": "596817675", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:40", "type": "NLPT", "name": "Couloir Parents", "setup_date": 1646568523, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:41", "type": "NLPT", "name": "Jardin", "setup_date": 1646568567, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:42", "type": "NLPT", "name": "Facade", "setup_date": 1646568594, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:43", "type": "NLC", "name": "Radiateur FF", "setup_date": 1646581781, "room_id": "873035982", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:44", "type": "NLC", "name": "Radiateur Salle De Bain Enfants", "setup_date": 1646828219, "room_id": "93888250", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:45", "type": "NLC", "name": "Radiateur Buanderie", "setup_date": 1646828251, "room_id": "2102454491", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:46", "type": "NLC", "name": "Radiateur A", "setup_date": 1646828278, "room_id": "2042969726", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:47", "type": "NLC", "name": "Radiateur B", "setup_date": 1646828308, "room_id": "3497055021", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:48", "type": "NLM", "name": "Cam Porte", "setup_date": 1653579677, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:49", "type": "NLC", "name": "Radiateur Sèche Serviette E", "setup_date": 1667205824, "room_id": "927970817", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:50", "type": "NLAO", "name": "Porte vitree sans pile", "setup_date": 1668001531, "room_id": "3707962039", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:51", "type": "NLC", "name": "Radiateur E", "setup_date": 1668339519, "room_id": "3435163850", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:52", "type": "NLM", "name": "Meurtrières", "setup_date": 1671560972, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:53", "type": "NLPT", "name": "Parking", "setup_date": 1672948768, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:54", "type": "NLM", "name": "Barbecue", "setup_date": 1672948768, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:55", "type": "NLAO", "name": "Bouton sans pile cuisine ete", "setup_date": 1672949735, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:03#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:03#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:07#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:07#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:08#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:08#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:28#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:28#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:29#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:29#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:30#1", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:30#2", "type": "NLD", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:50#1", "type": "NLAO", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:50#2", "type": "NLAO", "setup_date": 1673873611, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:56", "type": "NLM", "name": "Piscine", "setup_date": 1691244631, "room_id": "737850817", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:57", "type": "NLC", "name": "Radiateur DD", "setup_date": 1692093769, "room_id": "3795659199", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:58", "type": "NLM", "name": "Salle de bain", "setup_date": 1692094781, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:59", "type": "NLP", "name": "Prise Pool House Relais Zigbee", "setup_date": 1692095384, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "router" }, { "id": "98:76:54:32:10:00:00:60", "type": "NLPT", "name": "Plafonnier", "setup_date": 1692095856, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:61", "type": "NLPT", "name": "Terrasse Piscine", "setup_date": 1693848343, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:62", "type": "NLPT", "name": "Lumière", "setup_date": 1693848357, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:63", "type": "NLD", "name": "Salon Commande Double Haut", "setup_date": 1694336106, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:63#1", "type": "NLD", "setup_date": 1694336106, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:63#2", "type": "NLD", "setup_date": 1694336106, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:64", "type": "NLD", "name": "Commande Pool House Gauche", "setup_date": 1694336110, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:64#1", "type": "NLD", "setup_date": 1694336110, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:64#2", "type": "NLD", "setup_date": 1694336110, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:65", "type": "NLD", "name": "Commande Pool House Droite", "setup_date": 1694336143, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:65#1", "type": "NLD", "setup_date": 1694336143, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:65#2", "type": "NLD", "setup_date": 1694336143, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:66", "type": "NLD", "name": "Commande Double Bas", "setup_date": 1698577707, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:66#1", "type": "NLD", "setup_date": 1698577707, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:66#2", "type": "NLD", "setup_date": 1698577707, "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:67", "type": "NLPO", "name": "Cumulus Parents", "setup_date": 1699128857, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "water_heater" }, { "id": "98:76:54:32:10:00:00:68", "type": "NLPO", "name": "Cumulus DD", "setup_date": 1699132798, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "water_heater" }, { "id": "98:76:54:32:10:00:00:69", "type": "NLPC", "name": "Compteur Filtration Local Technique", "setup_date": 1711797163, "room_id": "2754296835", "bridge": "00:04:74:22:52:38" }, { "id": "98:76:54:32:10:00:00:70", "type": "NLC", "name": "Radiateur Sèche Serviette A", "setup_date": 1702133314, "room_id": "1641945290", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator" }, { "id": "98:76:54:32:10:00:00:71", "type": "NLPO", "name": "Cumulus Pool House", "setup_date": 1702135239, "room_id": "2061006239", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "water_heater" }, { "id": "98:76:54:32:10:00:00:72", "type": "NLC", "name": "Radiateur Sol Salle À Manger", "setup_date": 1707332251, "room_id": "3194154910", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator_without_pilot_wire" }, { "id": "98:76:54:32:10:00:00:73", "type": "NLC", "name": "Radiateur Sol Salon", "setup_date": 1707332251, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "radiator_without_pilot_wire" }, { "id": "98:76:54:32:10:00:00:74", "type": "NLP", "name": "Setup PC B", "setup_date": 1707332620, "room_id": "3497055021", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "router" }, { "id": "98:76:54:32:10:00:00:75", "type": "NLPM", "name": "Setup TV Apple TV Switch Salon", "setup_date": 1707333771, "room_id": "1462100035", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "multimedia" }, { "id": "98:76:54:32:10:00:00:76", "type": "NLP", "name": "Mesure PC Switch C", "setup_date": 1707335636, "room_id": "873035982", "bridge": "aa:aa:aa:aa:aa:aa", "appliance_type": "router" }, { "id": "98:76:54:32:10:00:00:77", "type": "NLPC", "name": "Compteur Plaque Sèche-Linge PC Buanderie Plan Cuisine", "setup_date": 1707339526, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:78", "type": "NLPC", "name": "Compteur Congel Micro-onde Frigo PC WC", "setup_date": 1708185348, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa" }, { "id": "98:76:54:32:10:00:00:79", "type": "NLPC", "name": "Compteur Lave-linge Four Lave Lave-Vaisselle PC TV Chambre ", "setup_date": 1708185369, "room_id": "2754296835", "bridge": "aa:aa:aa:aa:aa:aa" } ], "temperature_control_mode": "heating", "therm_mode": "schedule", "therm_setpoint_default_duration": 180, "schedules": [ { "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 360 }, { "zone_id": 1, "m_offset": 510 }, { "zone_id": 5, "m_offset": 960 }, { "zone_id": 1, "m_offset": 1200 }, { "zone_id": 2, "m_offset": 1260 }, { "zone_id": 1, "m_offset": 1380 }, { "zone_id": 0, "m_offset": 1800 }, { "zone_id": 1, "m_offset": 1950 }, { "zone_id": 5, "m_offset": 2400 }, { "zone_id": 1, "m_offset": 2640 }, { "zone_id": 2, "m_offset": 2700 }, { "zone_id": 1, "m_offset": 2820 }, { "zone_id": 0, "m_offset": 3240 }, { "zone_id": 1, "m_offset": 3390 }, { "zone_id": 5, "m_offset": 3840 }, { "zone_id": 1, "m_offset": 4080 }, { "zone_id": 2, "m_offset": 4140 }, { "zone_id": 1, "m_offset": 4260 }, { "zone_id": 0, "m_offset": 4680 }, { "zone_id": 1, "m_offset": 4830 }, { "zone_id": 5, "m_offset": 5280 }, { "zone_id": 1, "m_offset": 5520 }, { "zone_id": 2, "m_offset": 5580 }, { "zone_id": 1, "m_offset": 5700 }, { "zone_id": 0, "m_offset": 6120 }, { "zone_id": 1, "m_offset": 6270 }, { "zone_id": 5, "m_offset": 6720 }, { "zone_id": 1, "m_offset": 6960 }, { "zone_id": 2, "m_offset": 7020 }, { "zone_id": 1, "m_offset": 7140 }, { "zone_id": 0, "m_offset": 7560 }, { "zone_id": 1, "m_offset": 7710 }, { "zone_id": 5, "m_offset": 8160 }, { "zone_id": 1, "m_offset": 8400 }, { "zone_id": 2, "m_offset": 8460 }, { "zone_id": 1, "m_offset": 8580 }, { "zone_id": 0, "m_offset": 9000 }, { "zone_id": 1, "m_offset": 9150 }, { "zone_id": 5, "m_offset": 9600 }, { "zone_id": 1, "m_offset": 9840 }, { "zone_id": 2, "m_offset": 9900 }, { "zone_id": 1, "m_offset": 10020 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Éco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Nuit", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Confort sauf chambres parents", "id": 5, "type": 4, "rooms_temp": [ { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Chambre parents only", "id": 2, "type": 4, "rooms_temp": [ { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] } ], "name": "Planning Hiver", "default": false, "away_temp": 12, "hg_temp": 7, "id": "61fa621cdd99943657260882", "type": "therm", "selected": true }, { "timetable": [ { "zone_id": 2, "m_offset": 0 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Éco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Nuit", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Off", "id": 2, "type": 4, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] } ], "name": "Planning ete", "default": false, "away_temp": 12, "hg_temp": 7, "id": "625a76ceec2cce72075ac55a", "type": "therm" }, { "timetable": [ { "zone_id": 0, "m_offset": 0 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Night", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Eco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] } ], "name": "Full", "default": false, "away_temp": 12, "hg_temp": 7, "id": "63a44ba0735ffc27410f2331", "type": "therm" }, { "timetable": [ { "zone_id": 4, "m_offset": 0 }, { "zone_id": 0, "m_offset": 300 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 855 }, { "zone_id": 4, "m_offset": 1140 }, { "zone_id": 0, "m_offset": 1740 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2295 }, { "zone_id": 4, "m_offset": 2580 }, { "zone_id": 0, "m_offset": 3180 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3735 }, { "zone_id": 4, "m_offset": 4020 }, { "zone_id": 0, "m_offset": 4620 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5175 }, { "zone_id": 4, "m_offset": 5460 }, { "zone_id": 0, "m_offset": 6060 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6615 }, { "zone_id": 4, "m_offset": 6900 }, { "zone_id": 0, "m_offset": 7500 }, { "zone_id": 4, "m_offset": 7620 }, { "zone_id": 0, "m_offset": 8055 }, { "zone_id": 4, "m_offset": 8340 }, { "zone_id": 0, "m_offset": 8940 }, { "zone_id": 4, "m_offset": 9060 }, { "zone_id": 0, "m_offset": 9495 }, { "zone_id": 4, "m_offset": 9780 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Éco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Nuit", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] } ], "name": "Planning Hiver frileux", "default": false, "away_temp": 12, "hg_temp": 7, "id": "63c5b63b766611525b0b1e4d", "type": "therm" }, { "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 300 }, { "zone_id": 4, "m_offset": 420 }, { "zone_id": 0, "m_offset": 1020 }, { "zone_id": 1, "m_offset": 1140 }, { "zone_id": 0, "m_offset": 1740 }, { "zone_id": 4, "m_offset": 1860 }, { "zone_id": 0, "m_offset": 2460 }, { "zone_id": 1, "m_offset": 2580 }, { "zone_id": 0, "m_offset": 3180 }, { "zone_id": 4, "m_offset": 3300 }, { "zone_id": 0, "m_offset": 3900 }, { "zone_id": 1, "m_offset": 4020 }, { "zone_id": 0, "m_offset": 4620 }, { "zone_id": 4, "m_offset": 4740 }, { "zone_id": 0, "m_offset": 5340 }, { "zone_id": 1, "m_offset": 5460 }, { "zone_id": 0, "m_offset": 6060 }, { "zone_id": 4, "m_offset": 6180 }, { "zone_id": 0, "m_offset": 6780 }, { "zone_id": 1, "m_offset": 6900 }, { "zone_id": 0, "m_offset": 7560 }, { "zone_id": 4, "m_offset": 7680 }, { "zone_id": 0, "m_offset": 8220 }, { "zone_id": 1, "m_offset": 8340 }, { "zone_id": 0, "m_offset": 9000 }, { "zone_id": 4, "m_offset": 9120 }, { "zone_id": 0, "m_offset": 9660 }, { "zone_id": 1, "m_offset": 9780 } ], "zones": [ { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Nuit", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Confort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Éco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] } ], "name": "Chambres et SDB", "default": false, "away_temp": 12, "hg_temp": 7, "id": "6413ac548decf9f28b0efc4e", "type": "therm" }, { "timetable": [ { "zone_id": 5, "m_offset": 0 }, { "zone_id": 2, "m_offset": 360 }, { "zone_id": 5, "m_offset": 450 }, { "zone_id": 2, "m_offset": 1020 }, { "zone_id": 5, "m_offset": 1080 }, { "zone_id": 2, "m_offset": 1800 }, { "zone_id": 5, "m_offset": 1890 }, { "zone_id": 2, "m_offset": 2460 }, { "zone_id": 5, "m_offset": 2520 }, { "zone_id": 2, "m_offset": 3240 }, { "zone_id": 5, "m_offset": 3330 }, { "zone_id": 2, "m_offset": 3900 }, { "zone_id": 5, "m_offset": 3960 }, { "zone_id": 2, "m_offset": 4680 }, { "zone_id": 5, "m_offset": 4770 }, { "zone_id": 2, "m_offset": 5340 }, { "zone_id": 5, "m_offset": 5400 }, { "zone_id": 2, "m_offset": 6120 }, { "zone_id": 5, "m_offset": 6210 }, { "zone_id": 2, "m_offset": 6780 }, { "zone_id": 5, "m_offset": 6840 }, { "zone_id": 2, "m_offset": 7680 }, { "zone_id": 5, "m_offset": 7740 }, { "zone_id": 2, "m_offset": 8220 }, { "zone_id": 5, "m_offset": 8280 }, { "zone_id": 2, "m_offset": 9120 }, { "zone_id": 5, "m_offset": 9180 }, { "zone_id": 2, "m_offset": 9660 }, { "zone_id": 5, "m_offset": 9720 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Night", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Eco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "away" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "1662974901", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "away" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "927970817", "therm_setpoint_fp": "away" }, { "room_id": "1641945290", "therm_setpoint_fp": "away" }, { "room_id": "2102454491", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "away" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "1662974901", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "away" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "927970817", "therm_setpoint_fp": "away" }, { "id": "1641945290", "therm_setpoint_fp": "away" }, { "id": "2102454491", "therm_setpoint_fp": "away" } ] }, { "name": "SDB seulement", "id": 2, "type": 4, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Tout Off", "id": 5, "type": 4, "rooms_temp": [ { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "frost_guard" }, { "id": "3497055021", "therm_setpoint_fp": "frost_guard" }, { "id": "3435163850", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "frost_guard" }, { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Chambres Confort and All Off", "id": 6, "type": 4, "rooms_temp": [ { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Chambres Eco and all Off", "id": 7, "type": 4, "rooms_temp": [ { "room_id": "1662974901", "therm_setpoint_fp": "comfort" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3707962039", "therm_setpoint_fp": "comfort" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "comfort" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "1662974901", "therm_setpoint_fp": "comfort" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3707962039", "therm_setpoint_fp": "comfort" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "comfort" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "comfort" } ] }, { "name": "Chambres Eco SDB Confort All OFF", "id": 8, "type": 4, "rooms_temp": [ { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "away" }, { "room_id": "3435163850", "therm_setpoint_fp": "away" }, { "room_id": "3497055021", "therm_setpoint_fp": "away" }, { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "away" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "away" }, { "room_id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "room_id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "room_id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "away" }, { "id": "3435163850", "therm_setpoint_fp": "away" }, { "id": "3497055021", "therm_setpoint_fp": "away" }, { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "away" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "away" }, { "id": "93888250", "therm_setpoint_fp": "frost_guard" }, { "id": "927970817", "therm_setpoint_fp": "frost_guard" }, { "id": "1641945290", "therm_setpoint_fp": "frost_guard" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] }, { "name": "Chambres & SDB Confort All OFF", "id": 9, "type": 4, "rooms_temp": [ { "room_id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "room_id": "2042969726", "therm_setpoint_fp": "comfort" }, { "room_id": "3435163850", "therm_setpoint_fp": "comfort" }, { "room_id": "3497055021", "therm_setpoint_fp": "comfort" }, { "room_id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "room_id": "3795659199", "therm_setpoint_fp": "comfort" }, { "room_id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "room_id": "873035982", "therm_setpoint_fp": "comfort" }, { "room_id": "93888250", "therm_setpoint_fp": "comfort" }, { "room_id": "927970817", "therm_setpoint_fp": "comfort" }, { "room_id": "1641945290", "therm_setpoint_fp": "comfort" }, { "room_id": "2102454491", "therm_setpoint_fp": "frost_guard" } ], "modules": [], "rooms": [ { "id": "1662974901", "therm_setpoint_fp": "frost_guard" }, { "id": "2042969726", "therm_setpoint_fp": "comfort" }, { "id": "3435163850", "therm_setpoint_fp": "comfort" }, { "id": "3497055021", "therm_setpoint_fp": "comfort" }, { "id": "3707962039", "therm_setpoint_fp": "frost_guard" }, { "id": "3795659199", "therm_setpoint_fp": "comfort" }, { "id": "596817675", "therm_setpoint_fp": "frost_guard" }, { "id": "873035982", "therm_setpoint_fp": "comfort" }, { "id": "93888250", "therm_setpoint_fp": "comfort" }, { "id": "927970817", "therm_setpoint_fp": "comfort" }, { "id": "1641945290", "therm_setpoint_fp": "comfort" }, { "id": "2102454491", "therm_setpoint_fp": "frost_guard" } ] } ], "name": "SDM seulement", "default": false, "away_temp": 12, "hg_temp": 7, "id": "65428fdc7349fc4e49034381", "type": "therm" }, { "timetable": [ { "zone_id": 1, "m_offset": 300 }, { "zone_id": 3, "m_offset": 540 }, { "zone_id": 2, "m_offset": 960 }, { "zone_id": 0, "m_offset": 1020 }, { "zone_id": 1, "m_offset": 1740 }, { "zone_id": 3, "m_offset": 1980 }, { "zone_id": 2, "m_offset": 2400 }, { "zone_id": 0, "m_offset": 2460 }, { "zone_id": 1, "m_offset": 3180 }, { "zone_id": 3, "m_offset": 3420 }, { "zone_id": 2, "m_offset": 3840 }, { "zone_id": 0, "m_offset": 3900 }, { "zone_id": 1, "m_offset": 4620 }, { "zone_id": 3, "m_offset": 4860 }, { "zone_id": 2, "m_offset": 5280 }, { "zone_id": 0, "m_offset": 5340 }, { "zone_id": 1, "m_offset": 6060 }, { "zone_id": 3, "m_offset": 6300 }, { "zone_id": 2, "m_offset": 6720 }, { "zone_id": 0, "m_offset": 6780 }, { "zone_id": 1, "m_offset": 7500 }, { "zone_id": 3, "m_offset": 7740 }, { "zone_id": 2, "m_offset": 8160 }, { "zone_id": 0, "m_offset": 8220 }, { "zone_id": 1, "m_offset": 8940 }, { "zone_id": 3, "m_offset": 9180 }, { "zone_id": 2, "m_offset": 9600 }, { "zone_id": 0, "m_offset": 9660 } ], "zones": [ { "id": 0, "modules": [ { "id": "98:76:54:32:10:00:00:67", "bridge": "aa:aa:aa:aa:aa:aa", "on": false } ] }, { "id": 1, "modules": [ { "id": "98:76:54:32:10:00:00:67", "bridge": "aa:aa:aa:aa:aa:aa", "on": true } ] }, { "id": 2, "modules": [ { "id": "98:76:54:32:10:00:00:67", "bridge": "aa:aa:aa:aa:aa:aa", "on": true } ] }, { "id": 3, "modules": [ { "id": "98:76:54:32:10:00:00:67", "bridge": "aa:aa:aa:aa:aa:aa", "on": false } ] } ], "name": "Planning d'actions", "default": false, "timetable_sunrise": [], "timetable_sunset": [], "id": "64fa4a1266404bbb130f4b71", "type": "event", "selected": true }, { "timetable": [], "zones": [], "name": "Hiver", "default": false, "timetable_sunrise": [], "timetable_sunset": [], "id": "65c3f82f61e0a3ec5401640f", "type": "event" }, { "timetable": [ { "zone_id": 0, "m_offset": 0 }, { "zone_id": 1, "m_offset": 130 }, { "zone_id": 0, "m_offset": 430 }, { "zone_id": 1, "m_offset": 850 }, { "zone_id": 0, "m_offset": 1030 }, { "zone_id": 1, "m_offset": 1570 }, { "zone_id": 0, "m_offset": 1870 }, { "zone_id": 1, "m_offset": 2290 }, { "zone_id": 0, "m_offset": 2470 }, { "zone_id": 1, "m_offset": 3010 }, { "zone_id": 0, "m_offset": 3310 }, { "zone_id": 1, "m_offset": 3730 }, { "zone_id": 0, "m_offset": 3910 }, { "zone_id": 1, "m_offset": 4450 }, { "zone_id": 0, "m_offset": 4750 }, { "zone_id": 1, "m_offset": 5170 }, { "zone_id": 0, "m_offset": 5350 }, { "zone_id": 1, "m_offset": 5890 }, { "zone_id": 0, "m_offset": 6190 }, { "zone_id": 1, "m_offset": 6610 }, { "zone_id": 0, "m_offset": 6790 }, { "zone_id": 1, "m_offset": 7330 }, { "zone_id": 0, "m_offset": 7630 }, { "zone_id": 1, "m_offset": 8050 }, { "zone_id": 0, "m_offset": 8230 }, { "zone_id": 1, "m_offset": 8770 }, { "zone_id": 0, "m_offset": 9070 }, { "zone_id": 1, "m_offset": 9490 }, { "zone_id": 0, "m_offset": 9670 } ], "zones": [ { "id": 0, "price": 0.27, "price_type": "peak" }, { "id": 1, "price": 0.2068, "price_type": "off_peak" } ], "name": "electricity", "default": false, "tariff": "edf_tarif_bleu", "tariff_option": "peak_and_off_peak", "power_threshold": 36, "contract_power_unit": "kW", "id": "60ce3d057a24d640444c4f1c", "type": "electricity", "selected": true } ] }, { "id": "eeeeeeeeeffffffffffaaaaa", "name": "A SECOND HOME", "altitude": 200, "coordinates": [ 34.345576, 89.667112 ], "country": "FR", "timezone": "Europe/Paris", "rooms": [ { "id": "1468717414", "name": "Cave", "type": "garage", "module_ids": [ "12:34:56:78:90:00:00:09", "12:34:56:78:90:00:00:20", "12:34:56:78:90:00:00:33" ] }, { "id": "738709350", "name": "Salon", "type": "livingroom", "module_ids": [ "bb:bb:bb:bb:bb:bb", "12:34:56:78:90:00:00:01", "12:34:56:78:90:00:00:02", "12:34:56:78:90:00:00:03", "12:34:56:78:90:00:00:04", "12:34:56:78:90:00:00:05", "12:34:56:78:90:00:00:06", "12:34:56:78:90:00:00:07", "12:34:56:78:90:00:00:08", "12:34:56:78:90:00:00:10", "12:34:56:78:90:00:00:23", "12:34:56:78:90:00:00:24", "12:34:56:78:90:00:00:29", "12:34:56:78:90:00:00:30" ] }, { "id": "3098890768", "name": "Entrée", "type": "lobby", "module_ids": [ "12:34:56:78:90:00:00:11" ] }, { "id": "70754041", "name": "Salle de bains", "type": "bathroom", "module_ids": [ "12:34:56:78:90:00:00:12", "12:34:56:78:90:00:00:26" ] }, { "id": "1761556353", "name": "Nouveaux toilettes", "type": "toilets", "module_ids": [ "12:34:56:78:90:00:00:13" ] }, { "id": "968846272", "name": "Anciens Toilettes", "type": "toilets", "module_ids": [ "12:34:56:78:90:00:00:14" ] }, { "id": "4008422910", "name": "Palier", "type": "corridor", "module_ids": [ "12:34:56:78:90:00:00:15", "12:34:56:78:90:00:00:18", "12:34:56:78:90:00:00:31" ] }, { "id": "2640531479", "name": "Chambre parents", "type": "bedroom", "module_ids": [ "12:34:56:78:90:00:00:16", "12:34:56:78:90:00:00:27" ] }, { "id": "2667868658", "name": "Chambre Older", "type": "bedroom", "module_ids": [ "12:34:56:78:90:00:00:17", "12:34:56:78:90:00:00:22" ] }, { "id": "3783425301", "name": "Chambre Enfants", "type": "bedroom", "module_ids": [ "12:34:56:78:90:00:00:19", "12:34:56:78:90:00:00:28" ] }, { "id": "68319658", "name": "Chambre Old", "type": "bedroom", "module_ids": [ "12:34:56:78:90:00:00:25" ] }, { "id": "1156588698", "name": "Jardin", "type": "outdoor", "module_ids": [ "12:34:56:78:90:00:00:21" ] }, { "id": "1229033409", "name": "Grenier", "type": "custom", "module_ids": [ "12:34:56:78:90:00:00:32", "12:34:56:78:90:00:00:34" ] } ], "modules": [ { "id": "bb:bb:bb:bb:bb:bb", "type": "NLG", "name": "Legrand Gateway", "setup_date": 1692558574, "room_id": "738709350", "modules_bridged": [ "12:34:56:78:90:00:00:01", "12:34:56:78:90:00:00:02", "12:34:56:78:90:00:00:03", "12:34:56:78:90:00:00:04", "12:34:56:78:90:00:00:05", "12:34:56:78:90:00:00:06", "12:34:56:78:90:00:00:07", "12:34:56:78:90:00:00:08", "12:34:56:78:90:00:00:09", "12:34:56:78:90:00:00:10", "12:34:56:78:90:00:00:11", "12:34:56:78:90:00:00:12", "12:34:56:78:90:00:00:13", "12:34:56:78:90:00:00:14", "12:34:56:78:90:00:00:15", "12:34:56:78:90:00:00:16", "12:34:56:78:90:00:00:17", "12:34:56:78:90:00:00:18", "12:34:56:78:90:00:00:19", "12:34:56:78:90:00:00:20", "12:34:56:78:90:00:00:21", "12:34:56:78:90:00:00:22", "12:34:56:78:90:00:00:23", "12:34:56:78:90:00:00:24", "12:34:56:78:90:00:00:25", "12:34:56:78:90:00:00:26", "12:34:56:78:90:00:00:27", "12:34:56:78:90:00:00:28", "12:34:56:78:90:00:00:29", "12:34:56:78:90:00:00:30", "12:34:56:78:90:00:00:31", "12:34:56:78:90:00:00:32", "12:34:56:78:90:00:00:33", "12:34:56:78:90:00:00:34" ] }, { "id": "12:34:56:78:90:00:00:01", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 1", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:02", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 2", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:03", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 3", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:04", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 4", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:05", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 5", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:06", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 6", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:07", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 7", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:08", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 8", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:09", "type": "NLPO", "name": "OL Cumulus", "setup_date": 1692558628, "room_id": "1468717414", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "water_heater" }, { "id": "12:34:56:78:90:00:00:10", "type": "NLPT", "name": "OL Lumière Cuisine", "setup_date": 1692558628, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:11", "type": "NLPT", "name": "OL Escalier", "setup_date": 1692558628, "room_id": "3098890768", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:12", "type": "NLPT", "name": "OL Éclairage Salle de bain", "setup_date": 1692558628, "room_id": "70754041", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:13", "type": "NLPT", "name": "OL Lumière nouveaux toilettes", "setup_date": 1692558628, "room_id": "1761556353", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:14", "type": "NLPT", "name": "OL Lumière anciens toilettes", "setup_date": 1692558628, "room_id": "968846272", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:15", "type": "NLPT", "name": "OL Lumière palier salle de bain", "setup_date": 1692558628, "room_id": "4008422910", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:16", "type": "NLPT", "name": "OL Lumière chambre A", "setup_date": 1692558628, "room_id": "2640531479", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:17", "type": "NLPT", "name": "OL Lumière Chambre Older", "setup_date": 1692558628, "room_id": "2667868658", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:18", "type": "NLPT", "name": "OL Lumière Palier", "setup_date": 1692558628, "room_id": "4008422910", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:19", "type": "NLPT", "name": "OL Lumière enfants", "setup_date": 1692558628, "room_id": "3783425301", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:20", "type": "NLM", "name": "OL Lumière Cave", "setup_date": 1692643741, "room_id": "1468717414", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:21", "type": "NLM", "name": "OL Lumière Jardin", "setup_date": 1692643763, "room_id": "1156588698", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:22", "type": "NLC", "name": "OL Radiateur Chambre Older", "setup_date": 1692644489, "room_id": "2667868658", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:23", "type": "NLC", "name": "OL Radiateur Salon Fenêtre", "setup_date": 1692644493, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:24", "type": "NLC", "name": "OL Radiateur Salon Porte", "setup_date": 1692644497, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:25", "type": "NLC", "name": "OL Radiateur Chambre Old", "setup_date": 1692644501, "room_id": "68319658", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:26", "type": "NLC", "name": "OL Radiateur Serviette", "setup_date": 1692644506, "room_id": "70754041", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:27", "type": "NLC", "name": "OL Radiateur Chambre A", "setup_date": 1692644509, "room_id": "2640531479", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:28", "type": "NLC", "name": "OL Radiateur Chambre E", "setup_date": 1693159267, "room_id": "3783425301", "bridge": "bb:bb:bb:bb:bb:bb", "appliance_type": "radiator" }, { "id": "12:34:56:78:90:00:00:29", "type": "NLPT", "name": "OL Salle à manger", "setup_date": 1696921179, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:30", "type": "NLPT", "name": "OL Plan de travail", "setup_date": 1696921199, "room_id": "738709350", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:31", "type": "NLAO", "name": "Commande On/Off (Sans-Fil, Sans Pile) 9", "setup_date": 1696922170, "room_id": "4008422910", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:32", "type": "NLPT", "name": "OL Lumière Grenier", "setup_date": 1696949709, "room_id": "1229033409", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:33", "type": "NLAO", "name": "Commande Cave", "setup_date": 1696949890, "room_id": "1468717414", "bridge": "bb:bb:bb:bb:bb:bb" }, { "id": "12:34:56:78:90:00:00:34", "type": "NLAO", "name": "Commande Grenier", "setup_date": 1696951661, "room_id": "1229033409", "bridge": "bb:bb:bb:bb:bb:bb" } ], "temperature_control_mode": "heating", "therm_mode": "hg", "therm_setpoint_default_duration": 180, "schedules": [ { "timetable": [ { "zone_id": 1, "m_offset": 0 }, { "zone_id": 0, "m_offset": 420 }, { "zone_id": 4, "m_offset": 480 }, { "zone_id": 0, "m_offset": 1140 }, { "zone_id": 1, "m_offset": 1320 }, { "zone_id": 0, "m_offset": 1860 }, { "zone_id": 4, "m_offset": 1920 }, { "zone_id": 0, "m_offset": 2580 }, { "zone_id": 1, "m_offset": 2760 }, { "zone_id": 0, "m_offset": 3300 }, { "zone_id": 4, "m_offset": 3360 }, { "zone_id": 0, "m_offset": 4020 }, { "zone_id": 1, "m_offset": 4200 }, { "zone_id": 0, "m_offset": 4740 }, { "zone_id": 4, "m_offset": 4800 }, { "zone_id": 0, "m_offset": 5460 }, { "zone_id": 1, "m_offset": 5640 }, { "zone_id": 0, "m_offset": 6180 }, { "zone_id": 4, "m_offset": 6240 }, { "zone_id": 0, "m_offset": 6900 }, { "zone_id": 1, "m_offset": 7080 }, { "zone_id": 0, "m_offset": 7620 }, { "zone_id": 4, "m_offset": 7800 }, { "zone_id": 0, "m_offset": 8220 }, { "zone_id": 1, "m_offset": 8520 }, { "zone_id": 0, "m_offset": 9060 }, { "zone_id": 4, "m_offset": 9240 }, { "zone_id": 0, "m_offset": 9660 }, { "zone_id": 1, "m_offset": 9960 } ], "zones": [ { "name": "Comfort", "id": 0, "type": 0, "rooms_temp": [ { "room_id": "738709350", "therm_setpoint_fp": "comfort" }, { "room_id": "70754041", "therm_setpoint_fp": "comfort" }, { "room_id": "2640531479", "therm_setpoint_fp": "comfort" }, { "room_id": "2667868658", "therm_setpoint_fp": "comfort" }, { "room_id": "3783425301", "therm_setpoint_fp": "comfort" }, { "room_id": "68319658", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "738709350", "therm_setpoint_fp": "comfort" }, { "id": "70754041", "therm_setpoint_fp": "comfort" }, { "id": "2640531479", "therm_setpoint_fp": "comfort" }, { "id": "2667868658", "therm_setpoint_fp": "comfort" }, { "id": "3783425301", "therm_setpoint_fp": "comfort" }, { "id": "68319658", "therm_setpoint_fp": "comfort" } ] }, { "name": "Night", "id": 1, "type": 1, "rooms_temp": [ { "room_id": "738709350", "therm_setpoint_fp": "away" }, { "room_id": "70754041", "therm_setpoint_fp": "away" }, { "room_id": "2640531479", "therm_setpoint_fp": "away" }, { "room_id": "2667868658", "therm_setpoint_fp": "away" }, { "room_id": "3783425301", "therm_setpoint_fp": "away" }, { "room_id": "68319658", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "738709350", "therm_setpoint_fp": "away" }, { "id": "70754041", "therm_setpoint_fp": "away" }, { "id": "2640531479", "therm_setpoint_fp": "away" }, { "id": "2667868658", "therm_setpoint_fp": "away" }, { "id": "3783425301", "therm_setpoint_fp": "away" }, { "id": "68319658", "therm_setpoint_fp": "away" } ] }, { "name": "Comfort+", "id": 3, "type": 8, "rooms_temp": [ { "room_id": "738709350", "therm_setpoint_fp": "comfort" }, { "room_id": "70754041", "therm_setpoint_fp": "comfort" }, { "room_id": "2640531479", "therm_setpoint_fp": "comfort" }, { "room_id": "2667868658", "therm_setpoint_fp": "comfort" }, { "room_id": "3783425301", "therm_setpoint_fp": "comfort" }, { "room_id": "68319658", "therm_setpoint_fp": "comfort" } ], "modules": [], "rooms": [ { "id": "738709350", "therm_setpoint_fp": "comfort" }, { "id": "70754041", "therm_setpoint_fp": "comfort" }, { "id": "2640531479", "therm_setpoint_fp": "comfort" }, { "id": "2667868658", "therm_setpoint_fp": "comfort" }, { "id": "3783425301", "therm_setpoint_fp": "comfort" }, { "id": "68319658", "therm_setpoint_fp": "comfort" } ] }, { "name": "Eco", "id": 4, "type": 5, "rooms_temp": [ { "room_id": "738709350", "therm_setpoint_fp": "away" }, { "room_id": "70754041", "therm_setpoint_fp": "away" }, { "room_id": "2640531479", "therm_setpoint_fp": "away" }, { "room_id": "2667868658", "therm_setpoint_fp": "away" }, { "room_id": "3783425301", "therm_setpoint_fp": "away" }, { "room_id": "68319658", "therm_setpoint_fp": "away" } ], "modules": [], "rooms": [ { "id": "738709350", "therm_setpoint_fp": "away" }, { "id": "70754041", "therm_setpoint_fp": "away" }, { "id": "2640531479", "therm_setpoint_fp": "away" }, { "id": "2667868658", "therm_setpoint_fp": "away" }, { "id": "3783425301", "therm_setpoint_fp": "away" }, { "id": "68319658", "therm_setpoint_fp": "away" } ] } ], "name": "Mon planning de chauffe", "default": false, "away_temp": 12, "hg_temp": 7, "id": "64e3b6102853d9405304b27a", "type": "therm", "selected": true }, { "timetable": [], "zones": [], "name": "Planning d'actions", "default": false, "timetable_sunrise": [], "timetable_sunset": [], "id": "64ee68e2c8419b37790c5050", "type": "event", "selected": true }, { "timetable": [ { "zone_id": 0, "m_offset": 0 } ], "zones": [ { "id": 0, "price": 0.2516, "price_type": "basic" } ], "name": "electricity", "default": false, "tariff": "edf_tarif_bleu", "tariff_option": "basic", "power_threshold": 9, "contract_power_unit": "kVA", "id": "64e28390bc6d555f2d05c684", "type": "electricity", "selected": true } ] } ], "user": { "email": "john.doe@doe.com", "language": "fr-FR", "locale": "fr-FR", "feel_like_algorithm": 0, "unit_pressure": 0, "unit_system": 0, "unit_wind": 0, "id": "111111111112222222333333" } }, "status": "ok", "time_exec": 0.07427000999450684, "time_server": 1709762264 }jabesq-org-pyatmo-6216472/fixtures/homestatus_91763b24c43d3e344f424e8b.json000066400000000000000000000263731466116727400254620ustar00rootroot00000000000000{ "status": "ok", "time_server": 1559292039, "body": { "home": { "modules": [ { "id": "12:34:56:80:bb:26", "type": "NAMain", "firmware_revision": 202, "wifi_state": "full", "wifi_strength": 45, "ts": 1702884705, "temperature": 18.9, "co2": 498, "humidity": 33, "noise": 47, "pressure": 1034.8, "absolute_pressure": 956.1 }, { "id": "12:34:56:80:1c:42", "type": "NAModule1", "battery_state": "full", "battery_level": 6690, "firmware_revision": 53, "rf_state": "full", "rf_strength": 42, "last_seen": 1702884800, "reachable": true, "bridge": "70:ee:50:37:11:ca", "ts": 1702884697, "temperature": 5.8, "humidity": 65 }, { "id": "12:34:56:00:f1:62", "type": "NACamera", "monitoring": "on", "sd_status": 4, "alim_status": 2, "locked": false, "vpn_url": "https://prodvpn-eu-2.netatmo.net/restricted/10.255.123.45/609e27de5699fb18147ab47d06846631/MTRPn_BeWCav5RBq4U1OMDruTW4dkQ0NuMwNDAw11g,,", "is_local": true }, { "id": "12:34:56:00:fa:d0", "type": "NAPlug", "firmware_revision": 174, "rf_strength": 107, "wifi_strength": 42 }, { "id": "12:34:56:00:01:ae", "reachable": true, "type": "NATherm1", "firmware_revision": 65, "rf_strength": 58, "battery_level": 3793, "boiler_valve_comfort_boost": false, "boiler_status": false, "anticipating": false, "bridge": "12:34:56:00:fa:d0", "battery_state": "high" }, { "id": "12:34:56:03:a5:54", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 51, "battery_level": 3025, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" }, { "id": "12:34:56:03:a0:ac", "reachable": true, "type": "NRV", "firmware_revision": 79, "rf_strength": 59, "battery_level": 3029, "bridge": "12:34:56:00:fa:d0", "battery_state": "full" }, { "type": "NDB", "last_ftp_event": { "type": 3, "time": 1631444443, "id": 3 }, "id": "12:34:56:10:f1:66", "websocket_connected": true, "vpn_url": "https://prodvpn-eu-6.netatmo.net/10.20.30.40/1111111111111/2222222222222,,", "is_local": false, "alim_status": 2, "connection": "wifi", "firmware_name": "2.18.0", "firmware_revision": 2018000, "homekit_status": "configured", "max_peers_reached": false, "sd_status": 4, "wifi_strength": 66, "wifi_state": "medium" }, { "type": "NOC", "firmware_revision": 3002000, "monitoring": "on", "sd_status": 4, "connection": "wifi", "homekit_status": "upgradable", "floodlight": "auto", "timelapse_available": true, "id": "12:34:56:10:b9:0e", "vpn_url": "https://prodvpn-eu-6.netatmo.net/10.20.30.41/333333333333/444444444444,,", "is_local": false, "network_lock": false, "firmware_name": "3.2.0", "wifi_strength": 62, "alim_status": 2, "locked": false, "wifi_state": "high" }, { "boiler_control": "onoff", "dhw_control": "none", "firmware_revision": 22, "hardware_version": 222, "id": "12:34:56:20:f5:44", "outdoor_temperature": 8.2, "sequence_id": 19764, "type": "OTH", "wifi_strength": 57 }, { "battery_level": 4176, "boiler_status": false, "boiler_valve_comfort_boost": false, "firmware_revision": 6, "id": "12:34:56:20:f5:8c", "last_message": 1637684297, "last_seen": 1637684297, "radio_id": 2, "reachable": true, "rf_strength": 64, "type": "OTM", "bridge": "12:34:56:20:f5:44", "battery_state": "full" }, { "id": "12:34:56:30:d5:d4", "type": "NBG", "firmware_revision": 39, "wifi_strength": 65, "reachable": true }, { "id": "0009999992", "type": "NBR", "current_position": 0, "target_position": 0, "target_position_step": 100, "firmware_revision": 16, "rf_strength": 0, "last_seen": 1638353156, "reachable": true, "bridge": "12:34:56:30:d5:d4" }, { "id": "0009999993", "type": "NBO", "current_position": 0, "target_position": 0, "target_position:step": 100, "firmware_revision": 22, "rf_strength": 0, "last_seen": 1671395511, "reachable": true, "bridge": "12:34:56:30:d5:d4" }, { "id": "12:34:56:00:86:99", "type": "NACamDoorTag", "battery_state": "high", "battery_level": 5240, "firmware_revision": 58, "rf_state": "full", "rf_strength": 58, "last_seen": 1642698124, "last_activity": 1627757310, "reachable": false, "bridge": "12:34:56:00:f1:62", "status": "no_news" }, { "id": "12:34:56:00:e3:9b", "type": "NIS", "battery_state": "low", "battery_level": 5438, "firmware_revision": 209, "rf_state": "medium", "rf_strength": 62, "last_seen": 1644569790, "reachable": true, "bridge": "12:34:56:00:f1:62", "status": "no_sound", "monitoring": "off" }, { "id": "12:34:56:80:60:40", "type": "NLG", "offload": false, "firmware_revision": 211, "last_seen": 1644567372, "wifi_strength": 51, "reachable": true }, { "id": "12:34:56:80:00:12:ac:f2", "type": "NLP", "on": true, "offload": false, "firmware_revision": 62, "last_seen": 1644569425, "power": 0, "reachable": true, "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:80:00:c3:69:3c", "type": "NLT", "battery_state": "full", "battery_level": 3300, "firmware_revision": 42, "last_seen": 0, "reachable": false, "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:00:16:0e", "type": "NLE", "firmware_revision": 14, "wifi_strength": 38 }, { "id": "12:34:56:00:16:0e#0", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#1", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#2", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#3", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#4", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#5", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#6", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#7", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:16:0e#8", "type": "NLE", "bridge": "12:34:56:00:16:0e" }, { "id": "12:34:56:00:00:a1:4c:da", "type": "NLPC", "firmware_revision": 62, "last_seen": 1646511241, "power": 476, "reachable": true, "bridge": "12:34:56:80:60:40" }, { "id": "10:20:30:bd:b8:1e", "type": "BNS", "firmware_revision": 32, "wifi_strength": 49, "boiler_valve_comfort_boost": false, "boiler_status": true, "cooler_status": false }, { "id": "00:11:22:33:00:11:45:fe", "type": "NLF", "on": false, "brightness": 63, "firmware_revision": 57, "last_seen": 1657086939, "power": 0, "reachable": true, "bridge": "12:34:56:80:60:40" }, { "id": "12:34:56:00:01:01:01:b1", "type": "NLLF", "firmware_revision": 60, "last_seen": 1657086949, "power": 11, "reachable": true, "bridge": "12:34:56:80:60:40", "fan_speed": 1 } ], "rooms": [ { "id": "2746182631", "reachable": true, "therm_measured_temperature": 19.8, "therm_setpoint_temperature": 12, "therm_setpoint_mode": "away", "therm_setpoint_start_time": 1559229567, "therm_setpoint_end_time": 0 }, { "id": "2940411577", "reachable": true, "therm_measured_temperature": 27, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false }, { "id": "2833524037", "reachable": true, "therm_measured_temperature": 24.5, "heating_power_request": 0, "therm_setpoint_temperature": 7, "therm_setpoint_mode": "hg", "therm_setpoint_start_time": 0, "therm_setpoint_end_time": 0, "anticipating": false, "open_window": false }, { "id": "1002003001", "reachable": true, "anticipating": false, "heating_power_request": 0, "open_window": false, "humidity": 67, "therm_measured_temperature": 22, "therm_setpoint_temperature": 22, "therm_setpoint_start_time": 1647462737, "therm_setpoint_end_time": null, "therm_setpoint_mode": "home" } ], "id": "91763b24c43d3e344f424e8b", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", "last_seen": 1557071156, "out_of_sight": true }, { "id": "91827375-7e04-5298-83ae-a0cb8372dff2", "last_seen": 1559282761, "out_of_sight": false }, { "id": "91827376-7e04-5298-83af-a0cb8372dff3", "last_seen": 1559224132, "out_of_sight": true } ] } } } jabesq-org-pyatmo-6216472/fixtures/homestatus_91763b24c43d3e344f424e8c.json000066400000000000000000000010061466116727400254450ustar00rootroot00000000000000{ "status": "ok", "time_server": 1642952130, "body": { "home": { "persons": [ { "id": "abcdef12-1111-0000-0000-000111222333", "last_seen": 1489050910, "out_of_sight": true }, { "id": "abcdef12-2222-0000-0000-000111222333", "last_seen": 1489078776, "out_of_sight": true } ] } } }jabesq-org-pyatmo-6216472/fixtures/ping.json000066400000000000000000000001631466116727400207670ustar00rootroot00000000000000{ "local_url": "http://192.168.0.123/678460a0d47e5618699fb31169e2b47d", "product_name": "Welcome Netatmo" }jabesq-org-pyatmo-6216472/fixtures/status_ok.json000066400000000000000000000001311466116727400220410ustar00rootroot00000000000000{ "status": "ok", "time_exec": 0.020781993865967, "time_server": 1559162635 }jabesq-org-pyatmo-6216472/pyproject.toml000066400000000000000000000126161466116727400202100ustar00rootroot00000000000000[build-system] requires = ["wheel", "setuptools", "attrs>=17.1"] build-backend = "setuptools.build_meta" [tool.pytest.ini_options] minversion = "7.0" asyncio_mode = "auto" [tool.ruff] select = [ "B002", # Python does not support the unary prefix increment "B007", # Loop control variable {name} not used within loop body "B014", # Exception handler with duplicate exception "B023", # Function definition does not bind loop variable {name} "B026", # Star-arg unpacking after a keyword argument is strongly discouraged "C", # complexity "COM818", # Trailing comma on bare tuple prohibited "D", # docstrings "DTZ003", # Use datetime.now(tz=) instead of datetime.utcnow() "DTZ004", # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts) "E", # pycodestyle "F", # pyflakes/autoflake "G", # flake8-logging-format "I", # isort "ICN001", # import concentions; {name} should be imported as {asname} "ISC001", # Implicitly concatenated string literals on one line "N804", # First argument of a class method should be named cls "N805", # First argument of a method should be named self "N815", # Variable {name} in class scope should not be mixedCase "PGH001", # No builtin eval() allowed "PGH004", # Use specific rule codes when using noqa "PLC0414", # Useless import alias. Import alias does not rename original package. "PLC", # pylint "PLE", # pylint "PLR", # pylint "PLW", # pylint "Q000", # Double quotes found but single quotes preferred "RUF006", # Store a reference to the return value of asyncio.create_task "S102", # Use of exec detected "S103", # bad-file-permissions "S108", # hardcoded-temp-file "S306", # suspicious-mktemp-usage "S307", # suspicious-eval-usage "S313", # suspicious-xmlc-element-tree-usage "S314", # suspicious-xml-element-tree-usage "S315", # suspicious-xml-expat-reader-usage "S316", # suspicious-xml-expat-builder-usage "S317", # suspicious-xml-sax-usage "S318", # suspicious-xml-mini-dom-usage "S319", # suspicious-xml-pull-dom-usage "S320", # suspicious-xmle-tree-usage "S601", # paramiko-call "S602", # subprocess-popen-with-shell-equals-true "S604", # call-with-shell-equals-true "S608", # hardcoded-sql-expression "S609", # unix-command-wildcard-injection "SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass "SIM117", # Merge with-statements that use the same scope "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() "SIM201", # Use {left} != {right} instead of not {left} == {right} "SIM208", # Use {expr} instead of not (not {expr}) "SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a} "SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'. "SIM401", # Use get from dict with default instead of an if block "T100", # Trace found: {name} used "T20", # flake8-print "TID251", # Banned imports "TRY004", # Prefer TypeError exception for invalid type "TRY200", # Use raise from to specify exception cause "TRY302", # Remove exception handler; error is immediately re-raised "UP", # pyupgrade "W", # pycodestyle ] ignore = [ "D202", # No blank lines allowed after function docstring "D203", # 1 blank line required before class docstring "D213", # Multi-line docstring summary should start at the second line "D406", # Section name should end with a newline "D407", # Section name underlining "E501", # line too long "E731", # do not assign a lambda expression, use a def # False positives https://github.com/astral-sh/ruff/issues/5386 "PLC0208", # Use a sequence type instead of a `set` when iterating over values "PLR0911", # Too many return statements ({returns} > {max_returns}) "PLR0912", # Too many branches ({branches} > {max_branches}) "PLR0913", # Too many arguments to function call ({c_args} > {max_args}) "PLR0915", # Too many statements ({statements} > {max_statements}) "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target "UP006", # keep type annotation style as is "UP007", # keep type annotation style as is # Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923 "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] [tool.ruff.flake8-pytest-style] fixture-parentheses = false [tool.ruff.flake8-tidy-imports.banned-api] "pytz".msg = "use zoneinfo instead" [tool.ruff.isort] force-sort-within-sections = true combine-as-imports = true split-on-trailing-comma = false [tool.ruff.per-file-ignores] # Allow for main entry & scripts to write to stdout "src/pyatmo/__main__.py" = ["T201"] # Exceptions for tests "tests/*" = ["D10"] [tool.ruff.mccabe] max-complexity = 25 [tool.setuptools_scm] local_scheme = "no-local-version" tag_regex = "^(?Pv)?(?P[^\\+]+)(?P.*)?$" write_to = "src/pyatmo/__version__.py" write_to_template = '''""" Pyatmo: Simple API to access Netatmo devices and data DO NO EDIT THIS FILE - VERSION IS MANAGED BY SETUPTOOLS_SCM """ __version__ = "{version}" ''' jabesq-org-pyatmo-6216472/setup.cfg000066400000000000000000000023521466116727400171110ustar00rootroot00000000000000[metadata] name = pyatmo description = Simple API to access Netatmo weather station data from any Python 3 script. Designed for Home Assistant (but not only) long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/jabesq/pyatmo author = Hugo Dupras author_email = jabesq@gmail.com license = MIT license_files = LICENSE.txt classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy Topic :: Home Automation [options] packages = find: install_requires = aiohttp>=3.7.4,<4.0.0 oauthlib~=3.1 requests~=2.24 requests-oauthlib>=1.3,<3.0 python_requires = >=3.10 include_package_data = True package_dir = =src setup_requires = setuptools-scm [options.packages.find] where = src exclude = tests [options.package_data] pyatmo = py.typed [pep8] max-line-length = 88 ignore = W503, E501 [mypy] ignore_missing_imports = True [isort] profile = black jabesq-org-pyatmo-6216472/src/000077500000000000000000000000001466116727400160555ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/src/pyatmo/000077500000000000000000000000001466116727400173665ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/src/pyatmo/__init__.py000066400000000000000000000013451466116727400215020ustar00rootroot00000000000000"""Expose submodules.""" from pyatmo import const, modules from pyatmo.account import AsyncAccount from pyatmo.auth import AbstractAsyncAuth from pyatmo.exceptions import ( ApiError, ApiErrorThrottling, ApiHomeReachabilityError, InvalidHome, InvalidRoom, NoDevice, NoSchedule, ) from pyatmo.home import Home from pyatmo.modules import Module from pyatmo.modules.device_types import DeviceType from pyatmo.room import Room __all__ = [ "AbstractAsyncAuth", "ApiError", "ApiErrorThrottling", "ApiHomeReachabilityError", "AsyncAccount", "InvalidHome", "InvalidRoom", "Home", "Module", "Room", "DeviceType", "NoDevice", "NoSchedule", "const", "modules", ] jabesq-org-pyatmo-6216472/src/pyatmo/account.py000066400000000000000000000250151466116727400213770ustar00rootroot00000000000000"""Support for a Netatmo account.""" from __future__ import annotations import logging from typing import TYPE_CHECKING, Any from uuid import uuid4 from pyatmo import modules from pyatmo.const import ( GETEVENTS_ENDPOINT, GETHOMECOACHDATA_ENDPOINT, GETHOMESDATA_ENDPOINT, GETHOMESTATUS_ENDPOINT, GETPUBLIC_DATA_ENDPOINT, GETSTATIONDATA_ENDPOINT, HOME, SETSTATE_ENDPOINT, RawData, ) from pyatmo.helpers import extract_raw_data from pyatmo.home import Home from pyatmo.modules.module import MeasureInterval, Module if TYPE_CHECKING: from pyatmo.auth import AbstractAsyncAuth LOG = logging.getLogger(__name__) class AsyncAccount: """Async class of a Netatmo account.""" def __init__(self, auth: AbstractAsyncAuth, favorite_stations: bool = True) -> None: """Initialize the Netatmo account.""" self.auth: AbstractAsyncAuth = auth self.user: str | None = None self.all_homes_id: dict[str, str] = {} self.homes: dict[str, Home] = {} self.raw_data: RawData = {} self.favorite_stations: bool = favorite_stations self.public_weather_areas: dict[str, modules.PublicWeatherArea] = {} self.modules: dict[str, Module] = {} def __repr__(self) -> str: """Return the representation.""" return ( f"{self.__class__.__name__}(user={self.user}, home_ids={self.homes.keys()}" ) def process_topology(self, disabled_homes_ids: list[str] | None = None) -> None: """Process topology information from /homesdata.""" if disabled_homes_ids is None: disabled_homes_ids = [] for home in self.raw_data["homes"]: home_id = home.get("id", "Unknown") home_name = home.get("name", "Unknown") self.all_homes_id[home_id] = home_name if home_id in disabled_homes_ids: if home_id in self.homes: del self.homes[home_id] continue if home_id in self.homes: self.homes[home_id].update_topology(home) else: self.homes[home_id] = Home(self.auth, raw_data=home) async def async_update_topology( self, disabled_homes_ids: list[str] | None = None ) -> None: """Retrieve topology data from /homesdata.""" resp = await self.auth.async_post_api_request( endpoint=GETHOMESDATA_ENDPOINT, ) self.raw_data = extract_raw_data(await resp.json(), "homes") self.user = self.raw_data.get("user", {}).get("email") self.process_topology(disabled_homes_ids=disabled_homes_ids) async def async_update_status(self, home_id: str) -> None: """Retrieve status data from /homestatus.""" resp = await self.auth.async_post_api_request( endpoint=GETHOMESTATUS_ENDPOINT, params={"home_id": home_id}, ) raw_data = extract_raw_data(await resp.json(), HOME) await self.homes[home_id].update(raw_data, do_raise_for_reachability_error=True) async def async_update_events(self, home_id: str) -> None: """Retrieve events from /getevents.""" resp = await self.auth.async_post_api_request( endpoint=GETEVENTS_ENDPOINT, params={"home_id": home_id}, ) raw_data = extract_raw_data(await resp.json(), HOME) await self.homes[home_id].update(raw_data) async def async_update_weather_stations(self) -> None: """Retrieve status data from /getstationsdata.""" params = {"get_favorites": ("true" if self.favorite_stations else "false")} await self._async_update_data( GETSTATIONDATA_ENDPOINT, params=params, ) async def async_update_air_care(self) -> None: """Retrieve status data from /gethomecoachsdata.""" await self._async_update_data(GETHOMECOACHDATA_ENDPOINT) async def async_update_measures( self, home_id: str, module_id: str, start_time: int | None = None, end_time: int | None = None, interval: MeasureInterval = MeasureInterval.HOUR, days: int = 7, ) -> None: """Retrieve measures data from /getmeasure.""" await getattr(self.homes[home_id].modules[module_id], "async_update_measures")( start_time=start_time, end_time=end_time, interval=interval, days=days, ) def register_public_weather_area( self, lat_ne: str, lon_ne: str, lat_sw: str, lon_sw: str, required_data_type: str | None = None, filtering: bool = False, *, area_id: str = str(uuid4()), ) -> str: """Register public weather area to monitor.""" self.public_weather_areas[area_id] = modules.PublicWeatherArea( lat_ne, lon_ne, lat_sw, lon_sw, required_data_type, filtering, ) return area_id async def async_update_public_weather(self, area_id: str) -> None: """Retrieve status data from /getpublicdata.""" params = { "lat_ne": self.public_weather_areas[area_id].location.lat_ne, "lon_ne": self.public_weather_areas[area_id].location.lon_ne, "lat_sw": self.public_weather_areas[area_id].location.lat_sw, "lon_sw": self.public_weather_areas[area_id].location.lon_sw, "filtering": ( "true" if self.public_weather_areas[area_id].filtering else "false" ), } await self._async_update_data( GETPUBLIC_DATA_ENDPOINT, tag="body", params=params, area_id=area_id, ) async def _async_update_data( self, endpoint: str, params: dict[str, Any] | None = None, tag: str = "devices", area_id: str | None = None, ) -> None: """Retrieve status data from .""" resp = await self.auth.async_post_api_request(endpoint=endpoint, params=params) raw_data = extract_raw_data(await resp.json(), tag) await self.update_devices(raw_data, area_id) async def async_set_state(self, home_id: str, data: dict[str, Any]) -> None: """Modify device state by passing JSON specific to the device.""" LOG.debug("Setting state: %s", data) post_params = { "json": { HOME: { "id": home_id, **data, }, }, } resp = await self.auth.async_post_api_request( endpoint=SETSTATE_ENDPOINT, params=post_params, ) LOG.debug("Response: %s", resp) async def update_devices( self, raw_data: RawData, area_id: str | None = None, ) -> None: """Update device states.""" for device_data in raw_data.get("devices", {}): if home_id := device_data.get( "home_id", self.find_home_of_device(device_data), ): if home_id not in self.homes: modules_data = [] for module_data in device_data.get("modules", []): module_data["home_id"] = home_id module_data["id"] = module_data["_id"] module_data["name"] = module_data.get("module_name") modules_data.append(normalize_weather_attributes(module_data)) modules_data.append(normalize_weather_attributes(device_data)) self.homes[home_id] = Home( self.auth, raw_data={ "id": home_id, "name": device_data.get("home_name", "Unknown"), "modules": modules_data, }, ) await self.homes[home_id].update( {HOME: {"modules": [normalize_weather_attributes(device_data)]}}, ) else: LOG.debug("No home %s (%s) found.", home_id, home_id) for module_data in device_data.get("modules", []): module_data["home_id"] = home_id await self.update_devices({"devices": [module_data]}) if ( device_data["type"] == "NHC" or self.find_home_of_device(device_data) is None ): device_data["name"] = device_data.get( "station_name", device_data.get("module_name", "Unknown"), ) device_data = normalize_weather_attributes(device_data) if device_data["id"] not in self.modules: self.modules[device_data["id"]] = getattr( modules, device_data["type"], )( home=self, module=device_data, ) await self.modules[device_data["id"]].update(device_data) if device_data.get("modules", []): self.modules[device_data["id"]].modules = [ module["_id"] for module in device_data["modules"] ] if area_id is not None: self.public_weather_areas[area_id].update(raw_data) def find_home_of_device(self, device_data: dict[str, Any]) -> str | None: """Find home_id of device.""" return next( ( home_id for home_id, home in self.homes.items() if device_data["_id"] in home.modules ), None, ) ATTRIBUTES_TO_FIX = { "_id": "id", "firmware": "firmware_revision", "wifi_status": "wifi_strength", "rf_status": "rf_strength", "Temperature": "temperature", "Humidity": "humidity", "Pressure": "pressure", "CO2": "co2", "AbsolutePressure": "absolute_pressure", "Noise": "noise", "Rain": "rain", "WindStrength": "wind_strength", "WindAngle": "wind_angle", "GustStrength": "gust_strength", "GustAngle": "gust_angle", } def normalize_weather_attributes(raw_data: RawData) -> dict[str, Any]: """Normalize weather attributes.""" result: dict[str, Any] = {} for attribute, value in raw_data.items(): if attribute == "dashboard_data": result.update(**normalize_weather_attributes(value)) else: result[ATTRIBUTES_TO_FIX.get(attribute, attribute)] = value return result jabesq-org-pyatmo-6216472/src/pyatmo/auth.py000066400000000000000000000144371466116727400207120ustar00rootroot00000000000000"""Support for Netatmo authentication.""" from __future__ import annotations from abc import ABC, abstractmethod import asyncio from json import JSONDecodeError import logging from typing import Any from aiohttp import ClientError, ClientResponse, ClientSession, ContentTypeError from pyatmo.const import ( AUTHORIZATION_HEADER, DEFAULT_BASE_URL, ERRORS, WEBHOOK_URL_ADD_ENDPOINT, WEBHOOK_URL_DROP_ENDPOINT, ) from pyatmo.exceptions import ApiError, ApiErrorThrottling LOG = logging.getLogger(__name__) class AbstractAsyncAuth(ABC): """Abstract class to make authenticated requests.""" def __init__( self, websession: ClientSession, base_url: str = DEFAULT_BASE_URL, ) -> None: """Initialize the auth.""" self.websession = websession self.base_url = base_url @abstractmethod async def async_get_access_token(self) -> str: """Return a valid access token.""" async def async_get_image( self, endpoint: str, base_url: str | None = None, params: dict[str, Any] | None = None, timeout: int = 5, ) -> bytes: """Wrap async get requests.""" try: access_token = await self.async_get_access_token() except ClientError as err: raise ApiError(f"Access token failure: {err}") from err headers = {AUTHORIZATION_HEADER: f"Bearer {access_token}"} req_args = {"data": params if params is not None else {}} url = (base_url or self.base_url) + endpoint async with self.websession.get( url, **req_args, # type: ignore headers=headers, timeout=timeout, ) as resp: resp_content = await resp.read() if resp.headers.get("content-type") == "image/jpeg": return resp_content raise ApiError( f"{resp.status} - " f"invalid content-type in response" f"when accessing '{url}'", ) async def async_post_api_request( self, endpoint: str, base_url: str | None = None, params: dict[str, Any] | None = None, timeout: int = 5, ) -> ClientResponse: """Wrap async post requests.""" return await self.async_post_request( url=(base_url or self.base_url) + endpoint, params=params, timeout=timeout, ) async def async_post_request( self, url: str, params: dict[str, Any] | None = None, timeout: int = 5, ) -> ClientResponse: """Wrap async post requests.""" access_token = await self.get_access_token() headers = {AUTHORIZATION_HEADER: f"Bearer {access_token}"} req_args = self.prepare_request_arguments(params) async with self.websession.post( url, **req_args, headers=headers, timeout=timeout, ) as resp: return await self.process_response(resp, url) async def get_access_token(self): """Get access token.""" try: return await self.async_get_access_token() except ClientError as err: raise ApiError(f"Access token failure: {err}") from err def prepare_request_arguments(self, params): """Prepare request arguments.""" req_args = {"data": params if params is not None else {}} if "params" in req_args["data"]: req_args["params"] = req_args["data"]["params"] req_args["data"].pop("params") if "json" in req_args["data"]: req_args["json"] = req_args["data"]["json"] req_args.pop("data") return req_args async def process_response(self, resp, url): """Process response.""" resp_status = resp.status resp_content = await resp.read() if not resp.ok: LOG.debug("The Netatmo API returned %s (%s)", resp_content, resp_status) await self.handle_error_response(resp, resp_status, url) return await self.handle_success_response(resp, resp_content) async def handle_error_response(self, resp, resp_status, url): """Handle error response.""" try: resp_json = await resp.json() message = ( f"{resp_status} - " f"{ERRORS.get(resp_status, '')} - " f"{resp_json['error']['message']} " f"({resp_json['error']['code']}) " f"when accessing '{url}'", ) if resp_status == 403 and resp_json["error"]["code"] == 26: raise ApiErrorThrottling( message, ) else: raise ApiError( message, ) except (JSONDecodeError, ContentTypeError) as exc: raise ApiError( f"{resp_status} - " f"{ERRORS.get(resp_status, '')} - " f"when accessing '{url}'", ) from exc async def handle_success_response(self, resp, resp_content): """Handle success response.""" try: if "application/json" in resp.headers.get("content-type", []): return resp if resp_content not in [b"", b"None"]: return resp except (TypeError, AttributeError): LOG.debug("Invalid response %s", resp) return resp async def async_addwebhook(self, webhook_url: str) -> None: """Register webhook.""" try: resp = await self.async_post_api_request( endpoint=WEBHOOK_URL_ADD_ENDPOINT, params={"url": webhook_url}, ) except asyncio.exceptions.TimeoutError as exc: raise ApiError("Webhook registration timed out") from exc else: LOG.debug("addwebhook: %s", resp) async def async_dropwebhook(self) -> None: """Unregister webhook.""" try: resp = await self.async_post_api_request( endpoint=WEBHOOK_URL_DROP_ENDPOINT, params={"app_types": "app_security"}, ) except asyncio.exceptions.TimeoutError as exc: raise ApiError("Webhook registration timed out") from exc else: LOG.debug("dropwebhook: %s", resp) jabesq-org-pyatmo-6216472/src/pyatmo/const.py000066400000000000000000000067401466116727400210750ustar00rootroot00000000000000"""Common constants.""" from __future__ import annotations from typing import Any ERRORS: dict[int, str] = { 400: "Bad request", 401: "Unauthorized", 403: "Forbidden", 404: "Not found", 406: "Not Acceptable", 500: "Internal Server Error", 502: "Bad Gateway", 503: "Service Unavailable", } # Special types RawData = dict[str, Any] DEFAULT_BASE_URL: str = "https://api.netatmo.com/" # Endpoints AUTH_REQ_ENDPOINT = "oauth2/token" AUTH_URL_ENDPOINT = "oauth2/authorize" WEBHOOK_URL_ADD_ENDPOINT = "api/addwebhook" WEBHOOK_URL_DROP_ENDPOINT = "api/dropwebhook" GETHOMESDATA_ENDPOINT = "api/homesdata" GETHOMESTATUS_ENDPOINT = "api/homestatus" GETEVENTS_ENDPOINT = "api/getevents" SETTHERMMODE_ENDPOINT = "api/setthermmode" SETROOMTHERMPOINT_ENDPOINT = "api/setroomthermpoint" GETROOMMEASURE_ENDPOINT = "api/getroommeasure" SWITCHHOMESCHEDULE_ENDPOINT = "api/switchhomeschedule" SYNCHOMESCHEDULE_ENDPOINT = "api/synchomeschedule" GETHOMEDATA_ENDPOINT = "api/gethomedata" GETCAMERAPICTURE_ENDPOINT = "api/getcamerapicture" GETEVENTSUNTIL_ENDPOINT = "api/geteventsuntil" SETPERSONSAWAY_ENDPOINT = "api/setpersonsaway" SETPERSONSHOME_ENDPOINT = "api/setpersonshome" SETSTATE_ENDPOINT = "api/setstate" GETHOMECOACHDATA_ENDPOINT = "api/gethomecoachsdata" GETMEASURE_ENDPOINT = "api/getmeasure" GETSTATIONDATA_ENDPOINT = "api/getstationsdata" GETPUBLIC_DATA_ENDPOINT = "api/getpublicdata" AUTHORIZATION_HEADER = "Authorization" # Possible scops ALL_SCOPES: list[str] = [ "access_camera", # Netatmo camera products "access_doorbell", # Netatmo Smart Video Doorbell "access_presence", # Netatmo Smart Outdoor Camera "read_bubendorff", # Bubbendorf shutters "read_bfi", # BTicino IP "read_camera", # Netatmo camera products "read_carbonmonoxidedetector", # Netatmo CO sensor "read_doorbell", # Netatmo Smart Video Doorbell "read_homecoach", # Netatmo Smart Indoor Air Quality Monitor "read_magellan", # Legrand Wiring device or Electrical panel products "read_mhs1", # Bticino MyHome Server 1 modules "read_mx", # BTicino Classe 300 EOS "read_presence", # Netatmo Smart Outdoor Camera "read_smarther", # Smarther with Netatmo thermostat "read_smokedetector", # Smart Smoke Alarm information and events "read_station", # Netatmo weather station "read_thermostat", # Netatmo climate products "write_bubendorff", # Bubbendorf shutters "write_bfi", # BTicino IP "write_camera", # Netatmo camera products "write_magellan", # Legrand Wiring device or Electrical panel products "write_mhs1", # Bticino MyHome Server 1 modules "write_mx", # BTicino Classe 300 EOS "write_presence", # Netatmo Smart Outdoor Camera "write_smarther", # Smarther products "write_thermostat", # Netatmo climate products ] MANUAL = "manual" MAX = "max" HOME = "home" FROSTGUARD = "hg" SCHEDULES = "schedules" EVENTS = "events" STATION_TEMPERATURE_TYPE = "temperature" STATION_PRESSURE_TYPE = "pressure" STATION_HUMIDITY_TYPE = "humidity" ACCESSORY_RAIN_LIVE_TYPE = "rain_live" ACCESSORY_RAIN_60MIN_TYPE = "rain_60min" ACCESSORY_RAIN_24H_TYPE = "rain_24h" ACCESSORY_RAIN_TIME_TYPE = "rain_timeutc" ACCESSORY_WIND_STRENGTH_TYPE = "wind_strength" ACCESSORY_WIND_ANGLE_TYPE = "wind_angle" ACCESSORY_WIND_TIME_TYPE = "wind_timeutc" ACCESSORY_GUST_STRENGTH_TYPE = "gust_strength" ACCESSORY_GUST_ANGLE_TYPE = "gust_angle" # 2 days of dynamic historical data stored MAX_HISTORY_TIME_FRAME = 24 * 2 * 3600 UNKNOWN = "unknown" jabesq-org-pyatmo-6216472/src/pyatmo/event.py000066400000000000000000000055541466116727400210720ustar00rootroot00000000000000"""Module to represent a Netatmo event.""" from __future__ import annotations from dataclasses import dataclass from enum import Enum from pyatmo.const import RawData EVENT_ATTRIBUTES_MAP = {"id": "entity_id", "type": "event_type", "time": "event_time"} class EventTypes(Enum): """Event types.""" # temporarily disable locally-disabled and locally-enabled # pylint: disable=C0103 movement = "movement" person = "person" person_away = "person_away" connection = "connection" disconnection = "disconnection" new_module = "new_module" module_connect = "module_connect" module_disconnect = "module_disconnect" module_low_battery = "module_low_battery" module_end_update = "module_end_update" on = "on" off = "off" sd = "sd" alim = "alim" boot = "boot" outdoor = "outdoor" daily_summary = "daily_summary" tag_big_move = "tag_big_move" tag_small_move = "tag_small_move" tag_uninstalled = "tag_uninstalled" tag_open = "tag_open" hush = "hush" smoke = "smoke" tampered = "tampered" wifi_status = "wifi_status" battery_status = "battery_status" detection_chamber_status = "detection_chamber_status" sound_test = "sound_test" siren_sounding = "siren_sounding" siren_tampered = "siren_tampered" incoming_call = "incoming_call" accepted_call = "accepted_call" missed_call = "missed_call" co_detected = "co_detected" # pylint: enable=C0103 class VideoStatus(Enum): """Video states.""" # temporarily disable locally-disabled and locally-enabled # pylint: disable=C0103 available = "available" deleted = "deleted" # pylint: enable=C0103 @dataclass class Snapshot: """Class to represent a Netatmo event snapshot.""" snapshot_id: str version: int key: str url: str @dataclass class Event: """Class to represent a Netatmo events.""" entity_id: str event_type: EventTypes event_time: int message: str | None = None camera_id: str | None = None device_id: str | None = None person_id: str | None = None video_id: str | None = None sub_type: int | None = None snapshot: Snapshot | None = None vignette: Snapshot | None = None video_status: VideoStatus | None = None is_arrival: bool | None = None subevents: list[Event] | None = None def __init__(self, home_id: str, raw_data: RawData) -> None: """Initialize a Netatmo event instance.""" self.home_id = home_id self._init_attributes(raw_data) def _init_attributes(self, raw_data: RawData) -> None: """Initialize attributes of the instance.""" for attrib, value in raw_data.items(): if attrib == "subevents": value = [Event(self.home_id, event) for event in value] setattr(self, EVENT_ATTRIBUTES_MAP.get(attrib, attrib), value) jabesq-org-pyatmo-6216472/src/pyatmo/exceptions.py000066400000000000000000000015631466116727400221260ustar00rootroot00000000000000"""Exceptions for pyatmo.""" class NoSchedule(Exception): """Raised when no schedule is found.""" pass class InvalidSchedule(Exception): """Raised when an invalid schedule is encountered.""" pass class InvalidHome(Exception): """Raised when an invalid home is encountered.""" pass class InvalidRoom(Exception): """Raised when an invalid room is encountered.""" pass class NoDevice(Exception): """Raised when no device is found.""" pass class ApiError(Exception): """Raised when an API error is encountered.""" pass class ApiErrorThrottling(ApiError): """Raised when an API error is encountered.""" pass class ApiHomeReachabilityError(ApiError): """Raised when an API error is encountered.""" pass class InvalidState(Exception): """Raised when an invalid state is encountered.""" pass jabesq-org-pyatmo-6216472/src/pyatmo/helpers.py000066400000000000000000000030241466116727400214010ustar00rootroot00000000000000"""Collection of helper functions.""" from __future__ import annotations import logging from typing import Any, cast from pyatmo.const import RawData from pyatmo.exceptions import NoDevice LOG: logging.Logger = logging.getLogger(__name__) def fix_id(raw_data: RawData) -> dict[str, Any]: """Fix known errors in station ids like superfluous spaces.""" if not raw_data: return raw_data for station in raw_data: if not isinstance(station, dict): continue if station.get("_id") is None: continue station["_id"] = cast(dict, station)["_id"].replace(" ", "") for module in station.get("modules", {}): module["_id"] = module["_id"].replace(" ", "") return raw_data def extract_raw_data(resp: Any, tag: str) -> dict[str, Any]: """Extract raw data from server response.""" raw_data = {} if tag == "body": return {"public": resp["body"], "errors": []} if resp is None or "body" not in resp or tag not in resp["body"]: LOG.debug("Server response (tag: %s): %s", tag, resp) raise NoDevice("No device found, errors in response") if tag == "homes": return { tag: fix_id(resp["body"].get(tag)), "errors": resp["body"].get("errors", []), } if not (raw_data := fix_id(resp["body"].get(tag))): LOG.debug("Server response (tag: %s): %s", tag, resp) raise NoDevice("No device data available") return {tag: raw_data, "errors": resp["body"].get("errors", [])} jabesq-org-pyatmo-6216472/src/pyatmo/home.py000066400000000000000000000321061466116727400206720ustar00rootroot00000000000000"""Module to represent a Netatmo home.""" from __future__ import annotations import logging from typing import TYPE_CHECKING, Any from aiohttp import ClientResponse from pyatmo import modules from pyatmo.const import ( EVENTS, SCHEDULES, SETPERSONSAWAY_ENDPOINT, SETPERSONSHOME_ENDPOINT, SETSTATE_ENDPOINT, SETTHERMMODE_ENDPOINT, SWITCHHOMESCHEDULE_ENDPOINT, SYNCHOMESCHEDULE_ENDPOINT, RawData, ) from pyatmo.event import Event from pyatmo.exceptions import ( ApiHomeReachabilityError, InvalidSchedule, InvalidState, NoSchedule, ) from pyatmo.modules import Module from pyatmo.person import Person from pyatmo.room import Room from pyatmo.schedule import Schedule if TYPE_CHECKING: from pyatmo.auth import AbstractAsyncAuth LOG = logging.getLogger(__name__) class Home: """Class to represent a Netatmo home.""" auth: AbstractAsyncAuth entity_id: str name: str rooms: dict[str, Room] modules: dict[str, Module] schedules: dict[str, Schedule] persons: dict[str, Person] events: dict[str, Event] temperature_control_mode: str | None = None therm_mode: str | None = None therm_setpoint_default_duration: int | None = None cooling_mode: str | None = None def __init__(self, auth: AbstractAsyncAuth, raw_data: RawData) -> None: """Initialize a Netatmo home instance.""" self.auth = auth self.entity_id = raw_data["id"] self.name = raw_data.get("name", "Unknown") self.modules = { module["id"]: self.get_module(module) for module in raw_data.get("modules", []) } self.rooms = { room["id"]: Room( home=self, room=room, all_modules=self.modules, ) for room in raw_data.get("rooms", []) } self.schedules = { s["id"]: Schedule(home=self, raw_data=s) for s in raw_data.get(SCHEDULES, []) } self.persons = { s["id"]: Person(home=self, raw_data=s) for s in raw_data.get("persons", []) } self.events = {} self.temperature_control_mode = raw_data.get("temperature_control_mode") self.therm_mode = raw_data.get("therm_mode") self.therm_setpoint_default_duration = raw_data.get( "therm_setpoint_default_duration", ) self.cooling_mode = raw_data.get("cooling_mode") def get_module(self, module: dict) -> Module: """Return module.""" try: return getattr(modules, module["type"])( home=self, module=module, ) except AttributeError: LOG.info("Unknown device type %s", module["type"]) return getattr(modules, "NLunknown")( home=self, module=module, ) def update_topology(self, raw_data: RawData) -> None: """Update topology.""" self.name = raw_data.get("name", "Unknown") raw_modules = raw_data.get("modules", []) self.temperature_control_mode = raw_data.get("temperature_control_mode") self.therm_mode = raw_data.get("therm_mode") self.therm_setpoint_default_duration = raw_data.get( "therm_setpoint_default_duration", ) self.cooling_mode = raw_data.get("cooling_mode") for module in raw_modules: if (module_id := module["id"]) not in self.modules: self.modules[module_id] = self.get_module(module) else: self.modules[module_id].update_topology(module) # Drop module if has been removed for module in self.modules.keys() - {m["id"] for m in raw_modules}: self.modules.pop(module) raw_rooms = raw_data.get("rooms", []) for room in raw_rooms: if (room_id := room["id"]) not in self.rooms: self.rooms[room_id] = Room( home=self, room=room, all_modules=self.modules, ) else: self.rooms[room_id].update_topology(room) # Drop room if has been removed for room in self.rooms.keys() - {m["id"] for m in raw_rooms}: self.rooms.pop(room) self.schedules = { s["id"]: Schedule(home=self, raw_data=s) for s in raw_data.get(SCHEDULES, []) } async def update( self, raw_data: RawData, do_raise_for_reachability_error=False, ) -> None: """Update home with the latest data.""" has_error = False for module in raw_data.get("errors", []): has_error = True await self.modules[module["id"]].update({}) data = raw_data["home"] has_an_update = False for module in data.get("modules", []): has_an_update = True if module["id"] not in self.modules: self.update_topology({"modules": [module]}) await self.modules[module["id"]].update(module) for room in data.get("rooms", []): has_an_update = True self.rooms[room["id"]].update(room) for person_status in data.get("persons", []): if person := self.persons.get(person_status["id"]): person.update(person_status) self.events = { s["id"]: Event(home_id=self.entity_id, raw_data=s) for s in data.get(EVENTS, []) } if len(self.events) > 0: has_an_update = True has_one_module_reachable = False for module in self.modules.values(): if module.reachable: has_one_module_reachable = True if hasattr(module, "events"): setattr( module, "events", [ event for event in self.events.values() if getattr(event, "module_id") == module.entity_id ], ) if ( do_raise_for_reachability_error and has_error and has_one_module_reachable is False and has_an_update is False ): raise ApiHomeReachabilityError( "No Home update could be performed, all modules unreachable and not updated", ) def get_selected_schedule(self) -> Schedule | None: """Return selected schedule for given home.""" return next( (schedule for schedule in self.schedules.values() if schedule.selected), None, ) def is_valid_schedule(self, schedule_id: str) -> bool: """Check if valid schedule.""" return schedule_id in self.schedules def has_otm(self) -> bool: """Check if any room has an OTM device.""" return any("OTM" in room.device_types for room in self.rooms.values()) def has_bns(self) -> bool: """Check if any room has a BNS device.""" return any("BNS" in room.device_types for room in self.rooms.values()) def get_hg_temp(self) -> float | None: """Return frost guard temperature value for given home.""" if (schedule := self.get_selected_schedule()) is None: return None return schedule.hg_temp def get_away_temp(self) -> float | None: """Return configured away temperature value for given home.""" if (schedule := self.get_selected_schedule()) is None: return None return schedule.away_temp async def async_set_thermmode( self, mode: str, end_time: int | None = None, schedule_id: str | None = None, ) -> bool: """Set thermotat mode.""" if schedule_id is not None and not self.is_valid_schedule(schedule_id): raise NoSchedule(f"{schedule_id} is not a valid schedule id.") if mode is None: raise NoSchedule(f"{mode} is not a valid mode.") post_params = {"home_id": self.entity_id, "mode": mode} if end_time is not None and mode in {"hg", "away"}: post_params["endtime"] = str(end_time) if schedule_id is not None and mode == "schedule": post_params["schedule_id"] = schedule_id LOG.debug( "Setting home (%s) mode to %s (%s)", self.entity_id, mode, schedule_id, ) resp = await self.auth.async_post_api_request( endpoint=SETTHERMMODE_ENDPOINT, params=post_params, ) return (await resp.json()).get("status") == "ok" async def async_switch_schedule(self, schedule_id: str) -> bool: """Switch the schedule.""" if not self.is_valid_schedule(schedule_id): raise NoSchedule(f"{schedule_id} is not a valid schedule id") LOG.debug("Setting home (%s) schedule to %s", self.entity_id, schedule_id) resp = await self.auth.async_post_api_request( endpoint=SWITCHHOMESCHEDULE_ENDPOINT, params={"home_id": self.entity_id, "schedule_id": schedule_id}, ) return (await resp.json()).get("status") == "ok" async def async_set_state(self, data: dict[str, Any]) -> bool: """Set state using given data.""" if not is_valid_state(data): raise InvalidState("Data for '/set_state' contains errors.") LOG.debug("Setting state for home (%s) according to %s", self.entity_id, data) resp = await self.auth.async_post_api_request( endpoint=SETSTATE_ENDPOINT, params={"json": {"home": {"id": self.entity_id, **data}}}, ) return (await resp.json()).get("status") == "ok" async def async_set_persons_home( self, person_ids: list[str] | None = None, ) -> ClientResponse: """Mark persons as home.""" post_params: dict[str, Any] = {"home_id": self.entity_id} if person_ids: post_params["person_ids[]"] = person_ids return await self.auth.async_post_api_request( endpoint=SETPERSONSHOME_ENDPOINT, params=post_params, ) async def async_set_persons_away( self, person_id: str | None = None, ) -> ClientResponse: """Mark a person as away or set the whole home to being empty.""" post_params = {"home_id": self.entity_id} if person_id: post_params["person_id"] = person_id return await self.auth.async_post_api_request( endpoint=SETPERSONSAWAY_ENDPOINT, params=post_params, ) async def async_set_schedule_temperatures( self, zone_id: int, temps: dict[str, int], ) -> None: """Set the scheduled room temperature for the given schedule ID.""" selected_schedule = self.get_selected_schedule() if selected_schedule is None: raise NoSchedule("Could not determine selected schedule.") zones = [] timetable_entries = [ { "m_offset": timetable_entry.m_offset, "zone_id": timetable_entry.zone_id, } for timetable_entry in selected_schedule.timetable ] for zone in selected_schedule.zones: new_zone = { "id": zone.entity_id, "name": zone.name, "type": zone.type, "rooms": [], } for room in zone.rooms: temp = room.therm_setpoint_temperature if zone.entity_id == zone_id and room.entity_id in temps: temp = temps[room.entity_id] new_zone["rooms"].append( {"id": room.entity_id, "therm_setpoint_temperature": temp}, ) zones.append(new_zone) schedule = { "away_temp": selected_schedule.away_temp, "hg_temp": selected_schedule.hg_temp, "timetable": timetable_entries, "zones": zones, } await self.async_sync_schedule(selected_schedule.entity_id, schedule) async def async_sync_schedule( self, schedule_id: str, schedule: dict[str, Any], ) -> None: """Modify an existing schedule.""" if not is_valid_schedule(schedule): raise InvalidSchedule("Data for '/synchomeschedule' contains errors.") LOG.debug( "Setting schedule (%s) for home (%s) to %s", schedule_id, self.entity_id, schedule, ) resp = await self.auth.async_post_api_request( endpoint=SYNCHOMESCHEDULE_ENDPOINT, params={ "params": { "home_id": self.entity_id, "schedule_id": schedule_id, "name": "Default", }, "json": schedule, }, ) return (await resp.json()).get("status") == "ok" def is_valid_state(data: dict[str, Any]) -> bool: """Check set state data.""" return data is not None def is_valid_schedule(schedule: dict[str, Any]) -> bool: """Check schedule.""" return schedule is not None jabesq-org-pyatmo-6216472/src/pyatmo/modules/000077500000000000000000000000001466116727400210365ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/src/pyatmo/modules/__init__.py000066400000000000000000000040501466116727400231460ustar00rootroot00000000000000"""Expose submodules.""" from .base_class import Place from .bticino import ( BNAB, BNAS, BNCS, BNCX, BNDL, BNEU, BNFC, BNIL, BNLD, BNMH, BNMS, BNSL, BNTH, BNTR, BNXM, ) from .idiamant import NBG, NBO, NBR, NBS from .legrand import ( EBU, NLAO, NLAS, NLC, NLD, NLDD, NLE, NLF, NLFE, NLFN, NLG, NLIS, NLJ, NLL, NLLF, NLLM, NLLV, NLM, NLP, NLPBS, NLPC, NLPD, NLPM, NLPO, NLPS, NLPT, NLT, NLTS, NLUF, NLUI, NLUO, NLUP, NLV, Z3L, NLunknown, ) from .module import Camera, Dimmer, Fan, Module, Shutter, Switch from .netatmo import ( NCO, NDB, NHC, NIS, NOC, NRV, NSD, OTH, OTM, Location, NACamDoorTag, NACamera, NAMain, NAModule1, NAModule2, NAModule3, NAModule4, NAPlug, NATherm1, PublicWeatherArea, ) from .smarther import BNS from .somfy import TPSRS __all__ = [ "BNAB", "BNAS", "BNCS", "BNCX", "BNDL", "BNEU", "BNFC", "BNIL", "BNLD", "BNMH", "BNMS", "BNS", "BNSL", "BNTH", "BNTR", "BNXM", "Camera", "Dimmer", "EBU", "Fan", "Location", "Module", "NACamDoorTag", "NACamera", "NAMain", "NAModule1", "NAModule2", "NAModule3", "NAModule4", "NAPlug", "NATherm1", "NBG", "NBO", "NBR", "NBS", "NCO", "NDB", "NHC", "NIS", "NLAO", "NLAS", "NLC", "NLD", "NLDD", "NLE", "NLF", "NLFE", "NLFN", "NLG", "NLIS", "NLJ", "NLL", "NLLF", "NLLM", "NLLV", "NLM", "NLP", "NLPBS", "NLPC", "NLPD", "NLPM", "NLPO", "NLPS", "NLPT", "NLT", "NLTS", "NLUF", "NLUI", "NLunknown", "NLUO", "NLUP", "NLV", "NOC", "NRV", "NSD", "OTH", "OTM", "Place", "PublicWeatherArea", "Shutter", "Switch", "TPSRS", "Z3L", ] jabesq-org-pyatmo-6216472/src/pyatmo/modules/base_class.py000066400000000000000000000123231466116727400235100ustar00rootroot00000000000000"""Base class for Netatmo entities.""" from __future__ import annotations from abc import ABC import bisect from collections.abc import Iterable from dataclasses import dataclass import logging from operator import itemgetter from typing import TYPE_CHECKING, Any from pyatmo.const import MAX_HISTORY_TIME_FRAME, RawData from pyatmo.modules.device_types import DeviceType if TYPE_CHECKING: from pyatmo.event import EventTypes from pyatmo.home import Home from time import time LOG = logging.getLogger(__name__) NETATMO_ATTRIBUTES_MAP = { "entity_id": lambda x, y: x.get("id", y), "modules": lambda x, y: x.get("modules_bridged", y), "device_type": lambda x, y: DeviceType(x.get("type", y)), "event_type": lambda x, y: EventTypes(x.get("type", y)), "reachable": lambda x, _: x.get("reachable", False), "monitoring": lambda x, _: x.get("monitoring", False) == "on", "battery_level": lambda x, y: x.get("battery_vp", x.get("battery_level")), "place": lambda x, _: Place(x.get("place")), "target_position__step": lambda x, _: x.get("target_position:step"), } def default(key: str, val: Any) -> Any: """Return default value.""" return lambda x, _: x.get(key, val) def update_name(name: str, pre_fix: str) -> str: """Remove duplicates from string.""" if name.startswith(pre_fix): return name return f"{pre_fix} {name}" class EntityBase: """Base class for Netatmo entities.""" entity_id: str home: Home bridge: str | None history_features: set[str] history_features_values: dict[str, [int, int]] | {} name: str | None class NetatmoBase(EntityBase, ABC): """Base class for Netatmo entities.""" def __init__(self, raw_data: RawData) -> None: """Initialize a Netatmo entity.""" self.entity_id = raw_data["id"] self.name = raw_data.get("name", f"Unknown {self.entity_id}") self.history_features_values = {} self.history_features = set() def update_topology(self, raw_data: RawData) -> None: """Update topology.""" self._update_attributes(raw_data) if ( self.bridge and self.bridge in self.home.modules and getattr(self, "device_category") == "weather" ): self.name = update_name(self.name, self.home.modules[self.bridge].name) def _update_attributes(self, raw_data: RawData) -> None: """Update attributes.""" self.__dict__ = { key: NETATMO_ATTRIBUTES_MAP.get(key, default(key, val))(raw_data, val) for key, val in self.__dict__.items() } now = int(time()) for hist_feature in self.history_features: if hist_feature in self.__dict__: val = getattr(self, hist_feature) if val is None: continue self.add_history_data(hist_feature, val, now) def add_history_data(self, feature: str, value, time: int) -> None: """Add historical data at the given time.""" # get the feature values rolling buffer hist_f = self.history_features_values.setdefault(feature, []) if not hist_f or hist_f[-1][0] <= time: hist_f.append((time, value, self.entity_id)) else: i = bisect.bisect_left(hist_f, time, key=itemgetter(0)) if i < len(hist_f): if hist_f[i][0] == time: hist_f[i] = (time, value, self.entity_id) i = None if i is not None: hist_f.insert(i, (time, value, self.entity_id)) # keep timing history to a maximum representative time while len(hist_f) > 0 and hist_f[-1][0] - hist_f[0][0] > MAX_HISTORY_TIME_FRAME: hist_f.pop(0) def get_history_data(self, feature: str, from_ts: int, to_ts: int | None = None): """Retrieve historical data.""" hist_f = self.history_features_values.get(feature, []) if not hist_f: return [] in_s = bisect.bisect_left(hist_f, from_ts, key=itemgetter(0)) if to_ts is None: out_s = len(hist_f) else: out_s = bisect.bisect_right(hist_f, to_ts, key=itemgetter(0)) return hist_f[in_s:out_s] @dataclass class Location: """Class of Netatmo public weather location.""" latitude: float longitude: float def __init__(self, longitude: float, latitude: float) -> None: """Initialize self.""" self.latitude = latitude self.longitude = longitude def __iter__(self) -> Iterable[float]: """Iterate over latitude and longitude.""" yield self.longitude yield self.latitude @dataclass class Place: """Class of Netatmo public weather place.""" altitude: int | None city: str | None country: str | None timezone: str | None location: Location | None def __init__( self, data: dict[str, Any], ) -> None: """Initialize self.""" if data is None: return self.altitude = data.get("altitude") self.city = data.get("city") self.country = data.get("country") self.timezone = data.get("timezone") self.location = Location(*list(data.get("location", []))) jabesq-org-pyatmo-6216472/src/pyatmo/modules/bticino.py000066400000000000000000000022631466116727400230420ustar00rootroot00000000000000"""Module to represent BTicino modules.""" from __future__ import annotations import logging from pyatmo.modules.module import ( DimmableMixin, Module, Shutter, ShutterMixin, Switch, SwitchMixin, ) LOG = logging.getLogger(__name__) class BNDL(Module): """BTicino door lock.""" class BNSL(Switch): # pylint: disable=too-many-ancestors """BTicino staircase light.""" class BNCX(Module): """BTicino internal panel = gateway.""" class BNEU(Module): """BTicino external unit.""" class BNCS(Switch): """Bticino module Controlled Socket.""" class BNXM(Module): """BTicino X meter.""" class BNMS(Shutter): """BTicino motorized shade.""" class BNAS(ShutterMixin, Module): """BTicino automatic shutter.""" class BNAB(Shutter): """BTicino automatic blind.""" class BNMH(Module): """BTicino MyHome server.""" class BNTH(Module): """BTicino thermostat.""" class BNFC(Module): """BTicino fan coil.""" class BNTR(Module): """BTicino radiator thermostat.""" class BNIL(SwitchMixin, Module): """BTicino intelligent light.""" class BNLD(DimmableMixin, SwitchMixin, Module): """BTicino dimmer light.""" jabesq-org-pyatmo-6216472/src/pyatmo/modules/device_types.py000066400000000000000000000261051466116727400240770ustar00rootroot00000000000000"""Definitions of Netatmo devices types.""" from __future__ import annotations from enum import Enum import logging LOG = logging.getLogger(__name__) # pylint: disable=W0613 class DeviceType(str, Enum): """Class to represent Netatmo device types.""" # temporarily disable locally-disabled and locally-enabled # pylint: disable=C0103 # Climate/Energy NAPlug = "NAPlug" # Smart thermostat gateway NATherm1 = "NATherm1" # Smart thermostat NRV = "NRV" # Smart valve OTH = "OTH" # OpenTherm gateway OTM = "OTM" # OpenTherm modulating thermostat # Cameras/Security NACamDoorTag = "NACamDoorTag" # Smart Door and Window Sensors NACamera = "NACamera" # Smart Indoor Camera NCO = "NCO" # Smart Carbon Monoxide Alarm NDB = "NDB" # Smart Video Doorbell NIS = "NIS" # Smart Indoor Siren NOC = "NOC" # Smart Outdoor Camera (with Siren) NSD = "NSD" # Smart Smoke Detector # Weather NAMain = "NAMain" # Smart Home Weather Station NAModule1 = "NAModule1" NAModule2 = "NAModule2" NAModule3 = "NAModule3" NAModule4 = "NAModule4" public = "public" # Home Coach NHC = "NHC" # Smart Indoor Air Quality Monitor # Legrand Wiring devices and electrical panel products NLC = "NLC" # Cable outlet NLD = "NLD" # Dimmer NLDD = "NLDD" # Dimmer NLE = "NLE" # Connected Ecometer NLF = "NLF" # Dimmer Light Switch NLFE = "NLFE" # Dimmer Light Switch Evolution NLFN = "NLFN" # light switch with neutral NLG = "NLG" # Gateway NLGS = "NLGS" # Gateway standalone NLIS = "NLIS" # Double light switch NLL = "NLL" # Italian light switch with neutral NLLM = "NLLM" # Legrand / BTicino shutters NLLV = "NLLV" # Legrand / BTicino shutters NLM = "NLM" # light micro module NLP = "NLP" # Plug NLPBS = "NLPBS" # British standard plugs NLPC = "NLPC" # Connected energy meter NLPD = "NLPD" # Dry contact NLPM = "NLPM" # mobile plug NLPO = "NLPO" # Connected contactor NLPS = "NLPS" # Smart Load Shedder NLPT = "NLPT" # Connected latching relay / Telerupt NLT = "NLT" # Global remote control NLV = "NLV" # Legrand / BTicino shutters NLAO = "NLAO" # Legrand wireless batteryless light switch NLUO = "NLUO" # Legrand Plug-In dimmer switch NLUI = "NLUI" # Legrand In-Wall ON/OFF switch NLunknown = "NLunknown" # Legrand device stub NLUF = "NLUF" # Legrand device stub NLAS = "NLAS" # Legrand wireless batteryless scene switch NLUP = "NLUP" # Legrand device stub NLLF = "NLLF" # Legrand Centralized Ventilation Control NLTS = "NLTS" # Legrand motion sensor stub NLJ = "NLJ" # Legrand garage door opener # BTicino Classe 300 EOS BNCX = "BNCX" # internal panel = gateway BNDL = "BNDL" # door lock BNEU = "BNEU" # external unit BNSL = "BNSL" # staircase light BNCS = "BNCS" # Controlled Socket BNXM = "BNXM" # X meter BNMS = "BNMS" # motorized shade BNAS = "BNAS" # automatic shutter BNAB = "BNAB" # automatic blind BNMH = "BNMH" # MyHome server BNTH = "BNTH" # thermostat BNFC = "BNFC" # fan coil BNTR = "BNTR" # radiator BNIL = "BNIL" # intelligent light BNLD = "BNLD" # dimmer light # Bubbendorf shutters NBG = "NBG" # gateway NBO = "NBO" # orientable shutter NBR = "NBR" # roller shutter NBS = "NBS" # swing shutter # Somfy TPSRS = "TPSRS" # Somfy io shutter # 3rd Party BNS = "BNS" # Smarther with Netatmo EBU = "EBU" # EBU gas meter Z3L = "Z3L" # Zigbee 3 Light # Magellan NLDP = "NLDP" # Pocket Remote # pylint: enable=C0103 @classmethod def _missing_(cls, key): """Handle unknown device types.""" msg = f"{key} device is unknown" LOG.warning(msg) return DeviceType.NLunknown class DeviceCategory(str, Enum): """Class to represent Netatmo device types.""" # temporarily disable locally-disabled and locally-enabled # pylint: disable=C0103 climate = "climate" camera = "camera" siren = "siren" shutter = "shutter" lock = "lock" switch = "switch" sensor = "sensor" weather = "weather" air_care = "air_care" meter = "meter" dimmer = "dimmer" opening = "opening" fan = "fan" # pylint: enable=C0103 DEVICE_CATEGORY_MAP: dict[DeviceType, DeviceCategory] = { DeviceType.NRV: DeviceCategory.climate, DeviceType.NATherm1: DeviceCategory.climate, DeviceType.OTM: DeviceCategory.climate, DeviceType.NOC: DeviceCategory.camera, DeviceType.NACamDoorTag: DeviceCategory.opening, DeviceType.NACamera: DeviceCategory.camera, DeviceType.NDB: DeviceCategory.camera, DeviceType.NAMain: DeviceCategory.weather, DeviceType.NAModule1: DeviceCategory.weather, DeviceType.NAModule2: DeviceCategory.weather, DeviceType.NAModule3: DeviceCategory.weather, DeviceType.NAModule4: DeviceCategory.weather, DeviceType.NHC: DeviceCategory.air_care, DeviceType.NLV: DeviceCategory.shutter, DeviceType.NLLV: DeviceCategory.shutter, DeviceType.NLLM: DeviceCategory.shutter, DeviceType.NBR: DeviceCategory.shutter, DeviceType.NBO: DeviceCategory.shutter, DeviceType.NLP: DeviceCategory.switch, DeviceType.NLPM: DeviceCategory.switch, DeviceType.NLPBS: DeviceCategory.switch, DeviceType.NLIS: DeviceCategory.switch, DeviceType.NLL: DeviceCategory.switch, DeviceType.NLM: DeviceCategory.switch, DeviceType.NLC: DeviceCategory.switch, DeviceType.NLFN: DeviceCategory.dimmer, DeviceType.NLF: DeviceCategory.dimmer, DeviceType.NLFE: DeviceCategory.dimmer, DeviceType.BNS: DeviceCategory.climate, DeviceType.NLPC: DeviceCategory.meter, DeviceType.NLE: DeviceCategory.meter, DeviceType.Z3L: DeviceCategory.dimmer, DeviceType.NLUP: DeviceCategory.switch, DeviceType.NLPO: DeviceCategory.switch, DeviceType.TPSRS: DeviceCategory.shutter, DeviceType.NLUO: DeviceCategory.dimmer, DeviceType.NLUI: DeviceCategory.switch, DeviceType.NLUF: DeviceCategory.dimmer, DeviceType.NLPS: DeviceCategory.meter, DeviceType.NLD: DeviceCategory.switch, DeviceType.NLDD: DeviceCategory.switch, DeviceType.NLPT: DeviceCategory.switch, DeviceType.BNMS: DeviceCategory.shutter, DeviceType.BNAS: DeviceCategory.shutter, DeviceType.BNAB: DeviceCategory.shutter, DeviceType.BNTH: DeviceCategory.climate, DeviceType.BNFC: DeviceCategory.climate, DeviceType.BNTR: DeviceCategory.climate, DeviceType.NLPD: DeviceCategory.switch, DeviceType.NLJ: DeviceCategory.shutter, DeviceType.BNIL: DeviceCategory.switch, DeviceType.BNLD: DeviceCategory.dimmer, DeviceType.NIS: DeviceCategory.siren, DeviceType.BNCS: DeviceCategory.switch, DeviceType.NLLF: DeviceCategory.fan, } DEVICE_DESCRIPTION_MAP: dict[DeviceType, tuple[str, str]] = { # Netatmo Climate/Energy DeviceType.NAPlug: ("Netatmo", "Smart Thermostat Gateway"), DeviceType.NATherm1: ("Netatmo", "Smart Thermostat"), DeviceType.NRV: ("Netatmo", "Smart Valve"), DeviceType.OTH: ("Netatmo", "OpenTherm Gateway"), DeviceType.OTM: ("Netatmo", "OpenTherm Modulating Thermostat"), # Netatmo Cameras/Security DeviceType.NOC: ("Netatmo", "Smart Outdoor Camera"), DeviceType.NACamera: ("Netatmo", "Smart Indoor Camera"), DeviceType.NSD: ("Netatmo", "Smart Smoke Detector"), DeviceType.NIS: ("Netatmo", "Smart Indoor Siren"), DeviceType.NACamDoorTag: ("Netatmo", "Smart Door/Window Sensors"), DeviceType.NDB: ("Netatmo", "Smart Video Doorbell"), DeviceType.NCO: ("Netatmo", "Smart Carbon Monoxide Alarm"), # Netatmo Weather DeviceType.NAMain: ("Netatmo", "Smart Home Weather station"), DeviceType.NAModule1: ("Netatmo", "Smart Outdoor Module"), DeviceType.NAModule2: ("Netatmo", "Smart Anemometer"), DeviceType.NAModule3: ("Netatmo", "Smart Rain Gauge"), DeviceType.NAModule4: ("Netatmo", "Smart Indoor Module"), DeviceType.public: ("Netatmo", "Public Weather station"), # Netatmo Home Coach DeviceType.NHC: ("Netatmo", "Smart Indoor Air Quality Monitor"), # Legrand Wiring devices and electrical panel products DeviceType.NLG: ("Legrand", "Gateway"), DeviceType.NLGS: ("Legrand", "Gateway standalone"), DeviceType.NLP: ("Legrand", "Plug"), DeviceType.NLPM: ("Legrand", "Mobile plug"), DeviceType.NLPBS: ("Legrand", "British standard plugs"), DeviceType.NLF: ("Legrand", "2 wire light switch/dimmer"), DeviceType.NLFE: ("Legrand", "2 wire light switch/dimmer evolution"), DeviceType.NLIS: ("Legrand", "Double switch"), DeviceType.NLFN: ("Legrand", "Light switch/dimmer with neutral"), DeviceType.NLM: ("Legrand", "Light micro module"), DeviceType.NLL: ("Legrand", "Italian light switch with neutral"), DeviceType.NLLF: ("Legrand", "Centralized ventilation device"), DeviceType.NLV: ("Legrand/BTicino", "Shutters"), DeviceType.NLLV: ("Legrand/BTicino", "Shutters"), DeviceType.NLLM: ("Legrand/BTicino", "Shutters"), DeviceType.NLPO: ("Legrand", "Connected Contactor"), DeviceType.NLPT: ("Legrand", "Connected Latching Relay"), DeviceType.NLPC: ("Legrand", "Connected Energy Meter"), DeviceType.NLE: ("Legrand", "Connected Ecometer"), DeviceType.NLPS: ("Legrand", "Smart Load Shedder"), DeviceType.NLC: ("Legrand", "Cable Outlet"), DeviceType.NLT: ("Legrand", "Global Remote Control"), DeviceType.NLAS: ("Legrand", "Wireless batteryless scene switch"), DeviceType.NLD: ("Legrand", "Dimmer"), DeviceType.NLDD: ("Legrand", "Dimmer"), DeviceType.NLUP: ("Legrand", "Power outlet"), DeviceType.NLUO: ("Legrand", "Plug-In dimmer switch"), DeviceType.NLUI: ("Legrand", "In-wall switch"), DeviceType.NLTS: ("Legrand", "Motion sensor"), DeviceType.NLUF: ("Legrand", "In-Wall dimmer"), DeviceType.NLJ: ("Legrand", "Garage door opener"), # BTicino Classe 300 EOS DeviceType.BNCX: ("BTicino", "Internal Panel"), DeviceType.BNEU: ("BTicino", "External Unit"), DeviceType.BNDL: ("BTicino", "Door Lock"), DeviceType.BNSL: ("BTicino", "Staircase Light"), DeviceType.BNMS: ("BTicino", "Motorized Shade"), DeviceType.BNAS: ("BTicino", "Automatic Shutter"), DeviceType.BNAB: ("BTicino", "Automatic Blind"), DeviceType.BNMH: ("BTicino", "MyHome server 1"), DeviceType.BNTH: ("BTicino", "Thermostat"), DeviceType.BNFC: ("BTicino", "Fan coil"), DeviceType.BNTR: ("BTicino", "Module towel rail"), DeviceType.BNIL: ("BTicino", "Intelligent light"), DeviceType.BNLD: ("BTicino", "Dimmer"), DeviceType.BNCS: ("BTicino", "Controlled socket"), # Bubbendorf shutters DeviceType.NBG: ("Bubbendorf", "Gateway"), DeviceType.NBR: ("Bubbendorf", "Roller Shutter"), DeviceType.NBO: ("Bubbendorf", "Orientable Shutter"), DeviceType.NBS: ("Bubbendorf", "Swing Shutter"), # Somfy DeviceType.TPSRS: ("Somfy", "io Shutter"), # 3rd Party DeviceType.BNS: ("Smarther", "Smarther with Netatmo"), DeviceType.Z3L: ("3rd Party", "Zigbee 3 Light"), DeviceType.EBU: ("3rd Party", "EBU gas meter"), DeviceType.NLPD: ("Drivia", "Dry contact"), } jabesq-org-pyatmo-6216472/src/pyatmo/modules/idiamant.py000066400000000000000000000012571466116727400232030ustar00rootroot00000000000000"""Module to represent iDiamant modules.""" from __future__ import annotations import logging from pyatmo.modules.module import ( FirmwareMixin, Module, RfMixin, ShutterMixin, WifiMixin, ) LOG = logging.getLogger(__name__) class NBG(FirmwareMixin, WifiMixin, Module): """Class to represent a iDiamant NBG.""" ... class NBR(FirmwareMixin, RfMixin, ShutterMixin, Module): """Class to represent a iDiamant NBR.""" ... class NBO(FirmwareMixin, RfMixin, ShutterMixin, Module): """Class to represent a iDiamant NBO.""" ... class NBS(FirmwareMixin, RfMixin, ShutterMixin, Module): """Class to represent a iDiamant NBS.""" ... jabesq-org-pyatmo-6216472/src/pyatmo/modules/legrand.py000066400000000000000000000064741466116727400230370ustar00rootroot00000000000000"""Module to represent Legrand modules.""" from __future__ import annotations import logging from pyatmo.modules.module import ( BatteryMixin, ContactorMixin, DimmableMixin, Dimmer, EnergyHistoryLegacyMixin, EnergyHistoryMixin, Fan, FirmwareMixin, Module, OffloadMixin, PowerMixin, RfMixin, ShutterMixin, Switch, SwitchMixin, WifiMixin, ) LOG = logging.getLogger(__name__) # pylint: disable=R0901 class NLG(FirmwareMixin, OffloadMixin, WifiMixin, Module): """Legrand gateway.""" class NLT(DimmableMixin, FirmwareMixin, BatteryMixin, SwitchMixin, Module): """Legrand global remote control...but also wireless switch, like NLD.""" class NLP(Switch, OffloadMixin): """Legrand plug.""" class NLPM(Switch, OffloadMixin): """Legrand mobile plug.""" class NLPO(ContactorMixin, OffloadMixin, Switch): """Legrand contactor.""" class NLPT(Switch, OffloadMixin): """Legrand latching relay/teleruptor.""" class NLPBS(Switch): """Legrand british standard plug.""" class NLF(Dimmer): """Legrand 2 wire light switch.""" class NLFN(Dimmer): """Legrand light switch with neutral.""" class NLFE(Dimmer): """Legrand On-Off dimmer switch evolution.""" class NLM(Switch): """Legrand light micro module.""" class NLIS(Switch): """Legrand double switch.""" class NLD(DimmableMixin, FirmwareMixin, BatteryMixin, SwitchMixin, Module): """Legrand Double On/Off dimmer remote. Wireless 2 button switch light.""" class NLL(Switch, WifiMixin): """Legrand / BTicino italian light switch with neutral.""" class NLV(FirmwareMixin, RfMixin, ShutterMixin, Module): """Legrand / BTicino shutters.""" class NLLV(FirmwareMixin, RfMixin, ShutterMixin, Module): """Legrand / BTicino shutters.""" class NLLM(FirmwareMixin, RfMixin, ShutterMixin, Module): """Legrand / BTicino shutters.""" class NLPC(FirmwareMixin, EnergyHistoryMixin, PowerMixin, Module): """Legrand / BTicino connected energy meter.""" class NLE(FirmwareMixin, EnergyHistoryLegacyMixin, Module): """Legrand / BTicino connected ecometer. no power supported for the NLE (in the home status API).""" class NLPS(FirmwareMixin, EnergyHistoryMixin, PowerMixin, Module): """Legrand / BTicino smart load shedder.""" class NLC(Switch, OffloadMixin): """Legrand / BTicino cable outlet.""" class NLDD(FirmwareMixin, Module): """Legrand NLDD dimmer remote control.""" class NLUP(Switch): """Legrand NLUP Power outlet.""" class NLAO(FirmwareMixin, SwitchMixin, Module): """Legrand wireless batteryless light switch.""" class NLUI(FirmwareMixin, SwitchMixin, Module): """Legrand NLUI in-wall switch.""" class NLUF(Dimmer): """Legrand NLUF device stub.""" class NLUO(Dimmer): """Legrand NLUO device stub.""" class NLLF(Fan, PowerMixin, EnergyHistoryMixin): """Legrand NLLF fan/ventilation device.""" class NLunknown(Module): """NLunknown device stub.""" class NLAS(Module): """NLAS wireless batteryless scene switch.""" class Z3L(Dimmer): """Zigbee 3 Light.""" class EBU(Module): """EBU gas meter.""" class NLTS(Module): """NLTS motion sensor.""" class NLPD(Switch, OffloadMixin): """NLPD dry contact.""" class NLJ(FirmwareMixin, RfMixin, ShutterMixin, Module): """Legrand garage door opener.""" jabesq-org-pyatmo-6216472/src/pyatmo/modules/module.py000066400000000000000000001051211466116727400226750ustar00rootroot00000000000000"""Module to represent a Netatmo module.""" from __future__ import annotations from datetime import datetime, timedelta, timezone from enum import Enum import logging from typing import TYPE_CHECKING, Any from aiohttp import ClientConnectorError from pyatmo.const import GETMEASURE_ENDPOINT, RawData from pyatmo.exceptions import ApiError from pyatmo.modules.base_class import EntityBase, NetatmoBase, Place from pyatmo.modules.device_types import DEVICE_CATEGORY_MAP, DeviceCategory, DeviceType if TYPE_CHECKING: from pyatmo.event import Event from pyatmo.home import Home from operator import itemgetter from time import time LOG = logging.getLogger(__name__) ModuleT = dict[str, Any] # Hide from features list ATTRIBUTE_FILTER = { "battery_state", "battery_level", "battery_percent", "date_min_temp", "date_max_temp", "name", "entity_id", "device_id", "modules", "firmware_revision", "firmware_name", "home", "bridge", "room_id", "device_category", "device_type", "features", "history_features", "history_features_values", } def process_battery_state(data: str) -> int: """Process battery data and return percent (int) for display.""" mapping = { "max": 100, "full": 90, "high": 75, "medium": 50, "low": 25, "very_low": 10, } return mapping[data] class FirmwareMixin(EntityBase): """Mixin for firmware data.""" def __init__(self, home: Home, module: ModuleT): """Initialize firmware mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.firmware_revision: int | None = None self.firmware_name: str | None = None class WifiMixin(EntityBase): """Mixin for wifi data.""" def __init__(self, home: Home, module: ModuleT): """Initialize wifi mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.wifi_strength: int | None = None class RfMixin(EntityBase): """Mixin for rf data.""" def __init__(self, home: Home, module: ModuleT): """Initialize rf mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.rf_strength: int | None = None class RainMixin(EntityBase): """Mixin for rain data.""" def __init__(self, home: Home, module: ModuleT): """Initialize rain mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.rain: float | None = None self.sum_rain_1: float | None = None self.sum_rain_24: float | None = None class WindMixin(EntityBase): """Mixin for wind data.""" def __init__(self, home: Home, module: ModuleT): """Initialize wind mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.wind_strength: int | None = None self.wind_angle: int | None = None self.gust_strength: int | None = None self.gust_angle: int | None = None @property def wind_direction(self) -> str | None: """Return wind direction.""" return None if self.wind_angle is None else process_angle(self.wind_angle) @property def gust_direction(self) -> str | None: """Return gust direction.""" return None if self.gust_angle is None else process_angle(self.gust_angle) def process_angle(angle: int) -> str: """Process angle and return string for display.""" if angle >= 330: return "N" if angle >= 300: return "NW" if angle >= 240: return "W" if angle >= 210: return "SW" if angle >= 150: return "S" if angle >= 120: return "SE" if angle >= 60: return "E" return "NE" if angle >= 30 else "N" class TemperatureMixin(EntityBase): """Mixin for temperature data.""" def __init__(self, home: Home, module: ModuleT): """Initialize temperature mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.temperature: float | None = None self.temp_min: float | None = None self.temp_max: float | None = None self.temp_trend: str | None = None self.min_temp: float | None = None self.max_temp: float | None = None self.date_min_temp: int | None = None self.date_max_temp: int | None = None class HumidityMixin(EntityBase): """Mixin for humidity data.""" def __init__(self, home: Home, module: ModuleT): """Initialize humidity mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.humidity: int | None = None class CO2Mixin(EntityBase): """Mixin for CO2 data.""" def __init__(self, home: Home, module: ModuleT): """Initialize CO2 mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.co2: int | None = None class HealthIndexMixin(EntityBase): """Mixin for health index data.""" def __init__(self, home: Home, module: ModuleT): """Initialize health index mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.health_idx: int | None = None class NoiseMixin(EntityBase): """Mixin for noise data.""" def __init__(self, home: Home, module: ModuleT): """Initialize noise mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.noise: int | None = None class PressureMixin(EntityBase): """Mixin for pressure data.""" def __init__(self, home: Home, module: ModuleT): """Initialize pressure mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.pressure: float | None = None self.absolute_pressure: float | None = None self.pressure_trend: str | None = None class BoilerMixin(EntityBase): """Mixin for boiler data.""" def __init__(self, home: Home, module: ModuleT): """Initialize boiler mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.boiler_status: bool | None = None class CoolerMixin(EntityBase): """Mixin for cooler data.""" def __init__(self, home: Home, module: ModuleT): """Initialize cooler mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.cooler_status: bool | None = None class BatteryMixin(EntityBase): """Mixin for battery data.""" def __init__(self, home: Home, module: ModuleT): """Initialize battery mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.battery_state: str | None = None self.battery_level: int | None = None self.battery_percent: int | None = None @property def battery(self) -> int: """Return battery percent.""" if self.battery_percent is not None: return self.battery_percent if self.battery_state is None: return 0 return process_battery_state(self.battery_state) class PlaceMixin(EntityBase): """Mixin for place data.""" def __init__(self, home: Home, module: ModuleT): """Initialize place mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.place: Place | None = None class DimmableMixin(EntityBase): """Mixin for dimmable data.""" def __init__(self, home: Home, module: ModuleT): """Initialize dimmable mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.brightness: int | None = None async def async_set_brightness(self, brightness: int) -> bool: """Set brightness.""" json_brightness = { "modules": [ { "id": self.entity_id, "brightness": max(min(100, brightness), -1), "bridge": self.bridge, }, ], } return await self.home.async_set_state(json_brightness) class ApplianceTypeMixin(EntityBase): """Mixin for appliance type data.""" def __init__(self, home: Home, module: ModuleT): """Initialize appliance type mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.appliance_type: str | None = None class PowerMixin(EntityBase): """Mixin for power data.""" def __init__(self, home: Home, module: ModuleT): """Initialize power mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.power: int | None = None self.history_features.add("power") class EventMixin(EntityBase): """Mixin for event data.""" def __init__(self, home: Home, module: ModuleT): """Initialize event mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.events: list[Event] = [] class ContactorMixin(EntityBase): """Mixin for contactor data.""" def __init__(self, home: Home, module: ModuleT): """Initialize contactor mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.contactor_mode: str | None = None class OffloadMixin(EntityBase): """Mixin for offload data.""" def __init__(self, home: Home, module: ModuleT): """Initialize offload mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.offload: bool | None = None class SwitchMixin(EntityBase): """Mixin for switch data.""" def __init__(self, home: Home, module: ModuleT): """Initialize switch mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.on: bool | None = None async def async_set_switch(self, target_position: int) -> bool: """Set switch to target position.""" json_switch = { "modules": [ { "id": self.entity_id, "on": target_position, "bridge": self.bridge, }, ], } return await self.home.async_set_state(json_switch) async def async_on(self) -> bool: """Switch on.""" return await self.async_set_switch(True) async def async_off(self) -> bool: """Switch off.""" return await self.async_set_switch(False) class FanSpeedMixin(EntityBase): """Mixin for fan speed data.""" def __init__(self, home: Home, module: ModuleT): """Initialize fan speed mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.fan_speed: int | None = None async def async_set_fan_speed(self, speed: int) -> bool: """Set fan speed.""" json_fan_speed = { "modules": [ { "id": self.entity_id, # fan speed is clamped between 1 and 2 # since only NLLF is such a device # and it can only supports fan_speed 1 or 2 "fan_speed": max(min(2, speed), 1), "bridge": self.bridge, }, ], } return await self.home.async_set_state(json_fan_speed) class ShutterMixin(EntityBase): """Mixin for shutter data.""" __open_position = 100 __close_position = 0 __stop_position = -1 __preferred_position = -2 def __init__(self, home: Home, module: ModuleT): """Initialize shutter mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.current_position: int | None = None self.target_position: int | None = None self.target_position__step: int | None = None async def async_set_target_position(self, target_position: int) -> bool: """Set shutter to target position.""" # in case of a too low value, we default to stop and not the preferred position # We check against __preferred_position that is the lower known value if target_position < self.__preferred_position: target_position = self.__stop_position json_roller_shutter = { "modules": [ { "id": self.entity_id, "target_position": min(self.__open_position, target_position), "bridge": self.bridge, }, ], } return await self.home.async_set_state(json_roller_shutter) async def async_open(self) -> bool: """Open shutter.""" return await self.async_set_target_position(self.__open_position) async def async_close(self) -> bool: """Close shutter.""" return await self.async_set_target_position(self.__close_position) async def async_stop(self) -> bool: """Stop shutter.""" return await self.async_set_target_position(self.__stop_position) async def async_move_to_preferred_position(self) -> bool: """Move shutter to preferred position.""" return await self.async_set_target_position(self.__preferred_position) class CameraMixin(EntityBase): """Mixin for camera data.""" def __init__(self, home: Home, module: ModuleT): """Initialize camera mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.sd_status: int | None = None self.vpn_url: str | None = None self.local_url: str | None = None self.is_local: bool | None = None self.alim_status: int | None = None self.device_type: DeviceType async def async_get_live_snapshot(self) -> bytes | None: """Fetch live camera image.""" if not self.local_url and not self.vpn_url: return None resp = await self.home.auth.async_get_image( base_url=f"{self.local_url or self.vpn_url}", endpoint="/live/snapshot_720.jpg", timeout=10, ) return resp if isinstance(resp, bytes) else None async def async_update_camera_urls(self) -> None: """Update and validate the camera urls.""" if self.device_type == "NDB": self.is_local = None if self.vpn_url and self.is_local: temp_local_url = await self._async_check_url(self.vpn_url) if temp_local_url: try: self.local_url = await self._async_check_url( temp_local_url, ) except ClientConnectorError as exc: LOG.debug("Cannot connect to %s - reason: %s", temp_local_url, exc) self.is_local = False self.local_url = None async def _async_check_url(self, url: str) -> str | None: """Validate camera url.""" try: resp = await self.home.auth.async_post_api_request( base_url=f"{url}", endpoint="/command/ping", ) except ApiError: LOG.debug("Api error for camera url %s", url) return None assert not isinstance(resp, bytes) resp_data = await resp.json() return resp_data.get("local_url") if resp_data else None class FloodlightMixin(EntityBase): """Mixin for floodlight data.""" def __init__(self, home: Home, module: ModuleT): """Initialize floodlight mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.floodlight: str | None = None async def async_set_floodlight_state(self, state: str) -> bool: """Set floodlight state.""" json_floodlight_state = { "modules": [ { "id": self.entity_id, "floodlight": state, }, ], } return await self.home.async_set_state(json_floodlight_state) async def async_floodlight_on(self) -> bool: """Turn on floodlight.""" return await self.async_set_floodlight_state("on") async def async_floodlight_off(self) -> bool: """Turn off floodlight.""" return await self.async_set_floodlight_state("off") async def async_floodlight_auto(self) -> bool: """Set floodlight to auto mode.""" return await self.async_set_floodlight_state("auto") class StatusMixin(EntityBase): """Mixin for status data.""" def __init__(self, home: Home, module: ModuleT): """Initialize status mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.status: str | None = None class MonitoringMixin(EntityBase): """Mixin for monitoring data.""" def __init__(self, home: Home, module: ModuleT): """Initialize monitoring mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.monitoring: bool | None = None async def async_set_monitoring_state(self, state: str) -> bool: """Set monitoring state.""" json_monitoring_state = { "modules": [ { "id": self.entity_id, "monitoring": state, }, ], } return await self.home.async_set_state(json_monitoring_state) async def async_monitoring_on(self) -> bool: """Turn on monitoring.""" return await self.async_set_monitoring_state("on") async def async_monitoring_off(self) -> bool: """Turn off monitoring.""" return await self.async_set_monitoring_state("off") class MeasureInterval(Enum): """Measure interval.""" HALF_HOUR = "30min" HOUR = "1hour" THREE_HOURS = "3hours" DAY = "1day" WEEK = "1week" MONTH = "1month" class MeasureType(Enum): """Measure type.""" BOILERON = "boileron" BOILEROFF = "boileroff" SUM_BOILER_ON = "sum_boiler_on" SUM_BOILER_OFF = "sum_boiler_off" SUM_ENERGY_ELEC = "sum_energy_buy_from_grid" SUM_ENERGY_ELEC_BASIC = "sum_energy_buy_from_grid$0" SUM_ENERGY_ELEC_PEAK = "sum_energy_buy_from_grid$1" SUM_ENERGY_ELEC_OFF_PEAK = "sum_energy_buy_from_grid$2" SUM_ENERGY_PRICE = "sum_energy_buy_from_grid_price" SUM_ENERGY_PRICE_BASIC = "sum_energy_buy_from_grid_price$0" SUM_ENERGY_PRICE_PEAK = "sum_energy_buy_from_grid_price$1" SUM_ENERGY_PRICE_OFF_PEAK = "sum_energy_buy_from_grid_price$2" SUM_ENERGY_ELEC_LEGACY = "sum_energy_elec" SUM_ENERGY_ELEC_BASIC_LEGACY = "sum_energy_elec$0" SUM_ENERGY_ELEC_PEAK_LEGACY = "sum_energy_elec$1" SUM_ENERGY_ELEC_OFF_PEAK_LEGACY = "sum_energy_elec$2" MEASURE_INTERVAL_TO_SECONDS = { MeasureInterval.HALF_HOUR: 1800, MeasureInterval.HOUR: 3600, MeasureInterval.THREE_HOURS: 10800, MeasureInterval.DAY: 86400, MeasureInterval.WEEK: 604800, MeasureInterval.MONTH: 2592000, } ENERGY_FILTERS = f"{MeasureType.SUM_ENERGY_ELEC.value},{MeasureType.SUM_ENERGY_ELEC_BASIC.value},{MeasureType.SUM_ENERGY_ELEC_PEAK.value},{MeasureType.SUM_ENERGY_ELEC_OFF_PEAK.value}" ENERGY_FILTERS_LEGACY = f"{MeasureType.SUM_ENERGY_ELEC_LEGACY.value},{MeasureType.SUM_ENERGY_ELEC_BASIC_LEGACY.value},{MeasureType.SUM_ENERGY_ELEC_PEAK_LEGACY.value},{MeasureType.SUM_ENERGY_ELEC_OFF_PEAK_LEGACY.value}" ENERGY_FILTERS_MODES = ["generic", "basic", "peak", "off_peak"] def compute_riemann_sum( power_data: list[tuple[int, float]], conservative: bool = False ): """Compute energy from power with a rieman sum.""" delta_energy = 0 if power_data and len(power_data) > 1: # compute a rieman sum, as best as possible , trapezoidal, taking pessimistic asumption # as we don't want to artifically go up the previous one # (except in rare exceptions like reset, 0 , etc) for i in range(len(power_data) - 1): dt_h = float(power_data[i + 1][0] - power_data[i][0]) / 3600.0 if conservative: d_p_w = 0 else: d_p_w = abs(float(power_data[i + 1][1] - power_data[i][1])) d_nrj_wh = dt_h * ( min(power_data[i + 1][1], power_data[i][1]) + 0.5 * d_p_w ) delta_energy += d_nrj_wh return delta_energy class EnergyHistoryMixin(EntityBase): """Mixin for Energy history data.""" def __init__(self, home: Home, module: ModuleT): """Initialize history mixin.""" super().__init__(home, module) # type: ignore # mypy issue 4335 self.historical_data: list[dict[str, Any]] | None = None self.start_time: int | None = None self.end_time: int | None = None self.interval: MeasureInterval | None = None self.sum_energy_elec: int | None = None self.sum_energy_elec_peak: int | None = None self.sum_energy_elec_off_peak: int | None = None self._anchor_for_power_adjustment: int | None = None self.in_reset: bool | False = False def reset_measures(self, start_power_time, in_reset=True): """Reset energy measures.""" self.in_reset = in_reset self.historical_data = [] if start_power_time is None: self._anchor_for_power_adjustment = start_power_time else: self._anchor_for_power_adjustment = int(start_power_time.timestamp()) self.sum_energy_elec = 0 self.sum_energy_elec_peak = 0 self.sum_energy_elec_off_peak = 0 def get_sum_energy_elec_power_adapted( self, to_ts: int | float | None = None, conservative: bool = False ): """Compute proper energy value with adaptation from power.""" v = self.sum_energy_elec if v is None: return None, 0 delta_energy = 0 if not self.in_reset: if to_ts is None: to_ts = int(time()) from_ts = self._anchor_for_power_adjustment if ( from_ts is not None and from_ts < to_ts and isinstance(self, PowerMixin) and isinstance(self, NetatmoBase) ): power_data = self.get_history_data( "power", from_ts=from_ts, to_ts=to_ts ) if isinstance( self, EnergyHistoryMixin ): # well to please the linter.... delta_energy = compute_riemann_sum(power_data, conservative) return v, delta_energy def _log_energy_error(self, start_time, end_time, msg=None, body=None): if body is None: body = "NO BODY" LOG.debug( "ENERGY collection error %s %s %s %s %s %s %s", msg, self.name, datetime.fromtimestamp(start_time), datetime.fromtimestamp(end_time), start_time, end_time, body, ) async def async_update_measures( self, start_time: int | None = None, end_time: int | None = None, interval: MeasureInterval = MeasureInterval.HOUR, days: int = 7, ) -> None: """Update historical data.""" if end_time is None: end_time = int(datetime.now().timestamp()) if start_time is None: end = datetime.fromtimestamp(end_time) start_time = end - timedelta(days=days) start_time = int(start_time.timestamp()) prev_start_time = self.start_time prev_end_time = self.end_time self.start_time = start_time self.end_time = end_time # the legrand/netatmo handling of start and endtime is very peculiar # for 30mn/1h/3h intervals : in fact the starts is asked_start + intervals/2 ! # => so shift of 15mn, 30mn and 1h30 # for 1day : start is ALWAYS 12am (half day) of the first day of the range # for 1week : it will be half week ALWAYS, ie on a thursday at 12am (half day) # in fact in the case for all intervals the reported dates are "the middle" of the ranges delta_range = MEASURE_INTERVAL_TO_SECONDS.get(interval, 0) // 2 filters, raw_data = await self._energy_API_calls(start_time, end_time, interval) hist_good_vals = await self._get_aligned_energy_values_and_mode( start_time, end_time, delta_range, raw_data ) self.historical_data = [] prev_sum_energy_elec = self.sum_energy_elec self.sum_energy_elec = 0 self.sum_energy_elec_peak = 0 self.sum_energy_elec_off_peak = 0 # no data at all: we know nothing for the end: best guess, it is the start self._anchor_for_power_adjustment = start_time self.in_reset = False if len(hist_good_vals) == 0: # nothing has been updated or changed it can nearly be seen as an error, but the api is answering correctly # so we probably have to reset to 0 anyway as it means there were no exisitng # historical data for this time range LOG.debug( "NO VALUES energy update %s from: %s to %s, prev_sum=%s", self.name, datetime.fromtimestamp(start_time), datetime.fromtimestamp(end_time), prev_sum_energy_elec if prev_sum_energy_elec is not None else "NOTHING", ) else: await self._prepare_exported_historical_data( start_time, end_time, delta_range, hist_good_vals, prev_end_time, prev_start_time, prev_sum_energy_elec, ) async def _prepare_exported_historical_data( self, start_time, end_time, delta_range, hist_good_vals, prev_end_time, prev_start_time, prev_sum_energy_elec, ): computed_start = 0 computed_end = 0 computed_end_for_calculus = 0 for cur_start_time, val, vals in hist_good_vals: self.sum_energy_elec += val modes = [] val_modes = [] for i, v in enumerate(vals): if v is not None: modes.append(ENERGY_FILTERS_MODES[i]) val_modes.append(v) if ENERGY_FILTERS_MODES[i] == "off_peak": self.sum_energy_elec_off_peak += v elif ENERGY_FILTERS_MODES[i] == "peak": self.sum_energy_elec_peak += v c_start = cur_start_time c_end = cur_start_time + 2 * delta_range if computed_start == 0: computed_start = c_start computed_end = c_end # - delta_range not sure, revert ... it seems the energy value effectively stops at those mid values computed_end_for_calculus = c_end # - delta_range start_time_string = f"{datetime.fromtimestamp(c_start + 1, tz=timezone.utc).isoformat().split('+')[0]}Z" end_time_string = f"{datetime.fromtimestamp(c_end, tz=timezone.utc).isoformat().split('+')[0]}Z" self.historical_data.append( { "duration": (2 * delta_range) // 60, "startTime": start_time_string, "endTime": end_time_string, "Wh": val, "energyMode": modes, "WhPerModes": val_modes, "startTimeUnix": c_start, "endTimeUnix": c_end, }, ) if ( prev_sum_energy_elec is not None and prev_sum_energy_elec > self.sum_energy_elec ): msg = ( "ENERGY GOING DOWN %s from: %s to %s " "computed_start: %s, computed_end: %s, " "sum=%f prev_sum=%f prev_start: %s, prev_end %s" ) LOG.debug( msg, self.name, datetime.fromtimestamp(start_time), datetime.fromtimestamp(end_time), datetime.fromtimestamp(computed_start), datetime.fromtimestamp(computed_end), self.sum_energy_elec, prev_sum_energy_elec, datetime.fromtimestamp(prev_start_time), datetime.fromtimestamp(prev_end_time), ) else: msg = ( "Success in energy update %s from: %s to %s " "computed_start: %s, computed_end: %s , sum=%s prev_sum=%s" ) LOG.debug( msg, self.name, datetime.fromtimestamp(start_time), datetime.fromtimestamp(end_time), datetime.fromtimestamp(computed_start), datetime.fromtimestamp(computed_end), self.sum_energy_elec, prev_sum_energy_elec if prev_sum_energy_elec is not None else "NOTHING", ) self._anchor_for_power_adjustment = computed_end_for_calculus async def _get_aligned_energy_values_and_mode( self, start_time, end_time, delta_range, raw_data ): hist_good_vals = [] values_lots = raw_data for values_lot in values_lots: try: start_lot_time = int(values_lot["beg_time"]) except Exception: self._log_energy_error( start_time, end_time, msg="beg_time missing", body=values_lots, ) raise ApiError( f"Energy badly formed resp beg_time missing: {values_lots} - " f"module: {self.name}" ) from None interval_sec = values_lot.get("step_time") if interval_sec is None: if len(values_lot.get("value", [])) > 1: self._log_energy_error( start_time, end_time, msg="step_time missing", body=values_lots, ) interval_sec = 2 * delta_range else: interval_sec = int(interval_sec) # align the start on the begining of the segment cur_start_time = start_lot_time - interval_sec // 2 for val_arr in values_lot.get("value", []): vals = [] val = 0 for v in val_arr: if v is not None: v = int(v) val += v vals.append(v) else: vals.append(None) hist_good_vals.append((cur_start_time, val, vals)) cur_start_time = cur_start_time + interval_sec hist_good_vals = sorted(hist_good_vals, key=itemgetter(0)) return hist_good_vals def _get_energy_filers(self): return ENERGY_FILTERS async def _energy_API_calls(self, start_time, end_time, interval): filters = self._get_energy_filers() params = { "device_id": self.bridge, "module_id": self.entity_id, "scale": interval.value, "type": filters, "date_begin": start_time, "date_end": end_time, } resp = await self.home.auth.async_post_api_request( endpoint=GETMEASURE_ENDPOINT, params=params, ) rw_dt_f = await resp.json() rw_dt = rw_dt_f.get("body") if rw_dt is None: self._log_energy_error( start_time, end_time, msg=f"direct from {filters}", body=rw_dt_f ) raise ApiError( f"Energy badly formed resp: {rw_dt_f} - " f"module: {self.name} - " f"when accessing '{filters}'" ) raw_data = rw_dt return filters, raw_data class EnergyHistoryLegacyMixin(EnergyHistoryMixin): """Mixin for Energy history data, Using legacy APis (used for NLE).""" def _get_energy_filers(self): return ENERGY_FILTERS_LEGACY class Module(NetatmoBase): """Class to represent a Netatmo module.""" device_type: DeviceType device_category: DeviceCategory | None room_id: str | None modules: list[str] | None reachable: bool | None features: set[str] def __init__(self, home: Home, module: ModuleT) -> None: """Initialize a Netatmo module instance.""" super().__init__(module) self.device_type = DeviceType(module["type"]) self.home = home self.room_id = module.get("room_id") self.reachable = module.get("reachable") self.bridge = module.get("bridge") self.modules = module.get("modules_bridged") self.device_category = DEVICE_CATEGORY_MAP.get(self.device_type) self.features = set() async def update(self, raw_data: RawData) -> None: """Update module with the latest data.""" self.update_topology(raw_data) self.update_features() # If we have an NLE as a bridge all its bridged modules will have to be reachable if self.device_type == DeviceType.NLE: # if there is a bridge it means it is a leaf if self.bridge: self.reachable = True elif self.modules: # this NLE is a bridge itself : make it not available self.reachable = False if not self.reachable and self.modules: # Update bridged modules and associated rooms for module_id in self.modules: module = self.home.modules[module_id] await module.update(raw_data) if module.room_id: self.home.rooms[module.room_id].update(raw_data) def update_features(self) -> None: """Update features.""" self.features.update({var for var in vars(self) if var not in ATTRIBUTE_FILTER}) if "battery_state" in vars(self) or "battery_percent" in vars(self): self.features.add("battery") if "wind_angle" in self.features: self.features.add("wind_direction") self.features.add("gust_direction") # pylint: disable=too-many-ancestors class Camera( FirmwareMixin, MonitoringMixin, EventMixin, CameraMixin, WifiMixin, Module, ): """Class to represent a Netatmo camera.""" async def update(self, raw_data: RawData) -> None: """Update camera with the latest data.""" await Module.update(self, raw_data) await self.async_update_camera_urls() class Switch(FirmwareMixin, EnergyHistoryMixin, PowerMixin, SwitchMixin, Module): """Class to represent a Netatmo switch.""" ... class Dimmer(DimmableMixin, Switch): """Class to represent a Netatmo dimmer.""" ... class Shutter(FirmwareMixin, ShutterMixin, Module): """Class to represent a Netatmo shutter.""" ... class Fan(FirmwareMixin, FanSpeedMixin, PowerMixin, Module): """Class to represent a Netatmo ventilation device.""" ... # pylint: enable=too-many-ancestors jabesq-org-pyatmo-6216472/src/pyatmo/modules/netatmo.py000066400000000000000000000164111466116727400230620ustar00rootroot00000000000000"""Module to represent Netatmo modules.""" from __future__ import annotations from dataclasses import dataclass import logging from typing import Any from pyatmo.const import ( ACCESSORY_GUST_ANGLE_TYPE, ACCESSORY_GUST_STRENGTH_TYPE, ACCESSORY_RAIN_24H_TYPE, ACCESSORY_RAIN_60MIN_TYPE, ACCESSORY_RAIN_LIVE_TYPE, ACCESSORY_WIND_ANGLE_TYPE, ACCESSORY_WIND_STRENGTH_TYPE, STATION_HUMIDITY_TYPE, STATION_PRESSURE_TYPE, STATION_TEMPERATURE_TYPE, RawData, ) from pyatmo.modules.module import ( BatteryMixin, BoilerMixin, Camera, CO2Mixin, FirmwareMixin, FloodlightMixin, HealthIndexMixin, HumidityMixin, Module, MonitoringMixin, NoiseMixin, PlaceMixin, PressureMixin, RainMixin, RfMixin, StatusMixin, TemperatureMixin, WifiMixin, WindMixin, ) LOG = logging.getLogger(__name__) # pylint: disable=R0901 class NRV(FirmwareMixin, RfMixin, BatteryMixin, Module): """Class to represent a Netatmo NRV.""" ... class NATherm1(FirmwareMixin, RfMixin, BatteryMixin, BoilerMixin, Module): """Class to represent a Netatmo NATherm1.""" ... class NAPlug(FirmwareMixin, RfMixin, WifiMixin, Module): """Class to represent a Netatmo NAPlug.""" ... class OTH(FirmwareMixin, WifiMixin, Module): """Class to represent a Netatmo OTH.""" ... class OTM(FirmwareMixin, RfMixin, BatteryMixin, BoilerMixin, Module): """Class to represent a Netatmo OTM.""" ... class NACamera(Camera): """Class to represent a Netatmo NACamera.""" ... class NOC(FloodlightMixin, Camera): """Class to represent a Netatmo NOC.""" ... class NDB(Camera): """Class to represent a Netatmo NDB.""" ... class NAMain( TemperatureMixin, HumidityMixin, CO2Mixin, NoiseMixin, PressureMixin, WifiMixin, FirmwareMixin, PlaceMixin, Module, ): """Class to represent a Netatmo NAMain.""" ... class NAModule1( TemperatureMixin, HumidityMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module, ): """Class to represent a Netatmo NAModule1.""" ... class NAModule2(WindMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module): """Class to represent a Netatmo NAModule2.""" ... class NAModule3(RainMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module): """Class to represent a Netatmo NAModule3.""" ... class NAModule4( TemperatureMixin, CO2Mixin, HumidityMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module, ): """Class to represent a Netatmo NAModule4.""" ... class NHC( TemperatureMixin, HumidityMixin, CO2Mixin, PressureMixin, NoiseMixin, HealthIndexMixin, WifiMixin, FirmwareMixin, PlaceMixin, Module, ): """Class to represent a Netatmo NHC.""" ... class NACamDoorTag(StatusMixin, FirmwareMixin, BatteryMixin, RfMixin, Module): """Class to represent a Netatmo NACamDoorTag.""" ... class NIS( StatusMixin, MonitoringMixin, FirmwareMixin, BatteryMixin, RfMixin, Module, ): """Class to represent a Netatmo NIS.""" ... class NSD( FirmwareMixin, Module, ): """Class to represent a Netatmo NSD.""" ... class NCO( FirmwareMixin, Module, ): """Class to represent a Netatmo NCO.""" ... @dataclass class Location: """Class of Netatmo public weather location.""" lat_ne: str lon_ne: str lat_sw: str lon_sw: str class PublicWeatherArea: """Class of Netatmo public weather data.""" location: Location required_data_type: str | None filtering: bool modules: list[dict[str, Any]] def __init__( self, lat_ne: str, lon_ne: str, lat_sw: str, lon_sw: str, required_data_type: str | None = None, filtering: bool = False, ) -> None: """Initialize self.""" self.location = Location( lat_ne, lon_ne, lat_sw, lon_sw, ) self.modules = [] self.required_data_type = required_data_type self.filtering = filtering def update(self, raw_data: RawData) -> None: """Update public weather area with the latest data.""" self.modules = list(raw_data.get("public", [])) def stations_in_area(self) -> int: """Return available number of stations in area.""" return len(self.modules) def get_latest_rain(self) -> dict[str, Any]: """Return latest rain measures.""" return self.get_accessory_data(ACCESSORY_RAIN_LIVE_TYPE) def get_60_min_rain(self) -> dict[str, Any]: """Return 60 min rain measures.""" return self.get_accessory_data(ACCESSORY_RAIN_60MIN_TYPE) def get_24_h_rain(self) -> dict[str, Any]: """Return 24 h rain measures.""" return self.get_accessory_data(ACCESSORY_RAIN_24H_TYPE) def get_latest_pressures(self) -> dict[str, Any]: """Return latest pressure measures.""" return self.get_latest_station_measures(STATION_PRESSURE_TYPE) def get_latest_temperatures(self) -> dict[str, Any]: """Return latest temperature measures.""" return self.get_latest_station_measures(STATION_TEMPERATURE_TYPE) def get_latest_humidities(self) -> dict[str, Any]: """Return latest humidity measures.""" return self.get_latest_station_measures(STATION_HUMIDITY_TYPE) def get_latest_wind_strengths(self) -> dict[str, Any]: """Return latest wind strength measures.""" return self.get_accessory_data(ACCESSORY_WIND_STRENGTH_TYPE) def get_latest_wind_angles(self) -> dict[str, Any]: """Return latest wind angle measures.""" return self.get_accessory_data(ACCESSORY_WIND_ANGLE_TYPE) def get_latest_gust_strengths(self) -> dict[str, Any]: """Return latest gust strength measures.""" return self.get_accessory_data(ACCESSORY_GUST_STRENGTH_TYPE) def get_latest_gust_angles(self) -> dict[str, Any]: """Return latest gust angle measures.""" return self.get_accessory_data(ACCESSORY_GUST_ANGLE_TYPE) def get_latest_station_measures(self, data_type: str) -> dict[str, Any]: """Return latest station measures of a given type.""" measures: dict[str, Any] = {} for station in self.modules: for module in station["measures"].values(): if ( "type" in module and data_type in module["type"] and "res" in module and module["res"] ): measure_index = module["type"].index(data_type) latest_timestamp = sorted(module["res"], reverse=True)[0] measures[station["_id"]] = module["res"][latest_timestamp][ measure_index ] return measures def get_accessory_data(self, data_type: str) -> dict[str, Any]: """Return accessory data of a given type.""" data: dict[str, Any] = {} for station in self.modules: for module in station["measures"].values(): if data_type in module: data[station["_id"]] = module[data_type] return data jabesq-org-pyatmo-6216472/src/pyatmo/modules/smarther.py000066400000000000000000000005421466116727400232360ustar00rootroot00000000000000"""Module to represent Smarther modules.""" from __future__ import annotations import logging from pyatmo.modules.module import ( BoilerMixin, CoolerMixin, FirmwareMixin, Module, WifiMixin, ) LOG = logging.getLogger(__name__) class BNS(FirmwareMixin, BoilerMixin, CoolerMixin, WifiMixin, Module): """Smarther thermostat.""" jabesq-org-pyatmo-6216472/src/pyatmo/modules/somfy.py000066400000000000000000000004121466116727400225420ustar00rootroot00000000000000"""Module to represent somfy modules.""" from __future__ import annotations import logging from pyatmo.modules.module import RfMixin, Shutter LOG = logging.getLogger(__name__) class TPSRS(RfMixin, Shutter): """Class to represent a somfy TPSRS.""" ... jabesq-org-pyatmo-6216472/src/pyatmo/person.py000066400000000000000000000017261466116727400212540ustar00rootroot00000000000000"""Module to represent a Netatmo person.""" from __future__ import annotations from dataclasses import dataclass import logging from typing import TYPE_CHECKING from pyatmo.const import RawData from pyatmo.modules.base_class import NetatmoBase if TYPE_CHECKING: from .home import Home LOG = logging.getLogger(__name__) @dataclass class Person(NetatmoBase): """Class to represent a Netatmo person.""" pseudo: str | None url: str | None out_of_sight: bool | None = None last_seen: int | None = None def __init__(self, home: Home, raw_data: RawData) -> None: """Initialize a Netatmo person instance.""" super().__init__(raw_data) self.home = home self.pseudo = raw_data.get("pseudo") self.url = raw_data.get("url") def update(self, raw_data: RawData) -> None: """Update person data.""" self.out_of_sight = raw_data.get("out_of_sight") self.last_seen = raw_data.get("last_seen") jabesq-org-pyatmo-6216472/src/pyatmo/py.typed000066400000000000000000000000001466116727400210530ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/src/pyatmo/room.py000066400000000000000000000161541466116727400207230ustar00rootroot00000000000000"""Module to represent a Netatmo room.""" from __future__ import annotations from dataclasses import dataclass import logging from typing import TYPE_CHECKING, Any from pyatmo.const import ( FROSTGUARD, HOME, MANUAL, SETROOMTHERMPOINT_ENDPOINT, UNKNOWN, RawData, ) from pyatmo.modules.base_class import NetatmoBase from pyatmo.modules.device_types import DeviceType if TYPE_CHECKING: from pyatmo.home import Home from pyatmo.modules.module import Module LOG = logging.getLogger(__name__) MODE_MAP = {"schedule": "home"} @dataclass class Room(NetatmoBase): """Class to represent a Netatmo room.""" modules: dict[str, Module] device_types: set[DeviceType] features: set[str] climate_type: DeviceType | None = None humidity: int | None = None therm_measured_temperature: float | None = None reachable: bool | None = None heating_power_request: int | None = None therm_setpoint_temperature: float | None = None therm_setpoint_mode: str | None = None therm_setpoint_start_time: int | None = None therm_setpoint_end_time: int | None = None anticipating: bool | None = None open_window: bool | None = None cooling_setpoint_temperature: float | None = None cooling_setpoint_start_time: int | None = None cooling_setpoint_end_time: int | None = None cooling_setpoint_mode: str | None = None def __init__( self, home: Home, room: dict[str, Any], all_modules: dict[str, Module], ) -> None: """Initialize a Netatmo room instance.""" super().__init__(room) self.home = home self.modules = { m_id: m for m_id, m in all_modules.items() if m_id in room.get("module_ids", []) } self.device_types = set() self.features = set() self.evaluate_device_type() def update_topology(self, raw_data: RawData) -> None: """Update room topology.""" self.name = raw_data.get("name", UNKNOWN) self.modules = { m_id: m for m_id, m in self.home.modules.items() if m_id in raw_data.get("module_ids", []) } self.evaluate_device_type() def evaluate_device_type(self) -> None: """Evaluate the device type of the room.""" for module in self.modules.values(): self.device_types.add(module.device_type) if module.device_category is not None: self.features.add(module.device_category.name) if "OTM" in self.device_types: self.climate_type = DeviceType.OTM elif "NRV" in self.device_types: self.climate_type = DeviceType.NRV elif "NATherm1" in self.device_types: self.climate_type = DeviceType.NATherm1 elif "BNS" in self.device_types: self.climate_type = DeviceType.BNS self.features.add("humidity") elif "BNTH" in self.device_types: self.climate_type = DeviceType.BNTH def update(self, raw_data: RawData) -> None: """Update room data.""" self.humidity = raw_data.get("humidity") if self.climate_type == DeviceType.BNTH: # BNTH is wired, so the room is always reachable self.reachable = True else: self.reachable = raw_data.get("reachable") self.therm_measured_temperature = raw_data.get("therm_measured_temperature") self.reachable = raw_data.get("reachable") self.heating_power_request = raw_data.get("heating_power_request") self.therm_setpoint_mode = raw_data.get("therm_setpoint_mode") self.therm_setpoint_temperature = raw_data.get("therm_setpoint_temperature") self.therm_setpoint_start_time = raw_data.get("therm_setpoint_start_time") self.therm_setpoint_end_time = raw_data.get("therm_setpoint_end_time") self.anticipating = raw_data.get("anticipating") self.open_window = raw_data.get("open_window") self.cooling_setpoint_temperature = raw_data.get("cooling_setpoint_temperature") self.cooling_setpoint_start_time = raw_data.get("cooling_setpoint_start_time") self.cooling_setpoint_end_time = raw_data.get("cooling_setpoint_end_time") self.cooling_setpoint_mode = raw_data.get("cooling_setpoint_mode") async def async_therm_manual( self, temp: float | None = None, end_time: int | None = None, ) -> None: """Set room temperature set point to manual.""" await self.async_therm_set(MANUAL, temp, end_time) async def async_therm_home(self, end_time: int | None = None) -> None: """Set room temperature set point to home.""" await self.async_therm_set(HOME, end_time=end_time) async def async_therm_frostguard(self, end_time: int | None = None) -> None: """Set room temperature set point to frostguard.""" await self.async_therm_set(FROSTGUARD, end_time=end_time) async def async_therm_set( self, mode: str, temp: float | None = None, end_time: int | None = None, ) -> None: """Set room temperature set point.""" mode = MODE_MAP.get(mode, mode) if "NATherm1" in self.device_types or ( "NRV" in self.device_types and not self.home.has_otm() and not self.home.has_bns() ): await self._async_set_thermpoint(mode, temp, end_time) else: await self._async_therm_set(mode, temp, end_time) async def _async_therm_set( self, mode: str, temp: float | None = None, end_time: int | None = None, ) -> bool: """Set room temperature set point (OTM).""" json_therm_set: dict[str, Any] = { "rooms": [ { "id": self.entity_id, "therm_setpoint_mode": mode, }, ], } if temp: json_therm_set["rooms"][0]["therm_setpoint_temperature"] = temp if end_time: json_therm_set["rooms"][0]["therm_setpoint_end_time"] = end_time return await self.home.async_set_state(json_therm_set) async def _async_set_thermpoint( self, mode: str, temp: float | None = None, end_time: int | None = None, ) -> None: """Set room temperature set point (NRV, NATherm1).""" post_params = { "home_id": self.home.entity_id, "room_id": self.entity_id, "mode": mode, } # Temp and endtime should only be sent when mode=='manual', but netatmo api can # handle that even when mode == 'home' and these settings don't make sense if temp is not None: post_params["temp"] = str(temp) if end_time is not None: post_params["endtime"] = str(end_time) LOG.debug( "Setting room (%s) temperature set point to %s until %s", self.entity_id, temp, end_time, ) await self.home.auth.async_post_api_request( endpoint=SETROOMTHERMPOINT_ENDPOINT, params=post_params, ) jabesq-org-pyatmo-6216472/src/pyatmo/schedule.py000066400000000000000000000040731466116727400215400ustar00rootroot00000000000000"""Module to represent a Netatmo schedule.""" from __future__ import annotations from dataclasses import dataclass import logging from typing import TYPE_CHECKING from pyatmo.const import RawData from pyatmo.modules.base_class import NetatmoBase from pyatmo.room import Room if TYPE_CHECKING: from .home import Home LOG = logging.getLogger(__name__) @dataclass class Schedule(NetatmoBase): """Class to represent a Netatmo schedule.""" selected: bool away_temp: float | None hg_temp: float | None timetable: list[TimetableEntry] def __init__(self, home: Home, raw_data: RawData) -> None: """Initialize a Netatmo schedule instance.""" super().__init__(raw_data) self.home = home self.selected = raw_data.get("selected", False) self.hg_temp = raw_data.get("hg_temp") self.away_temp = raw_data.get("away_temp") self.timetable = [ TimetableEntry(home, r) for r in raw_data.get("timetable", []) ] self.zones = [Zone(home, r) for r in raw_data.get("zones", [])] @dataclass class TimetableEntry: """Class to represent a Netatmo schedule's timetable entry.""" zone_id: int | None m_offset: int | None def __init__(self, home: Home, raw_data: RawData) -> None: """Initialize a Netatmo schedule's timetable entry instance.""" self.home = home self.zone_id = raw_data.get("zone_id", 0) self.m_offset = raw_data.get("m_offset", 0) @dataclass class Zone(NetatmoBase): """Class to represent a Netatmo schedule's zone.""" type: int rooms: list[Room] def __init__(self, home: Home, raw_data: RawData) -> None: """Initialize a Netatmo schedule's zone instance.""" super().__init__(raw_data) self.home = home self.type = raw_data.get("type", 0) def room_factory(home: Home, room_raw_data: RawData): room = Room(home, room_raw_data, {}) room.update(room_raw_data) return room self.rooms = [room_factory(home, r) for r in raw_data.get("rooms", [])] jabesq-org-pyatmo-6216472/tests/000077500000000000000000000000001466116727400164305ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/tests/__init__.py000066400000000000000000000000001466116727400205270ustar00rootroot00000000000000jabesq-org-pyatmo-6216472/tests/common.py000066400000000000000000000041631466116727400202760ustar00rootroot00000000000000"""Define shared test helpers.""" # pylint: disable=redefined-outer-name, protected-access, unused-argument from __future__ import annotations import json import pathlib def get_fixture_path(filename: str) -> pathlib.Path: """Get path of fixture.""" return pathlib.Path(__file__).parent.joinpath("../fixtures", filename) def load_fixture(filename): """Load a fixture.""" return get_fixture_path(filename).read_text(encoding="utf-8") class MockResponse: def __init__(self, text, status): self._text = text self.status = status async def json(self): return self._text async def read(self): return self._text async def __aexit__(self, exc_type, exc, traceback): pass async def __aenter__(self): return self async def fake_post_request(*args, **kwargs): """Return fake data.""" if "endpoint" not in kwargs: return "{}" endpoint = kwargs["endpoint"].split("/")[-1] if endpoint in "snapshot_720.jpg": return b"test stream image bytes" if endpoint in [ "setpersonsaway", "setpersonshome", "setstate", "setroomthermpoint", "setthermmode", "switchhomeschedule", ]: payload = f'{{"{endpoint}": true}}' elif endpoint == "homestatus": home_id = kwargs.get("params", {}).get("home_id") payload = json.loads(load_fixture(f"{endpoint}_{home_id}.json")) elif endpoint == "getmeasure": module_id = kwargs.get("params", {}).get("module_id") type = kwargs.get("params", {}).get("type") payload = json.loads( load_fixture(f"{endpoint}_{type}_{module_id.replace(':', '_')}.json"), ) else: postfix = kwargs.get("POSTFIX", None) if postfix is not None: payload = json.loads(load_fixture(f"{endpoint}_{postfix}.json")) else: payload = json.loads(load_fixture(f"{endpoint}.json")) return MockResponse(payload, 200) async def fake_post_request_multi(*args, **kwargs): kwargs["POSTFIX"] = "multi" r = await fake_post_request(*args, **kwargs) return r jabesq-org-pyatmo-6216472/tests/conftest.py000066400000000000000000000037451466116727400206400ustar00rootroot00000000000000"""Define shared fixtures.""" # pylint: disable=redefined-outer-name, protected-access from contextlib import contextmanager from unittest.mock import AsyncMock, patch import pyatmo import pytest from .common import fake_post_request, fake_post_request_multi @contextmanager def does_not_raise(): yield @pytest.fixture(scope="function") async def async_auth(): """AsyncAuth fixture.""" with patch("pyatmo.auth.AbstractAsyncAuth", AsyncMock()) as auth: yield auth @pytest.fixture(scope="function") async def async_account(async_auth): """AsyncAccount fixture.""" account = pyatmo.AsyncAccount(async_auth) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", fake_post_request, ), patch( "pyatmo.auth.AbstractAsyncAuth.async_post_request", fake_post_request, ): await account.async_update_topology() yield account @pytest.fixture(scope="function") async def async_home(async_account): """AsyncClimate fixture for home_id 91763b24c43d3e344f424e8b.""" home_id = "91763b24c43d3e344f424e8b" await async_account.async_update_status(home_id) yield async_account.homes[home_id] @pytest.fixture(scope="function") async def async_account_multi(async_auth): """AsyncAccount fixture.""" account = pyatmo.AsyncAccount(async_auth) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", fake_post_request_multi, ), patch( "pyatmo.auth.AbstractAsyncAuth.async_post_request", fake_post_request_multi, ): await account.async_update_topology( disabled_homes_ids=["eeeeeeeeeffffffffffaaaaa"] ) yield account @pytest.fixture(scope="function") async def async_home_multi(async_account_multi): """AsyncClimate fixture for home_id 91763b24c43d3e344f424e8b.""" home_id = "aaaaaaaaaaabbbbbbbbbbccc" await async_account_multi.async_update_status(home_id) yield async_account_multi.homes[home_id] jabesq-org-pyatmo-6216472/tests/test_camera.py000066400000000000000000000077401466116727400213010ustar00rootroot00000000000000"""Define tests for camera module.""" import json from unittest.mock import AsyncMock, patch from pyatmo import DeviceType import pytest from tests.common import MockResponse # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_camera_NACamera(async_home): # pylint: disable=invalid-name """Test Netatmo indoor camera module.""" module_id = "12:34:56:00:f1:62" assert module_id in async_home.modules module = async_home.modules[module_id] await module.async_update_camera_urls() assert module.device_type == DeviceType.NACamera assert module.is_local assert module.local_url == "http://192.168.0.123/678460a0d47e5618699fb31169e2b47d" person_id = "91827374-7e04-5298-83ad-a0cb8372dff1" assert person_id in module.home.persons person = module.home.persons[person_id] assert person.pseudo == "John Doe" assert person.out_of_sight assert person.last_seen == 1557071156 @pytest.mark.asyncio async def test_async_NOC(async_home): # pylint: disable=invalid-name """Test basic outdoor camera functionality.""" module_id = "12:34:56:10:b9:0e" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NOC assert module.firmware_revision == 3002000 assert module.firmware_name == "3.2.0" assert module.monitoring is True assert module.alim_status == 2 assert module.is_local is False assert module.floodlight == "auto" with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) def gen_json_data(state): return { "json": { "home": { "id": "91763b24c43d3e344f424e8b", "modules": [ { "id": module_id, "floodlight": state, }, ], }, }, } with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_resp: assert await module.async_floodlight_on() mock_resp.assert_awaited_with( params=gen_json_data("on"), endpoint="api/setstate", ) assert await module.async_floodlight_off() mock_resp.assert_awaited_with( params=gen_json_data("off"), endpoint="api/setstate", ) assert await module.async_floodlight_auto() mock_resp.assert_awaited_with( params=gen_json_data("auto"), endpoint="api/setstate", ) @pytest.mark.asyncio async def test_async_camera_monitoring(async_home): """Test basic camera monitoring functionality.""" module_id = "12:34:56:10:b9:0e" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NOC assert module.is_local is False with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) def gen_json_data(state): return { "json": { "home": { "id": "91763b24c43d3e344f424e8b", "modules": [ { "id": module_id, "monitoring": state, }, ], }, }, } with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_resp: assert await module.async_monitoring_on() mock_resp.assert_awaited_with( params=gen_json_data("on"), endpoint="api/setstate", ) assert await module.async_monitoring_off() mock_resp.assert_awaited_with( params=gen_json_data("off"), endpoint="api/setstate", ) jabesq-org-pyatmo-6216472/tests/test_climate.py000066400000000000000000000246131466116727400214650ustar00rootroot00000000000000"""Define tests for climate module.""" import json from unittest.mock import AsyncMock, patch from pyatmo import DeviceType, NoSchedule from pyatmo.modules import NATherm1 from pyatmo.modules.device_types import DeviceCategory import pytest from tests.common import MockResponse, fake_post_request from tests.conftest import does_not_raise # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_climate_room(async_home): """Test room with climate devices.""" room_id = "2746182631" assert room_id in async_home.rooms room = async_home.rooms[room_id] assert room.reachable is True assert room.device_types == {DeviceType.NATherm1} module_id = "12:34:56:00:01:ae" assert module_id in room.modules assert len(room.modules) == 1 @pytest.mark.asyncio async def test_async_climate_NATherm1(async_home): # pylint: disable=invalid-name """Test NATherm1 climate device.""" module_id = "12:34:56:00:01:ae" module = async_home.modules[module_id] assert module.name == "Livingroom" assert module.device_type == DeviceType.NATherm1 assert module.reachable is True assert module.boiler_status is False assert module.firmware_revision == 65 assert module.battery == 75 assert module.rf_strength == 58 @pytest.mark.asyncio async def test_async_climate_NRV(async_home): # pylint: disable=invalid-name """Test NRV climate device.""" module_id = "12:34:56:03:a5:54" module = async_home.modules[module_id] assert module.name == "Valve1" assert async_home.rooms[module.room_id].name == "Entrada" assert module.device_type == DeviceType.NRV assert module.reachable is True assert module.rf_strength == 51 assert module.battery == 90 assert module.firmware_revision == 79 @pytest.mark.asyncio async def test_async_climate_NAPlug(async_home): # pylint: disable=invalid-name """Test NAPlug climate device.""" module_id = "12:34:56:00:fa:d0" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NAPlug assert len(module.modules) == 3 assert module.rf_strength == 107 assert module.wifi_strength == 42 assert module.firmware_revision == 174 @pytest.mark.asyncio async def test_async_climate_NIS(async_home): # pylint: disable=invalid-name """Test Netatmo siren.""" module_id = "12:34:56:00:e3:9b" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NIS assert module.firmware_revision == 209 assert module.status == "no_sound" assert module.monitoring is False @pytest.mark.asyncio async def test_async_climate_OTM(async_home): # pylint: disable=invalid-name """Test OTM climate device.""" module_id = "12:34:56:20:f5:8c" module = async_home.modules[module_id] assert module.name == "Bureau Modulate" assert module.device_type == DeviceType.OTM assert module.reachable is True assert module.boiler_status is False assert module.firmware_revision == 6 assert module.battery == 90 assert module.rf_strength == 64 @pytest.mark.asyncio async def test_async_climate_OTH(async_home): # pylint: disable=invalid-name """Test OTH climate device.""" module_id = "12:34:56:20:f5:44" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.OTH assert len(module.modules) == 1 assert module.wifi_strength == 57 assert module.firmware_revision == 22 @pytest.mark.asyncio async def test_async_climate_BNS(async_home): # pylint: disable=invalid-name """Test Smarther BNS climate module.""" module_id = "10:20:30:bd:b8:1e" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.BNS assert module.name == "Smarther" room = async_home.rooms[module.room_id] assert room.name == "Corridor" assert room.device_types == { DeviceType.BNS, } assert room.features == {"humidity", DeviceCategory.climate} @pytest.mark.asyncio async def test_async_climate_update(async_account): """Test basic climate state update.""" home_id = "91763b24c43d3e344f424e8b" await async_account.async_update_status(home_id) home = async_account.homes[home_id] room_id = "2746182631" room = home.rooms[room_id] module_id = "12:34:56:00:01:ae" module = home.modules[module_id] assert room.reachable is True assert room.humidity is None assert module.name == "Livingroom" assert module.device_type == DeviceType.NATherm1 assert module.reachable is True assert module.boiler_status is False assert module.battery == 75 assert isinstance(module, NATherm1) with open( "fixtures/home_status_error_disconnected.json", encoding="utf-8", ) as json_file: home_status_fixture = json.load(json_file) mock_home_status_resp = MockResponse(home_status_fixture, 200) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=mock_home_status_resp), ) as mock_request: await async_account.async_update_status(home_id) mock_request.assert_called() assert room.reachable is None assert module.reachable is False with open("fixtures/home_status_simple.json", encoding="utf-8") as json_file: home_status_fixture = json.load(json_file) mock_home_status_resp = MockResponse(home_status_fixture, 200) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=mock_home_status_resp), ) as mock_request: await async_account.async_update_status(home_id) mock_request.assert_called() assert room.reachable is True assert module.reachable is True assert module.battery == 75 assert module.rf_strength == 58 @pytest.mark.parametrize( "t_sched_id, expected", [ ("591b54a2764ff4d50d8b5795", does_not_raise()), ( "123456789abcdefg12345678", pytest.raises(NoSchedule), ), ], ) @pytest.mark.asyncio async def test_async_climate_switch_schedule( async_home, t_sched_id, expected, ): with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ), expected: await async_home.async_switch_schedule( schedule_id=t_sched_id, ) @pytest.mark.parametrize( "temp, end_time", [ ( 14, None, ), ( 14, 1559162650, ), ( None, None, ), ( None, 1559162650, ), ], ) @pytest.mark.asyncio async def test_async_climate_room_therm_set( async_home, temp, end_time, ): room_id = "2746182631" mode = "home" expected_params = { "home_id": "91763b24c43d3e344f424e8b", "room_id": room_id, "mode": mode, } if temp: expected_params["temp"] = str(temp) if end_time: expected_params["endtime"] = str(end_time) with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_post: room = async_home.rooms[room_id] await room.async_therm_set( mode=mode, temp=temp, end_time=end_time, ) mock_post.assert_awaited_once_with( endpoint="api/setroomthermpoint", params=expected_params, ) @pytest.mark.parametrize( "mode, end_time, schedule_id, json_fixture, expected, exception", [ ( "away", None, None, "status_ok.json", True, does_not_raise(), ), ( "away", 1559162650, None, "status_ok.json", True, does_not_raise(), ), ( "schedule", None, "591b54a2764ff4d50d8b5795", "status_ok.json", True, does_not_raise(), ), ( "schedule", 1559162650, "591b54a2764ff4d50d8b5795", "status_ok.json", True, does_not_raise(), ), ( None, None, None, "home_status_error_mode_is_missing.json", False, pytest.raises(NoSchedule), ), ( None, None, None, "home_status_error_mode_is_missing.json", False, pytest.raises(NoSchedule), ), ( "away", 1559162650, 0000000, "status_ok.json", True, pytest.raises(NoSchedule), ), ( "schedule", None, "blahblahblah", "home_status_error_invalid_schedule_id.json", False, pytest.raises(NoSchedule), ), ], ) @pytest.mark.asyncio async def test_async_climate_set_thermmode( async_home, mode, end_time, schedule_id, json_fixture, expected, exception, ): with open(f"fixtures/{json_fixture}", encoding="utf-8") as json_file: response = json.load(json_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ), exception: resp = await async_home.async_set_thermmode( mode=mode, end_time=end_time, schedule_id=schedule_id, ) assert expected is resp @pytest.mark.asyncio async def test_async_climate_empty_home(async_account): """Test climate setup with empty home.""" home_id = "91763b24c43d3e344f424e8c" with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", fake_post_request, ): await async_account.async_update_status(home_id) assert home_id in async_account.homes home = async_account.homes[home_id] assert len(home.rooms) == 0 jabesq-org-pyatmo-6216472/tests/test_energy.py000066400000000000000000000115221466116727400213330ustar00rootroot00000000000000"""Define tests for energy module.""" import datetime as dt import json from unittest.mock import AsyncMock, patch from pyatmo import ApiHomeReachabilityError, DeviceType from pyatmo.modules.module import EnergyHistoryMixin, MeasureInterval import pytest import time_machine from tests.common import MockResponse # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_energy_NLPC(async_home): # pylint: disable=invalid-name """Test Legrand / BTicino connected energy meter module.""" module_id = "12:34:56:00:00:a1:4c:da" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NLPC assert module.power == 476 @time_machine.travel(dt.datetime(2022, 2, 12, 7, 59, 49)) @pytest.mark.asyncio async def test_historical_data_retrieval(async_account): """Test retrieval of historical measurements.""" home_id = "91763b24c43d3e344f424e8b" await async_account.async_update_events(home_id=home_id) home = async_account.homes[home_id] module_id = "12:34:56:00:00:a1:4c:da" assert module_id in home.modules module = home.modules[module_id] assert module.device_type == DeviceType.NLPC await async_account.async_update_measures(home_id=home_id, module_id=module_id) # changed the reference here as start and stop data was not calculated in the spirit of the netatmo api where their time data is in the fact representing the "middle" of the range and not the begining assert module.historical_data[0] == { "Wh": 197, "duration": 60, "endTime": "2022-02-05T08:59:49Z", "endTimeUnix": 1644051589, "energyMode": ["basic"], "WhPerModes": [197], "startTime": "2022-02-05T07:59:50Z", "startTimeUnix": 1644047989, } assert module.historical_data[-1] == { "Wh": 259, "duration": 60, "endTime": "2022-02-12T07:59:49Z", "endTimeUnix": 1644652789, "energyMode": ["basic"], "WhPerModes": [259], "startTime": "2022-02-12T06:59:50Z", "startTimeUnix": 1644649189, } assert len(module.historical_data) == 168 @time_machine.travel(dt.datetime(2024, 7, 24, 22, 00, 10)) @pytest.mark.asyncio async def test_historical_data_retrieval_multi(async_account_multi): """Test retrieval of historical measurements.""" home_id = "aaaaaaaaaaabbbbbbbbbbccc" home = async_account_multi.homes[home_id] module_id = "98:76:54:32:10:00:00:69" assert module_id in home.modules module = home.modules[module_id] assert module.device_type == DeviceType.NLPC strt = int(dt.datetime.fromisoformat("2024-07-24 00:00:00").timestamp()) end_time = int(dt.datetime.fromisoformat("2024-07-24 22:27:00").timestamp()) await async_account_multi.async_update_measures( home_id=home_id, module_id=module_id, interval=MeasureInterval.HALF_HOUR, start_time=strt, end_time=end_time, ) assert isinstance(module, EnergyHistoryMixin) assert module.historical_data[0] == { "Wh": 20, "duration": 30, "endTime": "2024-07-23T22:30:00Z", "endTimeUnix": 1721773800, "energyMode": ["basic"], "WhPerModes": [20], "startTime": "2024-07-23T22:00:01Z", "startTimeUnix": 1721772000, } assert module.historical_data[17] == { "Wh": 710, "WhPerModes": [498, 212], "duration": 30, "endTime": "2024-07-24T07:00:00Z", "endTimeUnix": 1721804400, "energyMode": ["basic", "peak"], "startTime": "2024-07-24T06:30:01Z", "startTimeUnix": 1721802600, } assert module.historical_data[-1] == { "Wh": 16, "WhPerModes": [16], "duration": 30, "endTime": "2024-07-24T17:30:00Z", "endTimeUnix": 1721842200, "energyMode": ["peak"], "startTime": "2024-07-24T17:00:01Z", "startTimeUnix": 1721840400, } assert len(module.historical_data) == 39 assert module.sum_energy_elec == 17547 assert module.sum_energy_elec_off_peak == 4290 assert module.sum_energy_elec_peak == 10177 async def test_disconnected_main_bridge(async_account_multi): """Test retrieval of historical measurements.""" home_id = "aaaaaaaaaaabbbbbbbbbbccc" with open( "fixtures/home_multi_status_error_disconnected.json", encoding="utf-8", ) as json_file: home_status_fixture = json.load(json_file) mock_home_status_resp = MockResponse(home_status_fixture, 200) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=mock_home_status_resp), ) as mock_request: try: await async_account_multi.async_update_status(home_id) except ApiHomeReachabilityError: pass # expected error else: assert False jabesq-org-pyatmo-6216472/tests/test_fan.py000066400000000000000000000010451466116727400206050ustar00rootroot00000000000000"""Define tests for fan module.""" from pyatmo import DeviceType import pytest # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_fan_NLLF(async_home): # pylint: disable=invalid-name """Test NLLF Legrand centralized ventilation controller.""" module_id = "12:34:56:00:01:01:01:b1" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NLLF assert module.power == 11 assert module.firmware_revision == 60 assert module.fan_speed == 1 jabesq-org-pyatmo-6216472/tests/test_home.py000066400000000000000000000110621466116727400207710ustar00rootroot00000000000000"""Define tests for home module.""" # import datetime as dt import json from unittest.mock import AsyncMock, patch import pyatmo from pyatmo import DeviceType, NoDevice import pytest from tests.common import MockResponse # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_home(async_home): """Test basic home setup.""" room_id = "3688132631" room = async_home.rooms[room_id] assert room.device_types == { DeviceType.NDB, DeviceType.NACamera, DeviceType.NBR, DeviceType.NIS, DeviceType.NBO, } assert len(async_home.rooms) == 8 assert len(async_home.modules) == 38 assert async_home.modules != room.modules module_id = "12:34:56:10:f1:66" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NDB module_id = "12:34:56:10:b9:0e" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NOC assert async_home.temperature_control_mode == "cooling" @pytest.mark.asyncio async def test_async_home_set_schedule(async_home): """Test home schedule.""" schedule_id = "591b54a2764ff4d50d8b5795" selected_schedule = async_home.get_selected_schedule() assert selected_schedule.entity_id == schedule_id assert async_home.is_valid_schedule(schedule_id) assert not async_home.is_valid_schedule("123") assert async_home.get_hg_temp() == 7 assert async_home.get_away_temp() == 14 @pytest.mark.asyncio async def test_async_home_data_no_body(async_auth): with open("fixtures/homesdata_emtpy_home.json", encoding="utf-8") as fixture_file: json_fixture = json.load(fixture_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=json_fixture), ) as mock_request: climate = pyatmo.AsyncAccount(async_auth) with pytest.raises(NoDevice): await climate.async_update_topology() mock_request.assert_called() @pytest.mark.asyncio async def test_async_set_persons_home(async_account): """Test marking a person being at home.""" home_id = "91763b24c43d3e344f424e8b" home = async_account.homes[home_id] person_ids = [ "91827374-7e04-5298-83ad-a0cb8372dff1", "91827375-7e04-5298-83ae-a0cb8372dff2", ] with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_resp: await home.async_set_persons_home(person_ids) mock_resp.assert_awaited_with( params={"home_id": home_id, "person_ids[]": person_ids}, endpoint="api/setpersonshome", ) @pytest.mark.asyncio async def test_async_set_persons_away(async_account): """Test marking a set of persons being away.""" home_id = "91763b24c43d3e344f424e8b" home = async_account.homes[home_id] with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_resp: person_id = "91827374-7e04-5298-83ad-a0cb8372dff1" await home.async_set_persons_away(person_id) mock_resp.assert_awaited_with( params={"home_id": home_id, "person_id": person_id}, endpoint="api/setpersonsaway", ) await home.async_set_persons_away() mock_resp.assert_awaited_with( params={"home_id": home_id}, endpoint="api/setpersonsaway", ) @pytest.mark.asyncio async def test_home_event_update(async_account): """Test basic event update.""" home_id = "91763b24c43d3e344f424e8b" await async_account.async_update_events(home_id=home_id) home = async_account.homes[home_id] events = home.events assert len(events) == 8 module_id = "12:34:56:10:b9:0e" assert module_id in home.modules module = home.modules[module_id] events = module.events assert len(events) == 5 assert events[0].event_type == "outdoor" assert events[0].video_id == "11111111-2222-3333-4444-b42f0fc4cfad" assert events[1].event_type == "connection" def test_device_types_missing(): """Test handling of missing device types.""" assert DeviceType("NOC") == DeviceType.NOC assert DeviceType("UNKNOWN") == DeviceType.NLunknown jabesq-org-pyatmo-6216472/tests/test_shutter.py000066400000000000000000000063221466116727400215420ustar00rootroot00000000000000"""Define tests for shutter module.""" import json from unittest.mock import AsyncMock, patch from pyatmo import DeviceType import pytest from tests.common import MockResponse # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_shutter_NBR(async_home): # pylint: disable=invalid-name """Test NLP Bubendorf iDiamant roller shutter.""" module_id = "0009999992" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NBR assert module.firmware_revision == 16 assert module.current_position == 0 @pytest.mark.asyncio async def test_async_shutter_NBO(async_home): # pylint: disable=invalid-name """Test NBO Bubendorf iDiamant roller shutter.""" module_id = "0009999993" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NBO assert module.firmware_revision == 22 assert module.current_position == 0 @pytest.mark.asyncio async def test_async_shutters(async_home): """Test basic shutter functionality.""" room_id = "3688132631" assert room_id in async_home.rooms module_id = "0009999992" module = async_home.modules[module_id] assert module.device_type == DeviceType.NBR with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) def gen_json_data(position): return { "json": { "home": { "id": "91763b24c43d3e344f424e8b", "modules": [ { "bridge": "12:34:56:30:d5:d4", "id": module_id, "target_position": position, }, ], }, }, } with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=MockResponse(response, 200)), ) as mock_resp: assert await module.async_open() mock_resp.assert_awaited_with( params=gen_json_data(100), endpoint="api/setstate", ) assert await module.async_close() mock_resp.assert_awaited_with( params=gen_json_data(0), endpoint="api/setstate", ) assert await module.async_stop() mock_resp.assert_awaited_with( params=gen_json_data(-1), endpoint="api/setstate", ) assert await module.async_move_to_preferred_position() mock_resp.assert_awaited_with( params=gen_json_data(-2), endpoint="api/setstate", ) assert await module.async_set_target_position(47) mock_resp.assert_awaited_with( params=gen_json_data(47), endpoint="api/setstate", ) assert await module.async_set_target_position(-10) mock_resp.assert_awaited_with( params=gen_json_data(-1), endpoint="api/setstate", ) assert await module.async_set_target_position(101) mock_resp.assert_awaited_with( params=gen_json_data(100), endpoint="api/setstate", ) jabesq-org-pyatmo-6216472/tests/test_switch.py000066400000000000000000000016741466116727400213520ustar00rootroot00000000000000"""Define tests for switch module.""" from pyatmo import DeviceType import pytest # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_switch_NLP(async_home): # pylint: disable=invalid-name """Test NLP Legrand plug.""" module_id = "12:34:56:80:00:12:ac:f2" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NLP assert module.firmware_revision == 62 assert module.on assert module.power == 0 @pytest.mark.asyncio async def test_async_switch_NLF(async_home): # pylint: disable=invalid-name """Test NLF Legrand dimmer.""" module_id = "00:11:22:33:00:11:45:fe" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NLF assert module.firmware_revision == 57 assert module.on is False assert module.brightness == 63 assert module.power == 0 jabesq-org-pyatmo-6216472/tests/test_weather.py000066400000000000000000000233741466116727400215110ustar00rootroot00000000000000"""Define tests for weaather module.""" import pyatmo from pyatmo import DeviceType from pyatmo.modules.base_class import Location, Place import pytest # pylint: disable=F6401 @pytest.mark.asyncio async def test_async_weather_NAMain(async_home): # pylint: disable=invalid-name """Test Netatmo weather station main module.""" module_id = "12:34:56:80:bb:26" assert module_id in async_home.modules module = async_home.modules[module_id] assert module.device_type == DeviceType.NAMain @pytest.mark.asyncio async def test_async_weather_update(async_account): """Test basic weather station update.""" home_id = "91763b24c43d3e344f424e8b" await async_account.async_update_weather_stations() home = async_account.homes[home_id] module_id = "12:34:56:80:bb:26" assert module_id in home.modules module = home.modules[module_id] assert module.device_type == DeviceType.NAMain assert module.name == "Villa" assert module.modules == [ "12:34:56:80:44:92", "12:34:56:80:7e:18", "12:34:56:80:1c:42", "12:34:56:80:c1:ea", ] assert module.features == { "temperature", "humidity", "co2", "noise", "pressure", "absolute_pressure", "temp_trend", "pressure_trend", "min_temp", "max_temp", "temp_max", "temp_min", "reachable", "wifi_strength", "place", } assert module.firmware_revision == 181 assert module.wifi_strength == 57 assert module.temperature == 21.1 assert module.humidity == 45 assert module.co2 == 1339 assert module.pressure == 1026.8 assert module.noise == 35 assert module.absolute_pressure == 974.5 assert module.place == Place( { "altitude": 329, "city": "Someplace", "country": "FR", "location": Location(longitude=6.1234567, latitude=46.123456), "timezone": "Europe/Paris", }, ) module_id = "12:34:56:80:44:92" assert module_id in home.modules module = home.modules[module_id] assert module.name == "Villa Bedroom" assert module.features == { "temperature", "temp_trend", "min_temp", "max_temp", "temp_max", "temp_min", "reachable", "rf_strength", "co2", "humidity", "battery", "place", } assert module.device_type == DeviceType.NAModule4 assert module.modules is None assert module.firmware_revision == 51 assert module.rf_strength == 67 assert module.temperature == 19.3 assert module.humidity == 53 assert module.battery == 28 module_id = "12:34:56:80:c1:ea" assert module_id in home.modules module = home.modules[module_id] assert module.name == "Villa Rain" assert module.features == { "sum_rain_1", "sum_rain_24", "rain", "reachable", "rf_strength", "battery", "place", } assert module.device_type == DeviceType.NAModule3 assert module.modules is None assert module.firmware_revision == 12 assert module.rf_strength == 79 assert module.rain == 3.7 module_id = "12:34:56:80:1c:42" assert module_id in home.modules module = home.modules[module_id] assert module.name == "Villa Outdoor" assert module.features == { "temperature", "humidity", "temp_trend", "min_temp", "max_temp", "temp_max", "temp_min", "reachable", "rf_strength", "battery", "place", } assert module.device_type == DeviceType.NAModule1 assert module.modules is None assert module.firmware_revision == 50 assert module.rf_strength == 68 assert module.reachable is False module_id = "12:34:56:03:1b:e4" assert module_id in home.modules module = home.modules[module_id] assert module.name == "Villa Garden" assert module.features == { "wind_strength", "gust_strength", "gust_angle", "gust_direction", "wind_angle", "wind_direction", "reachable", "rf_strength", "battery", "place", } assert module.device_type == DeviceType.NAModule2 assert module.modules is None assert module.firmware_revision == 19 assert module.rf_strength == 59 assert module.wind_strength == 4 assert module.wind_angle == 217 assert module.gust_strength == 9 assert module.gust_angle == 206 @pytest.mark.asyncio async def test_async_weather_favorite(async_account): """Test favorite weather station.""" await async_account.async_update_weather_stations() module_id = "00:11:22:2c:be:c8" assert module_id in async_account.modules module = async_account.modules[module_id] assert module.device_type == DeviceType.NAMain assert module.name == "Zuhause (Kinderzimmer)" assert module.modules == ["00:11:22:2c:ce:b6"] assert module.features == { "temperature", "humidity", "co2", "noise", "pressure", "absolute_pressure", "temp_trend", "pressure_trend", "min_temp", "max_temp", "temp_max", "temp_min", "reachable", "wifi_strength", "place", } assert module.pressure == 1015.6 assert module.absolute_pressure == 1000.4 assert module.place == Place( { "altitude": 127, "city": "Wiesbaden", "country": "DE", "location": Location( longitude=8.238054275512695, latitude=50.07585525512695, ), "timezone": "Europe/Berlin", }, ) module_id = "00:11:22:2c:ce:b6" assert module_id in async_account.modules module = async_account.modules[module_id] assert module.device_type == DeviceType.NAModule1 assert module.name == "Unknown" assert module.modules is None assert module.features == { "temperature", "humidity", "temp_trend", "min_temp", "max_temp", "temp_max", "temp_min", "reachable", "rf_strength", "battery", "place", } assert module.temperature == 7.8 assert module.humidity == 87 @pytest.mark.asyncio async def test_async_air_care_update(async_account): """Test basic air care update.""" await async_account.async_update_air_care() module_id = "12:34:56:26:68:92" assert module_id in async_account.modules module = async_account.modules[module_id] assert module.device_type == DeviceType.NHC assert module.name == "Baby Bedroom" assert module.features == { "temperature", "humidity", "co2", "noise", "pressure", "absolute_pressure", "temp_trend", "pressure_trend", "min_temp", "max_temp", "temp_max", "temp_min", "health_idx", "reachable", "wifi_strength", "place", } assert module.modules is None assert module.firmware_revision == 45 assert module.wifi_strength == 68 assert module.temperature == 21.6 assert module.humidity == 66 assert module.co2 == 1053 assert module.pressure == 1021.4 assert module.noise == 45 assert module.absolute_pressure == 1011 assert module.health_idx == 1 @pytest.mark.asyncio async def test_async_public_weather_update(async_account): """Test basic public weather update.""" lon_ne = "6.221652" lat_ne = "46.610870" lon_sw = "6.217828" lat_sw = "46.596485" area_id = async_account.register_public_weather_area(lat_ne, lon_ne, lat_sw, lon_sw) await async_account.async_update_public_weather(area_id) area = async_account.public_weather_areas[area_id] assert area.location == pyatmo.modules.netatmo.Location( lat_ne, lon_ne, lat_sw, lon_sw, ) assert area.stations_in_area() == 8 assert area.get_latest_rain() == { "70:ee:50:1f:68:9e": 0, "70:ee:50:27:25:b0": 0, "70:ee:50:36:94:7c": 0.5, "70:ee:50:36:a9:fc": 0, } assert area.get_60_min_rain() == { "70:ee:50:1f:68:9e": 0, "70:ee:50:27:25:b0": 0, "70:ee:50:36:94:7c": 0.2, "70:ee:50:36:a9:fc": 0, } assert area.get_24_h_rain() == { "70:ee:50:1f:68:9e": 9.999, "70:ee:50:27:25:b0": 11.716000000000001, "70:ee:50:36:94:7c": 12.322000000000001, "70:ee:50:36:a9:fc": 11.009, } assert area.get_latest_pressures() == { "70:ee:50:1f:68:9e": 1007.3, "70:ee:50:27:25:b0": 1012.8, "70:ee:50:36:94:7c": 1010.6, "70:ee:50:36:a9:fc": 1010, "70:ee:50:01:20:fa": 1014.4, "70:ee:50:04:ed:7a": 1005.4, "70:ee:50:27:9f:2c": 1010.6, "70:ee:50:3c:02:78": 1011.7, } assert area.get_latest_temperatures() == { "70:ee:50:1f:68:9e": 21.1, "70:ee:50:27:25:b0": 23.2, "70:ee:50:36:94:7c": 21.4, "70:ee:50:36:a9:fc": 20.1, "70:ee:50:01:20:fa": 27.4, "70:ee:50:04:ed:7a": 19.8, "70:ee:50:27:9f:2c": 25.5, "70:ee:50:3c:02:78": 23.3, } assert area.get_latest_humidities() == { "70:ee:50:1f:68:9e": 69, "70:ee:50:27:25:b0": 60, "70:ee:50:36:94:7c": 62, "70:ee:50:36:a9:fc": 67, "70:ee:50:01:20:fa": 58, "70:ee:50:04:ed:7a": 76, "70:ee:50:27:9f:2c": 56, "70:ee:50:3c:02:78": 58, } assert area.get_latest_wind_strengths() == {"70:ee:50:36:a9:fc": 15} assert area.get_latest_wind_angles() == {"70:ee:50:36:a9:fc": 17} assert area.get_latest_gust_strengths() == {"70:ee:50:36:a9:fc": 31} assert area.get_latest_gust_angles() == {"70:ee:50:36:a9:fc": 217} jabesq-org-pyatmo-6216472/tests/testing_main_template.py000066400000000000000000000020061466116727400233540ustar00rootroot00000000000000import asyncio from aiohttp import ClientSession import pyatmo from pyatmo.auth import AbstractAsyncAuth from pyatmo.modules.module import MeasureInterval MY_TOKEN_FROM_NETATMO = "MY_TOKEN" class MyAuth(AbstractAsyncAuth): async def async_get_access_token(self): return MY_TOKEN_FROM_NETATMO async def main(): session = ClientSession() async_auth = MyAuth(session) account = pyatmo.AsyncAccount(async_auth) t = asyncio.create_task(account.async_update_topology()) home_id = "MY_HOME_ID" module_id = "MY_MODULE_ID" await asyncio.gather(t) await account.async_update_status(home_id=home_id) strt = 1709766000 + 10 * 60 # 1709421000+15*60 end = 1709852400 + 10 * 60 await account.async_update_measures( home_id=home_id, module_id=module_id, interval=MeasureInterval.HALF_HOUR, start_time=strt, end_time=end, ) # print(account) if __name__ == "__main__": topology = asyncio.run(main()) # print(topology) jabesq-org-pyatmo-6216472/tox.ini000066400000000000000000000011111466116727400165730ustar00rootroot00000000000000[tox] envlist = py310,py311 isolated_build = True skip_missing_interpreters = True [gh-actions] python = 3.10: py310 3.11: py311 [testenv] deps = pytest pytest-cov pytest-mock pytest-asyncio requests-mock time-machine setenv = COVERAGE_FILE = {envlogdir}/.coverage commands = python -m pytest --cov {envsitepackagesdir}/pyatmo {posargs} [coverage:paths] source = pyatmo .tox/*/lib/python*/site-packages/pyatmo [coverage:run] branch = True omit = */__main__.py source = pyatmo [coverage:report] show_missing = True precision = 2