aioafero 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aioafero-2.0.0/.coveragerc +27 -0
- aioafero-2.0.0/.github/workflows/cicd.yaml +43 -0
- aioafero-2.0.0/.github/workflows/release.yaml +47 -0
- aioafero-2.0.0/.gitignore +54 -0
- aioafero-2.0.0/.pre-commit-config.yaml +32 -0
- aioafero-2.0.0/.readthedocs.yml +27 -0
- aioafero-2.0.0/CHANGELOG.rst +175 -0
- aioafero-2.0.0/LICENSE.txt +21 -0
- aioafero-2.0.0/PKG-INFO +161 -0
- aioafero-2.0.0/README.rst +110 -0
- aioafero-2.0.0/docs/Makefile +29 -0
- aioafero-2.0.0/docs/_static/.gitignore +1 -0
- aioafero-2.0.0/docs/authors.rst +2 -0
- aioafero-2.0.0/docs/changelog.rst +2 -0
- aioafero-2.0.0/docs/conf.py +283 -0
- aioafero-2.0.0/docs/index.rst +29 -0
- aioafero-2.0.0/docs/license.rst +7 -0
- aioafero-2.0.0/docs/readme.rst +2 -0
- aioafero-2.0.0/docs/requirements.txt +5 -0
- aioafero-2.0.0/pyproject.toml +55 -0
- aioafero-2.0.0/setup.cfg +5 -0
- aioafero-2.0.0/sonar-project.properties +6 -0
- aioafero-2.0.0/src/aioafero/__init__.py +31 -0
- aioafero-2.0.0/src/aioafero/anonomyize_data.py +82 -0
- aioafero-2.0.0/src/aioafero/device.py +143 -0
- aioafero-2.0.0/src/aioafero/errors.py +22 -0
- aioafero-2.0.0/src/aioafero/types.py +13 -0
- aioafero-2.0.0/src/aioafero/util.py +69 -0
- aioafero-2.0.0/src/aioafero/v1/__init__.py +327 -0
- aioafero-2.0.0/src/aioafero/v1/auth.py +360 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/__init__.py +0 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/base.py +387 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/device.py +140 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/event.py +275 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/fan.py +170 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/light.py +280 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/lock.py +86 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/switch.py +103 -0
- aioafero-2.0.0/src/aioafero/v1/controllers/valve.py +100 -0
- aioafero-2.0.0/src/aioafero/v1/models/__init__.py +21 -0
- aioafero-2.0.0/src/aioafero/v1/models/device.py +18 -0
- aioafero-2.0.0/src/aioafero/v1/models/fan.py +94 -0
- aioafero-2.0.0/src/aioafero/v1/models/features.py +220 -0
- aioafero-2.0.0/src/aioafero/v1/models/light.py +91 -0
- aioafero-2.0.0/src/aioafero/v1/models/lock.py +42 -0
- aioafero-2.0.0/src/aioafero/v1/models/resource.py +43 -0
- aioafero-2.0.0/src/aioafero/v1/models/sensor.py +42 -0
- aioafero-2.0.0/src/aioafero/v1/models/switch.py +42 -0
- aioafero-2.0.0/src/aioafero/v1/models/valve.py +42 -0
- aioafero-2.0.0/src/aioafero/v1/v1_const.py +51 -0
- aioafero-2.0.0/tests/__init__.py +0 -0
- aioafero-2.0.0/tests/conftest.py +82 -0
- aioafero-2.0.0/tests/test_anonymize_data.py +370 -0
- aioafero-2.0.0/tests/test_device.py +558 -0
- aioafero-2.0.0/tests/test_util.py +46 -0
- aioafero-2.0.0/tests/v1/__init__.py +0 -0
- aioafero-2.0.0/tests/v1/controllers/__init__.py +0 -0
- aioafero-2.0.0/tests/v1/controllers/test_base.py +801 -0
- aioafero-2.0.0/tests/v1/controllers/test_device.py +257 -0
- aioafero-2.0.0/tests/v1/controllers/test_event.py +581 -0
- aioafero-2.0.0/tests/v1/controllers/test_fan.py +333 -0
- aioafero-2.0.0/tests/v1/controllers/test_light.py +743 -0
- aioafero-2.0.0/tests/v1/controllers/test_lock.py +158 -0
- aioafero-2.0.0/tests/v1/controllers/test_switch.py +320 -0
- aioafero-2.0.0/tests/v1/controllers/test_valve.py +205 -0
- aioafero-2.0.0/tests/v1/data/auth_webapp_login.html +166 -0
- aioafero-2.0.0/tests/v1/data/auth_webapp_login_bad_format.html +166 -0
- aioafero-2.0.0/tests/v1/data/auth_webapp_login_bad_qs.html +166 -0
- aioafero-2.0.0/tests/v1/data/auth_webapp_login_missing.html +166 -0
- aioafero-2.0.0/tests/v1/data/device_lock.json +1574 -0
- aioafero-2.0.0/tests/v1/data/raw_hs_data.json +3268 -0
- aioafero-2.0.0/tests/v1/data/water-timer-raw.json +1002 -0
- aioafero-2.0.0/tests/v1/device_dumps/dimmer-HPDA1110NWBP.json +566 -0
- aioafero-2.0.0/tests/v1/device_dumps/door-lock-TBD.json +3166 -0
- aioafero-2.0.0/tests/v1/device_dumps/fan-ZandraFan.json +916 -0
- aioafero-2.0.0/tests/v1/device_dumps/freezer.json +619 -0
- aioafero-2.0.0/tests/v1/device_dumps/glass-door.json +360 -0
- aioafero-2.0.0/tests/v1/device_dumps/light-a21.json +775 -0
- aioafero-2.0.0/tests/v1/device_dumps/light-rgb_temp.json +777 -0
- aioafero-2.0.0/tests/v1/device_dumps/power-outlet-HPPA11CWB.json +498 -0
- aioafero-2.0.0/tests/v1/device_dumps/rgbw-led-strip.json +582 -0
- aioafero-2.0.0/tests/v1/device_dumps/switch-HPDA311CWB.json +1400 -0
- aioafero-2.0.0/tests/v1/device_dumps/transformer.json +538 -0
- aioafero-2.0.0/tests/v1/device_dumps/water-timer.json +966 -0
- aioafero-2.0.0/tests/v1/models/__init__.py +0 -0
- aioafero-2.0.0/tests/v1/models/test_fan.py +121 -0
- aioafero-2.0.0/tests/v1/models/test_features.py +142 -0
- aioafero-2.0.0/tests/v1/models/test_light.py +91 -0
- aioafero-2.0.0/tests/v1/models/test_lock.py +32 -0
- aioafero-2.0.0/tests/v1/models/test_resources.py +5 -0
- aioafero-2.0.0/tests/v1/models/test_sensor.py +24 -0
- aioafero-2.0.0/tests/v1/models/test_switch.py +55 -0
- aioafero-2.0.0/tests/v1/models/test_valve.py +55 -0
- aioafero-2.0.0/tests/v1/test___init__.py +169 -0
- aioafero-2.0.0/tests/v1/test_auth.py +348 -0
- aioafero-2.0.0/tests/v1/utils.py +80 -0
- aioafero-2.0.0/tox.ini +97 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# .coveragerc to control coverage.py
|
|
2
|
+
[run]
|
|
3
|
+
branch = True
|
|
4
|
+
source = aioafero
|
|
5
|
+
|
|
6
|
+
[paths]
|
|
7
|
+
source =
|
|
8
|
+
src/
|
|
9
|
+
*/site-packages/
|
|
10
|
+
|
|
11
|
+
[report]
|
|
12
|
+
# Regexes for lines to exclude from consideration
|
|
13
|
+
exclude_lines =
|
|
14
|
+
# Have to re-enable the standard pragma
|
|
15
|
+
pragma: no cover
|
|
16
|
+
|
|
17
|
+
# Don't complain about missing debug-only code:
|
|
18
|
+
def __repr__
|
|
19
|
+
if self\.debug
|
|
20
|
+
|
|
21
|
+
# Don't complain if tests don't hit defensive assertion code:
|
|
22
|
+
raise AssertionError
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
# Don't complain if non-runnable code isn't run:
|
|
26
|
+
if 0:
|
|
27
|
+
if __name__ == .__main__.:
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Execute tests and linting
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
run_tests:
|
|
12
|
+
runs-on: "ubuntu-latest"
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
- name: Install requirements
|
|
24
|
+
run: |
|
|
25
|
+
pip install .[test]
|
|
26
|
+
- name: Execute Tests
|
|
27
|
+
run: |
|
|
28
|
+
python -m pytest --cov --cov-branch --cov-report=xml --junitxml=junit.xml -o junit_family=legacy
|
|
29
|
+
- name: Execute linting
|
|
30
|
+
if: matrix.python-version == '3.12'
|
|
31
|
+
run: |
|
|
32
|
+
pip install pre-commit
|
|
33
|
+
pre-commit run --all-files
|
|
34
|
+
- name: Upload coverage reports to Codecov
|
|
35
|
+
if: matrix.python-version == '3.13'
|
|
36
|
+
uses: codecov/codecov-action@v5
|
|
37
|
+
with:
|
|
38
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
39
|
+
- name: Upload test results to Codecov
|
|
40
|
+
if: ${{ !cancelled() }} && matrix.python-version == '3.13'
|
|
41
|
+
uses: codecov/test-results-action@v1
|
|
42
|
+
with:
|
|
43
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
run_tests:
|
|
8
|
+
runs-on: "ubuntu-latest"
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
python-version: ["3.12", "3.13"]
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- name: Install requirements
|
|
20
|
+
run: |
|
|
21
|
+
pip install .[test]
|
|
22
|
+
- name: Execute Tests
|
|
23
|
+
run: |
|
|
24
|
+
python -m pytest
|
|
25
|
+
- name: Execute linting
|
|
26
|
+
if: matrix.python-version == '3.12'
|
|
27
|
+
run: |
|
|
28
|
+
pip install pre-commit
|
|
29
|
+
pre-commit run --all-files
|
|
30
|
+
|
|
31
|
+
pypi-publish:
|
|
32
|
+
needs: [run_tests]
|
|
33
|
+
name: upload release to PyPI
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
if: github.ref_name == github.event.repository.default_branch
|
|
36
|
+
permissions:
|
|
37
|
+
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
38
|
+
id-token: write
|
|
39
|
+
steps:
|
|
40
|
+
- name: Checkout repo
|
|
41
|
+
uses: actions/checkout@v4
|
|
42
|
+
- name: Create files
|
|
43
|
+
run: |
|
|
44
|
+
pip install tox
|
|
45
|
+
tox -e build
|
|
46
|
+
- name: Publish package distributions to PyPI
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Temporary and binary files
|
|
2
|
+
*~
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
*.cfg
|
|
6
|
+
!.isort.cfg
|
|
7
|
+
!setup.cfg
|
|
8
|
+
*.orig
|
|
9
|
+
*.log
|
|
10
|
+
*.pot
|
|
11
|
+
__pycache__/*
|
|
12
|
+
.cache/*
|
|
13
|
+
.*.swp
|
|
14
|
+
*/.ipynb_checkpoints/*
|
|
15
|
+
.DS_Store
|
|
16
|
+
|
|
17
|
+
# Project files
|
|
18
|
+
.ropeproject
|
|
19
|
+
.project
|
|
20
|
+
.pydevproject
|
|
21
|
+
.settings
|
|
22
|
+
.idea
|
|
23
|
+
.vscode
|
|
24
|
+
tags
|
|
25
|
+
|
|
26
|
+
# Package files
|
|
27
|
+
*.egg
|
|
28
|
+
*.eggs/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg-info
|
|
31
|
+
|
|
32
|
+
# Unittest and coverage
|
|
33
|
+
htmlcov/*
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
.tox
|
|
37
|
+
junit*.xml
|
|
38
|
+
coverage.xml
|
|
39
|
+
.pytest_cache/
|
|
40
|
+
|
|
41
|
+
# Build and docs folder/files
|
|
42
|
+
build/*
|
|
43
|
+
dist/*
|
|
44
|
+
sdist/*
|
|
45
|
+
docs/api/*
|
|
46
|
+
docs/_rst/*
|
|
47
|
+
docs/_build/*
|
|
48
|
+
cover/*
|
|
49
|
+
MANIFEST
|
|
50
|
+
|
|
51
|
+
# Per-project virtualenvs
|
|
52
|
+
.venv*/
|
|
53
|
+
.conda*/
|
|
54
|
+
.python-version
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
default_language_version:
|
|
2
|
+
python: python3
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/jorisroovers/gitlint.git
|
|
5
|
+
rev: v0.19.1
|
|
6
|
+
hooks:
|
|
7
|
+
- id: gitlint
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/ambv/black.git
|
|
10
|
+
rev: 24.4.2
|
|
11
|
+
hooks:
|
|
12
|
+
- id: black
|
|
13
|
+
language_version: python3
|
|
14
|
+
|
|
15
|
+
- repo: https://github.com/PyCQA/flake8.git
|
|
16
|
+
rev: 7.1.0
|
|
17
|
+
hooks:
|
|
18
|
+
- id: flake8
|
|
19
|
+
additional_dependencies: [flake8-bugbear, "importlib-metadata<5.0"]
|
|
20
|
+
|
|
21
|
+
- repo: https://github.com/pycqa/isort.git
|
|
22
|
+
rev: 5.13.2
|
|
23
|
+
hooks:
|
|
24
|
+
- id: isort
|
|
25
|
+
args: ["--profile", "black"]
|
|
26
|
+
|
|
27
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks.git
|
|
28
|
+
rev: v4.6.0
|
|
29
|
+
hooks:
|
|
30
|
+
- id: trailing-whitespace
|
|
31
|
+
- id: end-of-file-fixer
|
|
32
|
+
- id: debug-statements
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Read the Docs configuration file
|
|
2
|
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
3
|
+
|
|
4
|
+
# Required
|
|
5
|
+
version: 2
|
|
6
|
+
|
|
7
|
+
# Build documentation in the docs/ directory with Sphinx
|
|
8
|
+
sphinx:
|
|
9
|
+
configuration: docs/conf.py
|
|
10
|
+
|
|
11
|
+
# Build documentation with MkDocs
|
|
12
|
+
#mkdocs:
|
|
13
|
+
# configuration: mkdocs.yml
|
|
14
|
+
|
|
15
|
+
# Optionally build your docs in additional formats such as PDF
|
|
16
|
+
formats:
|
|
17
|
+
- pdf
|
|
18
|
+
|
|
19
|
+
build:
|
|
20
|
+
os: ubuntu-22.04
|
|
21
|
+
tools:
|
|
22
|
+
python: "3.11"
|
|
23
|
+
|
|
24
|
+
python:
|
|
25
|
+
install:
|
|
26
|
+
- requirements: docs/requirements.txt
|
|
27
|
+
- {path: ., method: pip}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
=========
|
|
2
|
+
Changelog
|
|
3
|
+
=========
|
|
4
|
+
|
|
5
|
+
Version 2.0.0
|
|
6
|
+
=============
|
|
7
|
+
|
|
8
|
+
* Migration from aiohubspace to aioafero to support the Aefro IoT Cloud
|
|
9
|
+
|
|
10
|
+
Version 1.2.0
|
|
11
|
+
=============
|
|
12
|
+
|
|
13
|
+
* Enable auth to re-use a previously generated token
|
|
14
|
+
|
|
15
|
+
Version 1.1.3
|
|
16
|
+
=============
|
|
17
|
+
|
|
18
|
+
* Fix an issue where devices could be properly identified
|
|
19
|
+
|
|
20
|
+
Version 1.1.2
|
|
21
|
+
=============
|
|
22
|
+
|
|
23
|
+
* Fix an issue where water valves were showing as fans
|
|
24
|
+
|
|
25
|
+
Version 1.1.1
|
|
26
|
+
=============
|
|
27
|
+
|
|
28
|
+
* Fix an issue where 500's could stop polling
|
|
29
|
+
|
|
30
|
+
Version 1.1.0
|
|
31
|
+
=============
|
|
32
|
+
|
|
33
|
+
* Added an event type for invalid auth during token refresh
|
|
34
|
+
* Added a check to ensure the token is valid during refresh time. If invalid,
|
|
35
|
+
the event invalid_auth is emitted.
|
|
36
|
+
|
|
37
|
+
Version 1.0.4
|
|
38
|
+
=============
|
|
39
|
+
|
|
40
|
+
* Add additional logging around issues when querying Hubspace API
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Version 1.0.3
|
|
44
|
+
=============
|
|
45
|
+
|
|
46
|
+
* Fixed an issue where a new device could be generated prior to an element
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Version 1.0.2
|
|
50
|
+
=============
|
|
51
|
+
|
|
52
|
+
* Fixed an issue where an updated sensor could use an incorrect value
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
Version 1.0.1
|
|
56
|
+
=============
|
|
57
|
+
|
|
58
|
+
* Fixed an issue where passwords could be logged to debug logs
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
Version 1.0.0
|
|
62
|
+
=============
|
|
63
|
+
|
|
64
|
+
* Solidify API
|
|
65
|
+
* Fix an issue where the loop would break during collection
|
|
66
|
+
* Increase code coverage
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
Version 0.7.0
|
|
70
|
+
=============
|
|
71
|
+
|
|
72
|
+
* Add support for glass-doors
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
Version 0.6.4
|
|
76
|
+
=============
|
|
77
|
+
|
|
78
|
+
* Fix an issue where locks were not being managed by LockController
|
|
79
|
+
* Fix an issue with Fans not correctly setting presets
|
|
80
|
+
* Less greedy updates - Only forward updates if something has changed
|
|
81
|
+
on the resource
|
|
82
|
+
* Create additional unit tests to ensure functionality
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
Version 0.6.3
|
|
86
|
+
=============
|
|
87
|
+
|
|
88
|
+
* Fix an issue with Binary sensors to ensure the state is obvious
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
Version 0.6.2
|
|
92
|
+
=============
|
|
93
|
+
|
|
94
|
+
* Fix an issue with fan's preset not correctly identifying its state
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
Version 0.6.1
|
|
98
|
+
=============
|
|
99
|
+
|
|
100
|
+
* Fix an issue with binary sensors to ensure they return True / False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
Version 0.6.0
|
|
104
|
+
=============
|
|
105
|
+
|
|
106
|
+
* Add the ability to send raw states to Hubspace and have the tracked device update
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
Version 0.5.1
|
|
110
|
+
=============
|
|
111
|
+
|
|
112
|
+
* Fixed an issue where the account ID wouldnt be set during a partial initialization
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
Version 0.5.0
|
|
116
|
+
=============
|
|
117
|
+
|
|
118
|
+
* Only emit updates to subscribers if values have changed
|
|
119
|
+
* Fixed an issue where the logger was always in debug
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
Version 0.4.1
|
|
123
|
+
=============
|
|
124
|
+
|
|
125
|
+
* Adjusted logic for how HubspaceDevice modified models
|
|
126
|
+
* Fixed an issue around Device initialization
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Version 0.4.0
|
|
130
|
+
=============
|
|
131
|
+
|
|
132
|
+
* Added tracking for BLE and MAC addresses
|
|
133
|
+
* Added binary sensors
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
Version 0.3.7
|
|
137
|
+
=============
|
|
138
|
+
|
|
139
|
+
* Fixed an issue around subscribers with deletion
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
Version 0.3.6
|
|
143
|
+
=============
|
|
144
|
+
|
|
145
|
+
* Fixed an issue around switches not properly subscribing to updates
|
|
146
|
+
* Fixed an issue where Hubspace could return a session reauth token when preparing a new session
|
|
147
|
+
* Added models for HPSA11CWB and HPDA110NWBP
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
Version 0.3.0
|
|
151
|
+
=============
|
|
152
|
+
|
|
153
|
+
* Fixed an issue around subscribers with deletion
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
Version 0.2
|
|
158
|
+
===========
|
|
159
|
+
|
|
160
|
+
* Added support for Binary Sensors
|
|
161
|
+
* Fixed an issue where a dimmer switch could not be dimmed
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
Version 0.2
|
|
165
|
+
===========
|
|
166
|
+
|
|
167
|
+
* Added support for Sensors
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
Version 0.1
|
|
171
|
+
===========
|
|
172
|
+
|
|
173
|
+
* Initial implementation
|
|
174
|
+
* Rename from hubspace_async to aiohubspace
|
|
175
|
+
* Utilize the concept of a bridge instead of raw connection
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Chris Dohmen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aioafero-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aioafero
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Talk to the Hubspace API asynchronously
|
|
5
|
+
Project-URL: Repository, https://github.com/Expl0dingBanana/aioafero
|
|
6
|
+
Project-URL: Changelog, https://github.com/Expl0dingBanana/aioafero/CHANGELOG.md
|
|
7
|
+
Author-email: Chris Dohmen <chris.dohmen11@gmail.com>
|
|
8
|
+
Maintainer: tpural
|
|
9
|
+
Maintainer-email: Chris Dohmen <chris.dohmen11@gmail.com>
|
|
10
|
+
License: The MIT License (MIT)
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2024 Chris Dohmen
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE.txt
|
|
32
|
+
Keywords: Hubspace
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Programming Language :: Python
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Requires-Python: >=3.12
|
|
38
|
+
Requires-Dist: aiohttp
|
|
39
|
+
Requires-Dist: beautifulsoup4
|
|
40
|
+
Provides-Extra: cli
|
|
41
|
+
Requires-Dist: click; extra == 'cli'
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: aioresponses; extra == 'test'
|
|
44
|
+
Requires-Dist: anyio; extra == 'test'
|
|
45
|
+
Requires-Dist: pytest; extra == 'test'
|
|
46
|
+
Requires-Dist: pytest-aioresponses; extra == 'test'
|
|
47
|
+
Requires-Dist: pytest-asyncio; extra == 'test'
|
|
48
|
+
Requires-Dist: pytest-cov; extra == 'test'
|
|
49
|
+
Requires-Dist: pytest-mock; extra == 'test'
|
|
50
|
+
Description-Content-Type: text/x-rst
|
|
51
|
+
|
|
52
|
+
========
|
|
53
|
+
aioafero
|
|
54
|
+
========
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
Connects to Afero cloud API and provides an easy way to interact
|
|
58
|
+
with devices.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
This project was designed to asynchronously connect to the Afero IOT API. It
|
|
62
|
+
has the ability to retrieve the devices and set new states.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
.. image:: https://github.com/Expl0dingBanana/aioafero/actions/workflows/cicd.yaml/badge.svg?branch=main
|
|
66
|
+
:target: https://github.com/Expl0dingBanana/aioafero/actions/workflows/cicd.yaml
|
|
67
|
+
|
|
68
|
+
.. image:: https://codecov.io/github/Expl0dingBanana/aioafero/graph/badge.svg?token=NP2RE4I4XK
|
|
69
|
+
:target: https://codecov.io/github/Expl0dingBanana/aioafero
|
|
70
|
+
|
|
71
|
+
Overview
|
|
72
|
+
========
|
|
73
|
+
All data is stored within a "bridge" that knows of all of the devices aligned
|
|
74
|
+
with the Afero IOT account. This bridge contains multiple controllers for each
|
|
75
|
+
device type. These controllers know how to interact with the Afero IOT devices.
|
|
76
|
+
Each controller manages the device's states. To retrieve a device, you must
|
|
77
|
+
query ``bridge.<controller>.get_device(<device_id>)`` which will return
|
|
78
|
+
a model containing all the states. Any changes to the model will not
|
|
79
|
+
update Afero IOT as the correct call needs to be made.
|
|
80
|
+
|
|
81
|
+
Controllers
|
|
82
|
+
===========
|
|
83
|
+
|
|
84
|
+
The following controllers are implemented:
|
|
85
|
+
|
|
86
|
+
* ``bridge.devices``: Top-level devices (such as a ceiling-fan, or light that
|
|
87
|
+
is not associated with another device). These entities also contain their
|
|
88
|
+
respective sensors and binary sensors. This is purely an informational
|
|
89
|
+
controller and cannot set any states.
|
|
90
|
+
|
|
91
|
+
* ``bridge.fans``: Any device that matches a fan. Can perform the following
|
|
92
|
+
actions:
|
|
93
|
+
|
|
94
|
+
* turn_on
|
|
95
|
+
* turn_off
|
|
96
|
+
* set_speed
|
|
97
|
+
* set_direction
|
|
98
|
+
* set_preset
|
|
99
|
+
|
|
100
|
+
* ``bridge.lights``: Any device that matches a fan. Can perform the following
|
|
101
|
+
actions:
|
|
102
|
+
|
|
103
|
+
* turn_on
|
|
104
|
+
* turn_off
|
|
105
|
+
* set_color_temperature
|
|
106
|
+
* set_brightness
|
|
107
|
+
* set_rgb
|
|
108
|
+
* set_effect
|
|
109
|
+
|
|
110
|
+
* ``bridge.locks``: Any device that matches a lock. Can perform the following
|
|
111
|
+
actions:
|
|
112
|
+
|
|
113
|
+
* lock
|
|
114
|
+
* unlock
|
|
115
|
+
|
|
116
|
+
* ``bridge.switches``: Any device that matches a switch. Can perform the following
|
|
117
|
+
actions:
|
|
118
|
+
|
|
119
|
+
* turn_on
|
|
120
|
+
* turn_off
|
|
121
|
+
|
|
122
|
+
* ``bridge.valves``: Any device that matches a valves. Can perform the following
|
|
123
|
+
actions:
|
|
124
|
+
|
|
125
|
+
* turn_on
|
|
126
|
+
* turn_off
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Example Usage
|
|
130
|
+
=============
|
|
131
|
+
All examples assume you entered the shell with ``python -m asyncio``
|
|
132
|
+
|
|
133
|
+
.. code-block:: python
|
|
134
|
+
|
|
135
|
+
from aioafero import v1
|
|
136
|
+
import logging
|
|
137
|
+
logging.getLogger("aioafero").setLevel(logging.DEBUG)
|
|
138
|
+
USERNAME="" # Afero IOT username
|
|
139
|
+
PASSWORD="" # Afero IOT password
|
|
140
|
+
POLLING_INTERVAL=30 # Number of seconds between polling cycles
|
|
141
|
+
# Create the bridge
|
|
142
|
+
bridge = v1.AferoBridgeV1(USERNAME, PASSWORD, polling_interval=POLLING_INTERVAL)
|
|
143
|
+
# Query the API and populate the controllers
|
|
144
|
+
await bridge.initialize()
|
|
145
|
+
# Turn on the light that matches id="84338ebe-7ddf-4bfa-9753-3ee8cdcc8da6"
|
|
146
|
+
await conn.lights.turn_off("84338ebe-7ddf-4bfa-9753-3ee8cdcc8da6")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
Troubleshooting
|
|
150
|
+
===============
|
|
151
|
+
|
|
152
|
+
* Device shows incorrect model
|
|
153
|
+
|
|
154
|
+
* Afero IoT does not always report all the pertinent information through the API.
|
|
155
|
+
To resolve this, open a PR to ``src/aioafero/device.py`` and update the dataclass
|
|
156
|
+
``AferoDevice.__post_init__`` function to correctly identify the device.
|
|
157
|
+
|
|
158
|
+
* Afero IoT is slow to update
|
|
159
|
+
|
|
160
|
+
* The API rate-limits request. If other things are hitting the API (such as the phone app
|
|
161
|
+
or Home Assistant), you may need to stop using one to ensure a better connection.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
========
|
|
2
|
+
aioafero
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Connects to Afero cloud API and provides an easy way to interact
|
|
7
|
+
with devices.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
This project was designed to asynchronously connect to the Afero IOT API. It
|
|
11
|
+
has the ability to retrieve the devices and set new states.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
.. image:: https://github.com/Expl0dingBanana/aioafero/actions/workflows/cicd.yaml/badge.svg?branch=main
|
|
15
|
+
:target: https://github.com/Expl0dingBanana/aioafero/actions/workflows/cicd.yaml
|
|
16
|
+
|
|
17
|
+
.. image:: https://codecov.io/github/Expl0dingBanana/aioafero/graph/badge.svg?token=NP2RE4I4XK
|
|
18
|
+
:target: https://codecov.io/github/Expl0dingBanana/aioafero
|
|
19
|
+
|
|
20
|
+
Overview
|
|
21
|
+
========
|
|
22
|
+
All data is stored within a "bridge" that knows of all of the devices aligned
|
|
23
|
+
with the Afero IOT account. This bridge contains multiple controllers for each
|
|
24
|
+
device type. These controllers know how to interact with the Afero IOT devices.
|
|
25
|
+
Each controller manages the device's states. To retrieve a device, you must
|
|
26
|
+
query ``bridge.<controller>.get_device(<device_id>)`` which will return
|
|
27
|
+
a model containing all the states. Any changes to the model will not
|
|
28
|
+
update Afero IOT as the correct call needs to be made.
|
|
29
|
+
|
|
30
|
+
Controllers
|
|
31
|
+
===========
|
|
32
|
+
|
|
33
|
+
The following controllers are implemented:
|
|
34
|
+
|
|
35
|
+
* ``bridge.devices``: Top-level devices (such as a ceiling-fan, or light that
|
|
36
|
+
is not associated with another device). These entities also contain their
|
|
37
|
+
respective sensors and binary sensors. This is purely an informational
|
|
38
|
+
controller and cannot set any states.
|
|
39
|
+
|
|
40
|
+
* ``bridge.fans``: Any device that matches a fan. Can perform the following
|
|
41
|
+
actions:
|
|
42
|
+
|
|
43
|
+
* turn_on
|
|
44
|
+
* turn_off
|
|
45
|
+
* set_speed
|
|
46
|
+
* set_direction
|
|
47
|
+
* set_preset
|
|
48
|
+
|
|
49
|
+
* ``bridge.lights``: Any device that matches a fan. Can perform the following
|
|
50
|
+
actions:
|
|
51
|
+
|
|
52
|
+
* turn_on
|
|
53
|
+
* turn_off
|
|
54
|
+
* set_color_temperature
|
|
55
|
+
* set_brightness
|
|
56
|
+
* set_rgb
|
|
57
|
+
* set_effect
|
|
58
|
+
|
|
59
|
+
* ``bridge.locks``: Any device that matches a lock. Can perform the following
|
|
60
|
+
actions:
|
|
61
|
+
|
|
62
|
+
* lock
|
|
63
|
+
* unlock
|
|
64
|
+
|
|
65
|
+
* ``bridge.switches``: Any device that matches a switch. Can perform the following
|
|
66
|
+
actions:
|
|
67
|
+
|
|
68
|
+
* turn_on
|
|
69
|
+
* turn_off
|
|
70
|
+
|
|
71
|
+
* ``bridge.valves``: Any device that matches a valves. Can perform the following
|
|
72
|
+
actions:
|
|
73
|
+
|
|
74
|
+
* turn_on
|
|
75
|
+
* turn_off
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
Example Usage
|
|
79
|
+
=============
|
|
80
|
+
All examples assume you entered the shell with ``python -m asyncio``
|
|
81
|
+
|
|
82
|
+
.. code-block:: python
|
|
83
|
+
|
|
84
|
+
from aioafero import v1
|
|
85
|
+
import logging
|
|
86
|
+
logging.getLogger("aioafero").setLevel(logging.DEBUG)
|
|
87
|
+
USERNAME="" # Afero IOT username
|
|
88
|
+
PASSWORD="" # Afero IOT password
|
|
89
|
+
POLLING_INTERVAL=30 # Number of seconds between polling cycles
|
|
90
|
+
# Create the bridge
|
|
91
|
+
bridge = v1.AferoBridgeV1(USERNAME, PASSWORD, polling_interval=POLLING_INTERVAL)
|
|
92
|
+
# Query the API and populate the controllers
|
|
93
|
+
await bridge.initialize()
|
|
94
|
+
# Turn on the light that matches id="84338ebe-7ddf-4bfa-9753-3ee8cdcc8da6"
|
|
95
|
+
await conn.lights.turn_off("84338ebe-7ddf-4bfa-9753-3ee8cdcc8da6")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
Troubleshooting
|
|
99
|
+
===============
|
|
100
|
+
|
|
101
|
+
* Device shows incorrect model
|
|
102
|
+
|
|
103
|
+
* Afero IoT does not always report all the pertinent information through the API.
|
|
104
|
+
To resolve this, open a PR to ``src/aioafero/device.py`` and update the dataclass
|
|
105
|
+
``AferoDevice.__post_init__`` function to correctly identify the device.
|
|
106
|
+
|
|
107
|
+
* Afero IoT is slow to update
|
|
108
|
+
|
|
109
|
+
* The API rate-limits request. If other things are hitting the API (such as the phone app
|
|
110
|
+
or Home Assistant), you may need to stop using one to ensure a better connection.
|