smartbox 2.5.2__tar.gz → 2.7.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.
- smartbox-2.7.0/.env.example +16 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/FUNDING.yml +1 -2
- smartbox-2.7.0/.github/ISSUE_TEMPLATE/new-reseller.md +19 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/workflows/publish-to-pypi.yml +2 -2
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/workflows/python-package.yml +9 -9
- {smartbox-2.5.2 → smartbox-2.7.0}/.gitignore +7 -1
- smartbox-2.7.0/.vscode/settings.json +12 -0
- smartbox-2.7.0/CHANGELOG.md +366 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/CODEOWNERS +1 -1
- smartbox-2.7.0/PKG-INFO +254 -0
- smartbox-2.7.0/README.md +234 -0
- smartbox-2.7.0/ajtudela-pr-64-audit.md +497 -0
- smartbox-2.7.0/api-notes.md +861 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/codecov.yml +0 -2
- {smartbox-2.5.2 → smartbox-2.7.0}/pyproject.toml +27 -19
- {smartbox-2.5.2 → smartbox-2.7.0}/src/smartbox/__init__.py +40 -1
- {smartbox-2.5.2 → smartbox-2.7.0}/src/smartbox/cmd.py +266 -33
- smartbox-2.7.0/src/smartbox/error.py +54 -0
- smartbox-2.7.0/src/smartbox/models.py +325 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/src/smartbox/reseller.py +5 -11
- smartbox-2.7.0/src/smartbox/retry.py +78 -0
- smartbox-2.7.0/src/smartbox/session.py +1872 -0
- smartbox-2.7.0/src/smartbox/socket.py +509 -0
- smartbox-2.7.0/src/smartbox/update_manager.py +774 -0
- smartbox-2.7.0/src/smartbox/ws_user.py +758 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/common.py +11 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/conftest.py +9 -1
- smartbox-2.7.0/tests/fixtures/devs/device1/acm/1/samples.json +2839 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/acm/1/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/acm/1/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/acm/1/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/htr/0/samples.json +2839 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/htr/0/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/htr/0/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/htr/0/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/htr_system/power_limit.json +3 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/mgr/away_status.json +5 -0
- smartbox-2.7.0/tests/fixtures/devs/device1/pmo/3/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/0/samples.json +2839 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/0/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/0/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/0/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/1/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/1/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/1/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/2/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/2/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/2/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/3/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/3/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/3/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/4/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/4/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/4/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/5/setup.json +40 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/5/status.json +24 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_mod/5/version.json +6 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/htr_system/power_limit.json +3 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/mgr/away_status.json +5 -0
- smartbox-2.7.0/tests/fixtures/devs/device2/mgr/nodes.json +46 -0
- smartbox-2.7.0/tests/fixtures/devs.json +19 -0
- smartbox-2.7.0/tests/fixtures/grouped_devs.json +29 -0
- smartbox-2.7.0/tests/fixtures/live/htr_prog_addr2.json +187 -0
- smartbox-2.7.0/tests/fixtures/live/htr_prog_addr3.json +187 -0
- smartbox-2.7.0/tests/fixtures/live/htr_prog_addr4.json +187 -0
- smartbox-2.7.0/tests/fixtures/live/htr_prog_addr5.json +187 -0
- smartbox-2.7.0/tests/fixtures/live/htr_prog_addr6.json +187 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_addr2.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_addr3.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_addr4.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_addr5.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_addr6.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_setup_no_boost.json +24 -0
- smartbox-2.7.0/tests/fixtures/live/htr_status_boost_off.json +25 -0
- smartbox-2.7.0/tests/fixtures/live/socket_update_status_frame.json +28 -0
- smartbox-2.7.0/tests/fixtures/live/socket_update_sync_lost_frame.json +6 -0
- smartbox-2.7.0/tests/fixtures/live/socket_update_version_frame.json +9 -0
- smartbox-2.7.0/tests/fixtures/test_path.json +3 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/test_cmd.py +323 -2
- smartbox-2.7.0/tests/test_live_payloads.py +133 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/test_models.py +51 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/test_reseller.py +14 -5
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/test_session.py +1414 -264
- smartbox-2.7.0/tests/test_session_reliability.py +552 -0
- smartbox-2.7.0/tests/test_socket.py +673 -0
- smartbox-2.7.0/tests/test_update_manager.py +974 -0
- smartbox-2.7.0/tests/test_ws_user.py +887 -0
- smartbox-2.7.0/tools/api_functional_tests.py +233 -0
- smartbox-2.7.0/tools/away_probe.py +109 -0
- smartbox-2.7.0/tools/capture_prog.py +84 -0
- smartbox-2.7.0/tools/live_check.py +137 -0
- smartbox-2.7.0/tools/probe_extra_options.py +145 -0
- smartbox-2.7.0/tools/probe_modified_auto.py +214 -0
- smartbox-2.7.0/tools/probe_settle_window.py +146 -0
- smartbox-2.7.0/tools/probe_ws_user.py +491 -0
- smartbox-2.7.0/tools/prog_functional_tests.py +143 -0
- smartbox-2.7.0/tools/watch_status.py +123 -0
- smartbox-2.7.0/uv.lock +1424 -0
- smartbox-2.7.0/webapi-spec.md +186 -0
- smartbox-2.5.2/.github/ISSUE_TEMPLATE/new-reseller.md +0 -18
- smartbox-2.5.2/.vscode/settings.json +0 -7
- smartbox-2.5.2/CHANGELOG.md +0 -39
- smartbox-2.5.2/PKG-INFO +0 -190
- smartbox-2.5.2/README.md +0 -168
- smartbox-2.5.2/api-notes.md +0 -141
- smartbox-2.5.2/src/smartbox/error.py +0 -19
- smartbox-2.5.2/src/smartbox/models.py +0 -273
- smartbox-2.5.2/src/smartbox/session.py +0 -664
- smartbox-2.5.2/src/smartbox/socket.py +0 -313
- smartbox-2.5.2/src/smartbox/update_manager.py +0 -298
- smartbox-2.5.2/tests/fixtures/devs/device1/acm/1/samples.json +0 -2839
- smartbox-2.5.2/tests/fixtures/devs/device1/acm/1/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device1/acm/1/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device1/acm/1/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device1/htr/0/samples.json +0 -2839
- smartbox-2.5.2/tests/fixtures/devs/device1/htr/0/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device1/htr/0/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device1/htr/0/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device1/htr_system/power_limit.json +0 -1
- smartbox-2.5.2/tests/fixtures/devs/device1/mgr/away_status.json +0 -1
- smartbox-2.5.2/tests/fixtures/devs/device1/pmo/3/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/0/samples.json +0 -2839
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/0/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/0/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/0/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/1/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/1/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/1/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/2/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/2/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/2/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/3/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/3/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/3/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/4/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/4/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/4/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/5/setup.json +0 -40
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/5/status.json +0 -24
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_mod/5/version.json +0 -6
- smartbox-2.5.2/tests/fixtures/devs/device2/htr_system/power_limit.json +0 -1
- smartbox-2.5.2/tests/fixtures/devs/device2/mgr/away_status.json +0 -1
- smartbox-2.5.2/tests/fixtures/devs/device2/mgr/nodes.json +0 -46
- smartbox-2.5.2/tests/fixtures/devs.json +0 -19
- smartbox-2.5.2/tests/fixtures/grouped_devs.json +0 -24
- smartbox-2.5.2/tests/fixtures/test_path.json +0 -1
- smartbox-2.5.2/tests/test_update_manager.py +0 -283
- smartbox-2.5.2/uv.lock +0 -1155
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/.github/dependabot.yml +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/.pre-commit-config.yaml +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/LICENSE +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/src/smartbox/py.typed +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/__init__.py +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device1/connected.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device1/mgr/nodes.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device1/pmo/3/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device1/pmo/3/setup.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device1/pmo/3/status.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/connected.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/htr_mod/1/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/htr_mod/2/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/htr_mod/3/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/htr_mod/4/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/devs/device2/htr_mod/5/samples.json +0 -0
- {smartbox-2.5.2 → smartbox-2.7.0}/tests/fixtures/groups/test_home/guest_users.json +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copy this file to ".env" and fill in your values so the `smartbox` CLI does
|
|
2
|
+
# not need the credentials on every invocation. A real shell environment
|
|
3
|
+
# variable always overrides the value set here, and an explicit command-line
|
|
4
|
+
# option overrides both.
|
|
5
|
+
|
|
6
|
+
# Your username/password as used for the mobile app / web app (required).
|
|
7
|
+
SMARTBOX_USERNAME=
|
|
8
|
+
SMARTBOX_PASSWORD=
|
|
9
|
+
|
|
10
|
+
# API name for your heater vendor, e.g. "api" or "api-foo" (see README).
|
|
11
|
+
SMARTBOX_API_NAME=api
|
|
12
|
+
|
|
13
|
+
# Only needed if your reseller is not built into the package.
|
|
14
|
+
SMARTBOX_BASIC_AUTH_CREDS=
|
|
15
|
+
SMARTBOX_X_REFERER=
|
|
16
|
+
SMARTBOX_X_SERIAL_ID=
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: New reseller
|
|
3
|
+
about: Add a new available reseller.
|
|
4
|
+
title: "[RESELLER] New available reseller"
|
|
5
|
+
labels: reseller
|
|
6
|
+
assignees: Delmael
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
> [!NOTE]
|
|
11
|
+
> If you do not see your current reseller in the available list, you can ask to add it. We cannot ensure your device go through this platform.
|
|
12
|
+
> See [How to capture the values](https://github.com/ajtudela/smartbox/blob/main/api-notes.md#basic-auth-credential) — open your reseller's web app, watch the network tab, log in and read the `POST .../api/v2/client/token` request headers.
|
|
13
|
+
|
|
14
|
+
* [ ] I have checked with the `smartbox resellers` command that my reseller is not already present
|
|
15
|
+
* **Website url (mandatory)** (the `x-referer` header):
|
|
16
|
+
* Name of the reseller:
|
|
17
|
+
* API name (the `api-<...>` part of the request host, e.g. `api-foo`):
|
|
18
|
+
* Basic auth credential (the base64 string after `Basic ` in the `authorization` header):
|
|
19
|
+
* Serial id (the `x-serialid` header):
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
permissions:
|
|
15
15
|
id-token: write
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
18
|
with:
|
|
19
19
|
fetch-depth: 0
|
|
20
20
|
- name: Install uv
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
with:
|
|
23
23
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
24
24
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
|
25
|
-
uses: actions/setup-python@
|
|
25
|
+
uses: actions/setup-python@v7.0.0
|
|
26
26
|
with:
|
|
27
27
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
28
28
|
- name: Build a binary wheel and a source tarball
|
|
@@ -18,19 +18,19 @@ jobs:
|
|
|
18
18
|
matrix:
|
|
19
19
|
python-version: [3.14]
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
22
|
- name: Install uv
|
|
23
23
|
uses: astral-sh/setup-uv@v7
|
|
24
24
|
with:
|
|
25
25
|
python-version: ${{ matrix.python-version }}
|
|
26
26
|
- name: Set up Python ${{ matrix.python-version }}
|
|
27
|
-
uses: actions/setup-python@
|
|
27
|
+
uses: actions/setup-python@v7.0.0
|
|
28
28
|
with:
|
|
29
29
|
python-version: ${{ matrix.python-version }}
|
|
30
30
|
- name: Install the project
|
|
31
31
|
run: uv sync --all-extras --dev
|
|
32
32
|
- name: Lint with ruff
|
|
33
|
-
run: uv run ruff check src/smartbox
|
|
33
|
+
run: uv run ruff check src/smartbox tests
|
|
34
34
|
|
|
35
35
|
typechecker:
|
|
36
36
|
runs-on: ubuntu-latest
|
|
@@ -40,19 +40,19 @@ jobs:
|
|
|
40
40
|
python-version: [3.14]
|
|
41
41
|
|
|
42
42
|
steps:
|
|
43
|
-
- uses: actions/checkout@
|
|
43
|
+
- uses: actions/checkout@v7
|
|
44
44
|
- name: Install uv
|
|
45
45
|
uses: astral-sh/setup-uv@v7
|
|
46
46
|
with:
|
|
47
47
|
python-version: ${{ matrix.python-version }}
|
|
48
48
|
- name: Set up Python ${{ matrix.python-version }}
|
|
49
|
-
uses: actions/setup-python@
|
|
49
|
+
uses: actions/setup-python@v7.0.0
|
|
50
50
|
with:
|
|
51
51
|
python-version: ${{ matrix.python-version }}
|
|
52
52
|
- name: Install the project
|
|
53
53
|
run: uv sync --all-extras --dev
|
|
54
54
|
- name: Typecheck with mypy
|
|
55
|
-
run: uv run mypy src/smartbox
|
|
55
|
+
run: uv run mypy src/smartbox tests
|
|
56
56
|
|
|
57
57
|
build:
|
|
58
58
|
runs-on: ubuntu-latest
|
|
@@ -62,14 +62,14 @@ jobs:
|
|
|
62
62
|
python-version: [3.14]
|
|
63
63
|
|
|
64
64
|
steps:
|
|
65
|
-
- uses: actions/checkout@
|
|
65
|
+
- uses: actions/checkout@v7
|
|
66
66
|
- name: Install uv
|
|
67
67
|
uses: astral-sh/setup-uv@v7
|
|
68
68
|
with:
|
|
69
69
|
python-version: ${{ matrix.python-version }}
|
|
70
70
|
|
|
71
71
|
- name: Set up Python ${{ matrix.python-version }}
|
|
72
|
-
uses: actions/setup-python@
|
|
72
|
+
uses: actions/setup-python@v7.0.0
|
|
73
73
|
with:
|
|
74
74
|
python-version: ${{ matrix.python-version }}
|
|
75
75
|
- name: Install the project
|
|
@@ -77,7 +77,7 @@ jobs:
|
|
|
77
77
|
uv sync --all-extras --dev
|
|
78
78
|
uv run tox -e py
|
|
79
79
|
- name: "Upload coverage to Codecov"
|
|
80
|
-
uses: codecov/codecov-action@
|
|
80
|
+
uses: codecov/codecov-action@v7.1.1
|
|
81
81
|
with:
|
|
82
82
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
83
83
|
fail_ci_if_error: true
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[python]": {
|
|
3
|
+
"editor.codeActionsOnSave": {
|
|
4
|
+
"source.fixAll.ruff": "explicit",
|
|
5
|
+
"source.organizeImports.ruff": "explicit"
|
|
6
|
+
},
|
|
7
|
+
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
8
|
+
"editor.formatOnSave": true
|
|
9
|
+
},
|
|
10
|
+
"python.testing.pytestEnabled": true,
|
|
11
|
+
"python.testing.unittestEnabled": false
|
|
12
|
+
}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.7.0
|
|
4
|
+
|
|
5
|
+
### New
|
|
6
|
+
* Per-user `ws_user` websocket transport (`WsUserSocketSession`,
|
|
7
|
+
`check_ws_user_support`): one connection serves every device of the
|
|
8
|
+
account, replacing N per-device `socket_io` sessions. Wire protocol
|
|
9
|
+
and every failure mode verified live (api-notes.md, "Transports —
|
|
10
|
+
socket_io vs ws_user"). Selected via the new `ws_user_socket=` kwarg
|
|
11
|
+
on `UpdateManager`; the default transport is unchanged.
|
|
12
|
+
* `WsUserUnsupportedError` + the fallback doctrine: only deterministic
|
|
13
|
+
handshake rejections (HTTP 401/403/404/410 in the one-shot probe on a
|
|
14
|
+
fresh token; 404/410 in the run loop, or 401/403 that keep rejecting
|
|
15
|
+
freshly minted tokens) signal "endpoint unsupported"; transient
|
|
16
|
+
trouble is retried and never demotes.
|
|
17
|
+
* In `ws_user` mode `UpdateManager` ignores the SocketSession
|
|
18
|
+
pass-through kwargs (warned at construction) — the shared socket's
|
|
19
|
+
liveness is heartbeat-driven, not knob-driven.
|
|
20
|
+
|
|
21
|
+
### Breaking
|
|
22
|
+
* `UpdateManager.socket_session` now returns `None` when the manager
|
|
23
|
+
runs in `ws_user` mode (previously always a `SocketSession`); use the
|
|
24
|
+
new `ws_user_socket` accessor to distinguish modes.
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
* CLI: every authentication option also resolves from a `SMARTBOX_*`
|
|
28
|
+
environment variable, and the `smartbox` console script loads a `.env`
|
|
29
|
+
file (searched upward from the working directory) before parsing
|
|
30
|
+
options. Precedence: command line > shell environment > `.env`. See
|
|
31
|
+
`.env.example`.
|
|
32
|
+
|
|
33
|
+
### Fixes
|
|
34
|
+
* CLI: `.env` parsing now follows python-dotenv semantics — an inline
|
|
35
|
+
`#` starts a comment only when it is preceded by whitespace and lies
|
|
36
|
+
outside quotes, and quoted values unquote even when a trailing
|
|
37
|
+
comment follows them. Previously inline comments silently became
|
|
38
|
+
part of the value and quote-stripping was defeated, corrupting
|
|
39
|
+
credentials written in the conventional quoted style.
|
|
40
|
+
|
|
41
|
+
### Refactor
|
|
42
|
+
* `UpdateManager`: `subscribe_to_node_status`/`_setup`/`_version`/`_prog`
|
|
43
|
+
share one `_subscribe_to_node_key` implementation.
|
|
44
|
+
|
|
45
|
+
### Tests & CI
|
|
46
|
+
* Socket tests for the namespace callbacks, websocket cleanup, SIGINT
|
|
47
|
+
handler and cancellation during connect; coverage floor of 95%
|
|
48
|
+
(`fail_under`) enforced.
|
|
49
|
+
* ruff and mypy run over `tests/` in CI; `socket.py` is no longer
|
|
50
|
+
excluded from codecov.
|
|
51
|
+
|
|
52
|
+
### Docs
|
|
53
|
+
* README rewritten: library usage, command table, `.env` section and an
|
|
54
|
+
actionable Support section. api-notes documents how to capture the
|
|
55
|
+
Basic Auth credential and the new-reseller issue template points to it.
|
|
56
|
+
|
|
57
|
+
## 2.6.2
|
|
58
|
+
|
|
59
|
+
Port round of upstream PR #64 (ajtudela, `improvements/fix_bugs`, 19
|
|
60
|
+
commits) — full per-commit audit, verdicts and evidence in
|
|
61
|
+
ajtudela-pr-64-audit.md. Ten commits were already fixed by the 2.6.x
|
|
62
|
+
round (independent convergence); of the remainder, seven were ported
|
|
63
|
+
(each commit references the upstream source hash), one was declined by
|
|
64
|
+
decision (#7: typed-mode sparse statuses keep the rich
|
|
65
|
+
`SmartboxValidationError` rejection — the bare `{"sync_status": "lost"}`
|
|
66
|
+
dead-node frame is first-class there), and one is upstream-only (#18,
|
|
67
|
+
version bump).
|
|
68
|
+
|
|
69
|
+
### Bug Fixes
|
|
70
|
+
* `set_node_setup` never serializes the read-modify-write GET through
|
|
71
|
+
the Pydantic models: the internal read is always raw, so keys the
|
|
72
|
+
setup models do not declare (e.g. `counter_offset` on pmo nodes) can
|
|
73
|
+
no longer be wiped on the device by a setup write (upstream `5618aa3`).
|
|
74
|
+
Completed by `extra="allow"` on `DefaultNodeSetup`/`PmoSetup`, so
|
|
75
|
+
typed (`raw_response=False`) reads keep unknown keys and round-trip
|
|
76
|
+
losslessly (upstream `5618aa3`, completion by decision).
|
|
77
|
+
* `InvalidAuthError`, `APIUnavailableError` and `ResellerNotExistError`
|
|
78
|
+
now derive from `SmartboxError` — one `except SmartboxError` catches
|
|
79
|
+
every library failure. `APIUnavailableError` keeps its
|
|
80
|
+
`aiohttp.ClientConnectionError` base for backwards compatibility; the
|
|
81
|
+
data-path 403 → `SmartboxError` mapping is kept deliberately
|
|
82
|
+
(upstream `62efcf8`).
|
|
83
|
+
* CLI: unknown `-d`/`-n` values raise `click.BadParameter` with a
|
|
84
|
+
`param_hint` (exit code 2, usage line, offending option named)
|
|
85
|
+
instead of `ClickException`; malformed wire node payloads stay
|
|
86
|
+
`ClickException` (upstream `6ad2014`).
|
|
87
|
+
|
|
88
|
+
### Build & Docs
|
|
89
|
+
* Core dependencies bounded to their current major: `aiohttp>=3,<4`,
|
|
90
|
+
`pydantic>=2,<3`, `python-socketio>=5,<6` (upstream `da3bb9c`; the
|
|
91
|
+
commit's unused-dependency removal was already done in 2.6.0).
|
|
92
|
+
* `.vscode/settings.json`: pylint/flake8 editor settings replaced with
|
|
93
|
+
the ruff formatter/code-actions setup (upstream `a78bc3a`; its
|
|
94
|
+
pyproject/ruff halves were already done in 2.6.0).
|
|
95
|
+
* CODEOWNERS co-owner and README badge reflow adopted from upstream
|
|
96
|
+
`2ec1ef0`.
|
|
97
|
+
|
|
98
|
+
### Tests
|
|
99
|
+
* `test_all_resellers` (real HTTP calls to twelve reseller servers)
|
|
100
|
+
moved behind a `network` marker, deselected by default; run on demand
|
|
101
|
+
with `pytest -m network`. Sessions in it are closed (upstream
|
|
102
|
+
`0bef64c`).
|
|
103
|
+
|
|
104
|
+
## 2.6.1
|
|
105
|
+
|
|
106
|
+
### Features
|
|
107
|
+
* Node reachability / write-confirmation tracking on `UpdateManager`:
|
|
108
|
+
`subscribe_to_node_availability` / `get_node_availability` report a
|
|
109
|
+
node Available/Unavailable from its status/setup frames — a bare
|
|
110
|
+
`{"sync_status": "lost"}` frame arms a uniform 6 s grace timer
|
|
111
|
+
(`unavailable_delay` knob, matches the vendor app's unreachable
|
|
112
|
+
window); any ok frame reports Available again. `expect_write_confirmation`
|
|
113
|
+
(knob `write_confirm_timeout`, 6 s) arms a window after an accepted
|
|
114
|
+
write: if no ok frame arrives, a one-shot discriminating GET decides
|
|
115
|
+
"applied (node alive)" vs "silently dropped (node unreachable)" —
|
|
116
|
+
writes to unreachable nodes are ACKed OK with no device ack (observed
|
|
117
|
+
live). Frame taps register lazily; both features share them, each
|
|
118
|
+
enables them independently. Backed by live probes 2026-09-26/30
|
|
119
|
+
(api-notes.md, "Node reachability").
|
|
120
|
+
|
|
121
|
+
## 2.6.0
|
|
122
|
+
|
|
123
|
+
### Features
|
|
124
|
+
* Full node programme (schedule) support: `get_node_prog` / `set_node_prog`
|
|
125
|
+
(+ typed `NodeProg` model, sync `Session.get_prog` / `set_prog` wrappers,
|
|
126
|
+
`subscribe_to_node_prog` websocket helper and `prog` / `set-prog` CLI
|
|
127
|
+
commands). Wire note: GET and POST both use the day-keyed object shape;
|
|
128
|
+
the array shape is rejected with 400 (observed live).
|
|
129
|
+
* Full management/fleet surface per webapi-spec §2–3: device discovery
|
|
130
|
+
GET/POST, device rtc/time, device/node/group rename, device/node delete,
|
|
131
|
+
device group move, node select/power, group geo_data/extra_data, invite
|
|
132
|
+
flows (invite/revoke/confirm — confirm is unauthenticated), quiet-home
|
|
133
|
+
notification config GET/POST + test, encrypted-wifi-credentials and
|
|
134
|
+
geocoding helpers. Read-only-verified paths pinned from the official
|
|
135
|
+
vendor app; all writes marked **unverified on live hardware** in docstrings.
|
|
136
|
+
New base helpers: `_api_delete`, host-relative `_api_get` (params not
|
|
137
|
+
logged — may carry secrets) and `_api_post_path` (auth optional).
|
|
138
|
+
* Away-status writes default `enabled: true` to match the vendor app shape
|
|
139
|
+
(`{away, enabled}`); the server also honours `{away}` alone (D1 verified
|
|
140
|
+
live).
|
|
141
|
+
* Setup models widened for the fw-1.9 htr family: optional
|
|
142
|
+
`user_duty_factor` / `flash_version` / `extra_options`; new
|
|
143
|
+
`max_stemp_limit` / `priority` / `revision` and
|
|
144
|
+
`factory_options.operating_mode` / `power_factor` / `super_lock_available`.
|
|
145
|
+
Its `factory_options` carries no `prog_resolution` (schedule resolution
|
|
146
|
+
not readable from setup on this family).
|
|
147
|
+
|
|
148
|
+
### Bug Fixes
|
|
149
|
+
* `SocketSession.cancel()` is now bounded by a timeout (no more unbounded
|
|
150
|
+
hangs on a wedged websocket) and disconnects exactly once (cancel +
|
|
151
|
+
shutdown no longer double-disconnect).
|
|
152
|
+
* The websocket loop checks the exit flag before touching the REST API, so
|
|
153
|
+
cancel is no longer delayed by a slow auth refresh.
|
|
154
|
+
* Dangling background cleanup tasks are awaited (bounded) on shutdown
|
|
155
|
+
instead of dying as "Task was destroyed but it is pending" noise.
|
|
156
|
+
* Routine retry log downgraded from `_LOGGER.exception` to `_LOGGER.warning`.
|
|
157
|
+
* Status models widened for the newer htr firmware family (`error_code`
|
|
158
|
+
str|int; optional `act_duty` / `power_pcb_temp`); optional fields
|
|
159
|
+
`easy` / `runback` / `version` tolerated.
|
|
160
|
+
|
|
161
|
+
* Code-review round 3 (2026-09-27): request-timeouts and HTTP 5xx now map
|
|
162
|
+
to `APIUnavailableError` (aiohttp's total-timeout raises a plain
|
|
163
|
+
`TimeoutError` that previously escaped all error handling; 5xx GETs are
|
|
164
|
+
retried via the existing retry wrapper — 4xx still raises
|
|
165
|
+
`SmartboxError`); request bodies are redacted in debug logs (the
|
|
166
|
+
invite-confirmation `pass` leaked in plaintext); subscription user
|
|
167
|
+
callbacks are isolated — one raising callback can no longer starve the
|
|
168
|
+
other subscriptions or propagate into the socket loop, and jq-emitted
|
|
169
|
+
`null` node payloads no longer fire callbacks; the socket reconnect
|
|
170
|
+
backoff is capped at 30s per attempt (previously up to ~8.5 min of
|
|
171
|
+
futile retries before the token refresh that usually fixes the
|
|
172
|
+
disconnect); `_attempt_connection` also tolerates transient
|
|
173
|
+
`TimeoutError`/`OSError` from the websocket transport instead of
|
|
174
|
+
killing the run loop; the ping task is cancelled **and** reaped
|
|
175
|
+
(bounded) on cancel/shutdown; `get_device_power_limit` raises
|
|
176
|
+
`SmartboxError` instead of `KeyError` on an unexpected payload;
|
|
177
|
+
sync `Session` annotations aligned with the async surface (`set_setup`
|
|
178
|
+
→ `None`, `get_status`/`get_setup`/`get_prog` may return models);
|
|
179
|
+
CLI: non-numeric node addresses give a clean error, `resellers` prints
|
|
180
|
+
a readable list without credentials, and `-u`/`-p` accept the
|
|
181
|
+
`SMARTBOX_USERNAME`/`SMARTBOX_PASSWORD` env vars; `__version__` no
|
|
182
|
+
longer explodes when imported uninstalled.
|
|
183
|
+
|
|
184
|
+
* Code-review round 4 (2026-09-27): sync `Session` no longer fails on the
|
|
185
|
+
second consecutive call with "RuntimeError: Session is closed" (the
|
|
186
|
+
per-call cleanup now forgets the closed client session so the next
|
|
187
|
+
`asyncio.run` recreates it — regression test drives the real client
|
|
188
|
+
through a local HTTP server); sync `get_device_power_limit` /
|
|
189
|
+
`set_device_power_limit` regain the async `node` parameter (pmo devices
|
|
190
|
+
were unreachable from the sync API) and sync wrappers were added for
|
|
191
|
+
`health_check`, `api_version`, `get_device_connected`,
|
|
192
|
+
`get_node_samples` and `get_node_version`; CLI `-a/--api-name` defaults
|
|
193
|
+
to `api` and session/API failures (auth, network, unknown reseller)
|
|
194
|
+
surface as clean `ClickException` errors instead of tracebacks;
|
|
195
|
+
`set_node_prog` rejects array-shape / `prog`-less payloads with a clear
|
|
196
|
+
error instead of an `AttributeError` traceback or a silent no-op POST
|
|
197
|
+
(CLI guard included); a token endpoint 200 with a non-JSON body raises
|
|
198
|
+
`SmartboxError` instead of `InvalidAuthError` (it must not trigger the
|
|
199
|
+
consumer's reauth flow); `SocketSession.run` authenticates before the
|
|
200
|
+
first connect attempt (a cold CLI session no longer burns its
|
|
201
|
+
reconnect budget on an empty token); the CLI SIGINT handler is removed
|
|
202
|
+
at teardown and platforms without signal-handler support no longer die
|
|
203
|
+
on connect; package exports completed (`NodeVersion` and the remaining
|
|
204
|
+
public model types).
|
|
205
|
+
|
|
206
|
+
* Code-review round 5 (2026-09-27) — **contract changes**:
|
|
207
|
+
* `raw_response=True` no longer validates responses: `get_devices`,
|
|
208
|
+
`get_homes`, `get_grouped_devices`, `get_home_guests`,
|
|
209
|
+
`get_device_connected` and `get_device_away_status` return the wire
|
|
210
|
+
payload (with only the documented list extraction, e.g. `devs` +
|
|
211
|
+
`invited_to` flattened) instead of model-serialised dicts. Unknown
|
|
212
|
+
keys are kept (live: `grouped_devs` carries `extraData`, previously
|
|
213
|
+
dropped); a payload too malformed to extract from raises
|
|
214
|
+
`SmartboxError`. All raw getters now follow the same rule.
|
|
215
|
+
* New `SmartboxValidationError(SmartboxError)`, exported: with
|
|
216
|
+
`raw_response=False`, payload drift raises it (chained from the
|
|
217
|
+
pydantic error) instead of a bare `pydantic.ValidationError`.
|
|
218
|
+
* Every library call is bounded by a 30s whole-call deadline covering
|
|
219
|
+
token refresh, retries and backoff — also on caller-provided
|
|
220
|
+
websessions (previously aiohttp's 300s default applied there, and 5
|
|
221
|
+
retries could stretch one call to minutes). Expiry raises
|
|
222
|
+
`APIUnavailableError`; a backoff that would overrun it is skipped.
|
|
223
|
+
* A rejected refresh token falls back to one password login before
|
|
224
|
+
`InvalidAuthError` is raised; a mid-session 401 invalidates the
|
|
225
|
+
token and retries the request once after re-authenticating.
|
|
226
|
+
* Code-review round 5 — reliability fixes:
|
|
227
|
+
* The websocket loop survives transient auth-refresh failures
|
|
228
|
+
(`APIUnavailableError`/`SmartboxError` are waited out with capped
|
|
229
|
+
backoff; previously one network blip ended `run()` for good); only
|
|
230
|
+
rejected credentials end it.
|
|
231
|
+
* `cancel()` during reconnect backoff stops the reconnect loop
|
|
232
|
+
immediately (it used to keep attempting), and a connect completing
|
|
233
|
+
after `cancel()` is disconnected instead of leaking a live socket
|
|
234
|
+
that kept `run()` alive.
|
|
235
|
+
* The keepalive ping task survives a failed send (it died for the
|
|
236
|
+
rest of the session on one `BadNamespaceError`).
|
|
237
|
+
* Secrets: the INFO "Successfully connected" log no longer prints the
|
|
238
|
+
access token; error messages and logs no longer embed request query
|
|
239
|
+
strings (aiohttp's exception text leaked the wifi password of
|
|
240
|
+
`get_encrypted_wifi_credentials`).
|
|
241
|
+
* Truncated response bodies (`ClientPayloadError`) map to
|
|
242
|
+
`APIUnavailableError` (retried on GETs) and undecodable JSON to
|
|
243
|
+
`SmartboxError` — both previously escaped the library's error types.
|
|
244
|
+
* `retry_attempts=0` makes one attempt instead of raising `TypeError`.
|
|
245
|
+
* Update subscriptions anchor their paths (`/prog` no longer matches
|
|
246
|
+
`/prog_temps` frames, likewise status/setup/version).
|
|
247
|
+
* Hygiene: 45 unneeded `type: ignore`s removed, sync
|
|
248
|
+
`Session.set_device_away_status` annotated `-> None`, dead
|
|
249
|
+
`_basic_auth_credentials` attribute removed, `socket.py` imports
|
|
250
|
+
`urllib.parse` explicitly.
|
|
251
|
+
|
|
252
|
+
* Code-review round 6 (2026-09-27, every finding reproduced by a probe
|
|
253
|
+
before fixing): the token endpoint (`/client/token`) maps truncated
|
|
254
|
+
bodies (`ClientPayloadError`) and undecodable-JSON 200s to
|
|
255
|
+
`APIUnavailableError` / `SmartboxError` like the REST path — a
|
|
256
|
+
truncated token body previously escaped raw and **ended the websocket
|
|
257
|
+
loop for good** (end-to-end reproduced); `SocketSession` rejects
|
|
258
|
+
`ping_interval <= 0` (hot ping loop) and `reconnect_attempts < 1`
|
|
259
|
+
(endless refresh churn) with a `ValueError` at construction; the CLI
|
|
260
|
+
`set-status` command gives a clean error for `--stemp` without
|
|
261
|
+
`--units` instead of a raw `ValueError` traceback; the token endpoint
|
|
262
|
+
treats HTTP 429 as transient (`APIUnavailableError`) instead of bad
|
|
263
|
+
credentials — rate limiting no longer triggers the password-login
|
|
264
|
+
fallback, the consumer's reauth flow, or the end of the websocket
|
|
265
|
+
loop (400/401 rejections still surface as `InvalidAuthError`).
|
|
266
|
+
|
|
267
|
+
* Code-review round 6 follow-up (2026-09-27, **breaking** — 2.6.0 is the
|
|
268
|
+
alignment window; every fix probe-verified): `set_node_prog` raises
|
|
269
|
+
`ValueError` for a `prog`-less / array-shaped payload (was `TypeError`
|
|
270
|
+
— now aligned with `set_node_status`'s input validation); the sync
|
|
271
|
+
`Session` wrapper return annotations reflect `raw_response=False`
|
|
272
|
+
(e.g. `get_devices` may return a `Devices` model, `get_nodes` a
|
|
273
|
+
`list[Node]`); the sync `Session` no longer leaks "coroutine was never
|
|
274
|
+
awaited" `RuntimeWarning`s when misused inside a running event loop
|
|
275
|
+
(the pre-built coroutines are closed before re-raising); socket
|
|
276
|
+
teardown reaps cancelled disconnect tasks and cancelled pending
|
|
277
|
+
background tasks (bounded) — no more "Task was destroyed but it is
|
|
278
|
+
pending" noise in edge teardown timing.
|
|
279
|
+
|
|
280
|
+
* Dependency refresh (2026-09-27, all gates + live socket round green):
|
|
281
|
+
runtime aiohttp 3.14.0→3.14.3, pydantic 2.13.4→2.13.5,
|
|
282
|
+
python-socketio 5.16.2→5.17.0 (+engineio 4.14.0, bidict), asyncclick
|
|
283
|
+
8.3.0.7→8.4.2.1, jq 1.11.0→1.12.0; dev pytest 9.1.1, ruff 0.16.9,
|
|
284
|
+
mypy 2.3.1, time-machine 3.5.1, tox 4.64.3, pytest-randomly 5.0.0.
|
|
285
|
+
* Removed dead dependencies `requests` and `websocket-client` (imported
|
|
286
|
+
nowhere; legacy from the pre-asyncio era — the websocket path uses
|
|
287
|
+
python-socketio/simple-websocket, HTTP uses aiohttp).
|
|
288
|
+
* Lint config: ruff `target-version` aligned to the runtime floor
|
|
289
|
+
(py313 → py314); disabled CPY001 (no copyright headers in this
|
|
290
|
+
project) and PLR0917 (positional variant of the already-ignored
|
|
291
|
+
PLR0913); dropped dead mypy override modules (`freezegun`, `test`);
|
|
292
|
+
typing-only imports moved behind `TYPE_CHECKING` (ruff TC rules).
|
|
293
|
+
|
|
294
|
+
* Code-review round (2026-09-27, all gates + contract tests + live smoke
|
|
295
|
+
green): caller-provided websessions are no longer closed on context
|
|
296
|
+
exit (session-ownership model, `aclose_owned_session()`); REST requests
|
|
297
|
+
get bounded timeouts (30s total / 10s connect) on library-created
|
|
298
|
+
sessions; GETs retry on transient connection failures (uses the
|
|
299
|
+
previously dead `retry_attempts`/`backoff_factor` constructor config);
|
|
300
|
+
mid-session HTTP 401 now raises `InvalidAuthError` (consumers can
|
|
301
|
+
trigger reauth); access token is masked in debug logs; sync `Session`
|
|
302
|
+
closes its lazily-created client session per call (no more "Unclosed
|
|
303
|
+
client session" warnings); CLI: clean `ClickException` errors for
|
|
304
|
+
unknown device/node ids and invalid prog JSON, and fixed a latent bug
|
|
305
|
+
where set-* commands could never resolve a node (string vs int address
|
|
306
|
+
comparison); sample-window defaults are computed at call time (they
|
|
307
|
+
were frozen at import and drifted in long-lived processes); docstring
|
|
308
|
+
fixes (`Sample`/`PmoSample` were swapped, `subscribe_to_device_connected`
|
|
309
|
+
claimed to be a power-limit hook); removed redundant field
|
|
310
|
+
redeclarations in status subclasses and 1-tuple call hacks in the
|
|
311
|
+
update manager; dropped dead `[tool.uv.workspace]` and
|
|
312
|
+
`[tool.setuptools.*]` config.
|
|
313
|
+
|
|
314
|
+
* Code-review round 7 — final pre-release pass (2026-09-27, gates +
|
|
315
|
+
contract tests green): `SocketSession` can now be constructed outside
|
|
316
|
+
a running event loop (the REST websession binding moved from
|
|
317
|
+
`__init__` to `run()`, with `external_http=True` so engineio never
|
|
318
|
+
closes the session shared with REST traffic); the websocket run loop
|
|
319
|
+
no longer dies when the first `dev_data` emit races the server drop
|
|
320
|
+
(`BadNamespaceError` is a *sibling* of `ConnectionError` under
|
|
321
|
+
`SocketIOError` — the catch family was widened to `SocketIOError`);
|
|
322
|
+
a token-endpoint 200 with a wrong-shaped body raises `SmartboxError`
|
|
323
|
+
instead of `InvalidAuthError` (consistent with the undecodable-JSON /
|
|
324
|
+
non-JSON mapping: a server-side drift is not "credentials rejected");
|
|
325
|
+
`AsyncSession` rejects a negative `backoff_factor` at construction
|
|
326
|
+
(it previously silently disabled backoff); CLI node resolution gives
|
|
327
|
+
a clean error on malformed wire payloads (missing/non-numeric `addr`)
|
|
328
|
+
instead of a raw `KeyError`/`ValueError` traceback.
|
|
329
|
+
|
|
330
|
+
## 0.0.5 (alpha)
|
|
331
|
+
|
|
332
|
+
### Features
|
|
333
|
+
* Rename `away_status` to `device_away_status`
|
|
334
|
+
* Update API docs
|
|
335
|
+
* Add tox, tox and flake8 on github action
|
|
336
|
+
|
|
337
|
+
### Bug Fixes
|
|
338
|
+
* Pin dependency of python-socketio to match server
|
|
339
|
+
|
|
340
|
+
## 0.0.4 (alpha)
|
|
341
|
+
|
|
342
|
+
### Features
|
|
343
|
+
* Refactor socket session and implement reconnect
|
|
344
|
+
* Add note on basic auth credentials
|
|
345
|
+
|
|
346
|
+
## 0.0.3 (alpha)
|
|
347
|
+
|
|
348
|
+
### Features
|
|
349
|
+
* Fixed packaging
|
|
350
|
+
|
|
351
|
+
### Bug Fixes
|
|
352
|
+
* Fixed disconnect handling on token refresh
|
|
353
|
+
|
|
354
|
+
## 0.0.2 (alpha)
|
|
355
|
+
|
|
356
|
+
### Features
|
|
357
|
+
* Added `get_api_name` function
|
|
358
|
+
* Added basic tests for REST interactions
|
|
359
|
+
* Added token refresh support
|
|
360
|
+
* Added socket.io interface via `open_socket` function (no tests as yet)
|
|
361
|
+
* Added documentation for known REST and websocket endpoints
|
|
362
|
+
|
|
363
|
+
## 0.0.1 (alpha)
|
|
364
|
+
|
|
365
|
+
### Features
|
|
366
|
+
* Initial version supporting some REST endpoints
|