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.
Files changed (97) hide show
  1. aioafero-2.0.0/.coveragerc +27 -0
  2. aioafero-2.0.0/.github/workflows/cicd.yaml +43 -0
  3. aioafero-2.0.0/.github/workflows/release.yaml +47 -0
  4. aioafero-2.0.0/.gitignore +54 -0
  5. aioafero-2.0.0/.pre-commit-config.yaml +32 -0
  6. aioafero-2.0.0/.readthedocs.yml +27 -0
  7. aioafero-2.0.0/CHANGELOG.rst +175 -0
  8. aioafero-2.0.0/LICENSE.txt +21 -0
  9. aioafero-2.0.0/PKG-INFO +161 -0
  10. aioafero-2.0.0/README.rst +110 -0
  11. aioafero-2.0.0/docs/Makefile +29 -0
  12. aioafero-2.0.0/docs/_static/.gitignore +1 -0
  13. aioafero-2.0.0/docs/authors.rst +2 -0
  14. aioafero-2.0.0/docs/changelog.rst +2 -0
  15. aioafero-2.0.0/docs/conf.py +283 -0
  16. aioafero-2.0.0/docs/index.rst +29 -0
  17. aioafero-2.0.0/docs/license.rst +7 -0
  18. aioafero-2.0.0/docs/readme.rst +2 -0
  19. aioafero-2.0.0/docs/requirements.txt +5 -0
  20. aioafero-2.0.0/pyproject.toml +55 -0
  21. aioafero-2.0.0/setup.cfg +5 -0
  22. aioafero-2.0.0/sonar-project.properties +6 -0
  23. aioafero-2.0.0/src/aioafero/__init__.py +31 -0
  24. aioafero-2.0.0/src/aioafero/anonomyize_data.py +82 -0
  25. aioafero-2.0.0/src/aioafero/device.py +143 -0
  26. aioafero-2.0.0/src/aioafero/errors.py +22 -0
  27. aioafero-2.0.0/src/aioafero/types.py +13 -0
  28. aioafero-2.0.0/src/aioafero/util.py +69 -0
  29. aioafero-2.0.0/src/aioafero/v1/__init__.py +327 -0
  30. aioafero-2.0.0/src/aioafero/v1/auth.py +360 -0
  31. aioafero-2.0.0/src/aioafero/v1/controllers/__init__.py +0 -0
  32. aioafero-2.0.0/src/aioafero/v1/controllers/base.py +387 -0
  33. aioafero-2.0.0/src/aioafero/v1/controllers/device.py +140 -0
  34. aioafero-2.0.0/src/aioafero/v1/controllers/event.py +275 -0
  35. aioafero-2.0.0/src/aioafero/v1/controllers/fan.py +170 -0
  36. aioafero-2.0.0/src/aioafero/v1/controllers/light.py +280 -0
  37. aioafero-2.0.0/src/aioafero/v1/controllers/lock.py +86 -0
  38. aioafero-2.0.0/src/aioafero/v1/controllers/switch.py +103 -0
  39. aioafero-2.0.0/src/aioafero/v1/controllers/valve.py +100 -0
  40. aioafero-2.0.0/src/aioafero/v1/models/__init__.py +21 -0
  41. aioafero-2.0.0/src/aioafero/v1/models/device.py +18 -0
  42. aioafero-2.0.0/src/aioafero/v1/models/fan.py +94 -0
  43. aioafero-2.0.0/src/aioafero/v1/models/features.py +220 -0
  44. aioafero-2.0.0/src/aioafero/v1/models/light.py +91 -0
  45. aioafero-2.0.0/src/aioafero/v1/models/lock.py +42 -0
  46. aioafero-2.0.0/src/aioafero/v1/models/resource.py +43 -0
  47. aioafero-2.0.0/src/aioafero/v1/models/sensor.py +42 -0
  48. aioafero-2.0.0/src/aioafero/v1/models/switch.py +42 -0
  49. aioafero-2.0.0/src/aioafero/v1/models/valve.py +42 -0
  50. aioafero-2.0.0/src/aioafero/v1/v1_const.py +51 -0
  51. aioafero-2.0.0/tests/__init__.py +0 -0
  52. aioafero-2.0.0/tests/conftest.py +82 -0
  53. aioafero-2.0.0/tests/test_anonymize_data.py +370 -0
  54. aioafero-2.0.0/tests/test_device.py +558 -0
  55. aioafero-2.0.0/tests/test_util.py +46 -0
  56. aioafero-2.0.0/tests/v1/__init__.py +0 -0
  57. aioafero-2.0.0/tests/v1/controllers/__init__.py +0 -0
  58. aioafero-2.0.0/tests/v1/controllers/test_base.py +801 -0
  59. aioafero-2.0.0/tests/v1/controllers/test_device.py +257 -0
  60. aioafero-2.0.0/tests/v1/controllers/test_event.py +581 -0
  61. aioafero-2.0.0/tests/v1/controllers/test_fan.py +333 -0
  62. aioafero-2.0.0/tests/v1/controllers/test_light.py +743 -0
  63. aioafero-2.0.0/tests/v1/controllers/test_lock.py +158 -0
  64. aioafero-2.0.0/tests/v1/controllers/test_switch.py +320 -0
  65. aioafero-2.0.0/tests/v1/controllers/test_valve.py +205 -0
  66. aioafero-2.0.0/tests/v1/data/auth_webapp_login.html +166 -0
  67. aioafero-2.0.0/tests/v1/data/auth_webapp_login_bad_format.html +166 -0
  68. aioafero-2.0.0/tests/v1/data/auth_webapp_login_bad_qs.html +166 -0
  69. aioafero-2.0.0/tests/v1/data/auth_webapp_login_missing.html +166 -0
  70. aioafero-2.0.0/tests/v1/data/device_lock.json +1574 -0
  71. aioafero-2.0.0/tests/v1/data/raw_hs_data.json +3268 -0
  72. aioafero-2.0.0/tests/v1/data/water-timer-raw.json +1002 -0
  73. aioafero-2.0.0/tests/v1/device_dumps/dimmer-HPDA1110NWBP.json +566 -0
  74. aioafero-2.0.0/tests/v1/device_dumps/door-lock-TBD.json +3166 -0
  75. aioafero-2.0.0/tests/v1/device_dumps/fan-ZandraFan.json +916 -0
  76. aioafero-2.0.0/tests/v1/device_dumps/freezer.json +619 -0
  77. aioafero-2.0.0/tests/v1/device_dumps/glass-door.json +360 -0
  78. aioafero-2.0.0/tests/v1/device_dumps/light-a21.json +775 -0
  79. aioafero-2.0.0/tests/v1/device_dumps/light-rgb_temp.json +777 -0
  80. aioafero-2.0.0/tests/v1/device_dumps/power-outlet-HPPA11CWB.json +498 -0
  81. aioafero-2.0.0/tests/v1/device_dumps/rgbw-led-strip.json +582 -0
  82. aioafero-2.0.0/tests/v1/device_dumps/switch-HPDA311CWB.json +1400 -0
  83. aioafero-2.0.0/tests/v1/device_dumps/transformer.json +538 -0
  84. aioafero-2.0.0/tests/v1/device_dumps/water-timer.json +966 -0
  85. aioafero-2.0.0/tests/v1/models/__init__.py +0 -0
  86. aioafero-2.0.0/tests/v1/models/test_fan.py +121 -0
  87. aioafero-2.0.0/tests/v1/models/test_features.py +142 -0
  88. aioafero-2.0.0/tests/v1/models/test_light.py +91 -0
  89. aioafero-2.0.0/tests/v1/models/test_lock.py +32 -0
  90. aioafero-2.0.0/tests/v1/models/test_resources.py +5 -0
  91. aioafero-2.0.0/tests/v1/models/test_sensor.py +24 -0
  92. aioafero-2.0.0/tests/v1/models/test_switch.py +55 -0
  93. aioafero-2.0.0/tests/v1/models/test_valve.py +55 -0
  94. aioafero-2.0.0/tests/v1/test___init__.py +169 -0
  95. aioafero-2.0.0/tests/v1/test_auth.py +348 -0
  96. aioafero-2.0.0/tests/v1/utils.py +80 -0
  97. 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.
@@ -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.