python-rako-2025 0.4.4__tar.gz → 0.5.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.
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.coveragerc +4 -2
- python_rako_2025-0.5.0/.github/workflows/ci.yml +75 -0
- python_rako_2025-0.5.0/.github/workflows/release.yml +117 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.gitignore +0 -1
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.pre-commit-config.yaml +6 -6
- python_rako_2025-0.5.0/CHANGELOG.md +123 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/Makefile +9 -9
- python_rako_2025-0.5.0/PKG-INFO +334 -0
- python_rako_2025-0.5.0/README.md +293 -0
- python_rako_2025-0.5.0/RELEASING.md +153 -0
- python_rako_2025-0.5.0/examples/listen_status.py +76 -0
- python_rako_2025-0.5.0/examples/state_snapshot.py +87 -0
- python_rako_2025-0.5.0/examples/verified_commands.py +65 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/pyproject.toml +10 -5
- python_rako_2025-0.5.0/python_rako/__init__.py +150 -0
- python_rako_2025-0.5.0/python_rako/__version__.py +1 -0
- python_rako_2025-0.5.0/python_rako/bridge.py +791 -0
- python_rako_2025-0.5.0/python_rako/commands.py +618 -0
- python_rako_2025-0.5.0/python_rako/const.py +111 -0
- python_rako_2025-0.5.0/python_rako/exceptions.py +47 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/python_rako/helpers.py +40 -87
- python_rako_2025-0.5.0/python_rako/listener.py +449 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/python_rako/model.py +42 -5
- python_rako_2025-0.5.0/python_rako/pacing.py +534 -0
- python_rako_2025-0.5.0/python_rako/protocol.py +658 -0
- python_rako_2025-0.5.0/python_rako/state.py +431 -0
- python_rako_2025-0.5.0/scripts/bump_version.py +120 -0
- python_rako_2025-0.5.0/scripts/latency.py +201 -0
- python_rako_2025-0.5.0/scripts/listen.py +166 -0
- python_rako_2025-0.5.0/scripts/measure_interval.py +271 -0
- python_rako_2025-0.5.0/scripts/snapshot.py +101 -0
- python_rako_2025-0.5.0/tests/README_TESTING.md +138 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_async_lock.py +64 -15
- python_rako_2025-0.5.0/tests/test_bridge_async_parsing.py +96 -0
- python_rako_2025-0.5.0/tests/test_bridge_state.py +278 -0
- python_rako_2025-0.5.0/tests/test_command_queue.py +682 -0
- python_rako_2025-0.5.0/tests/test_commands.py +670 -0
- python_rako_2025-0.5.0/tests/test_discovery.py +104 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_helpers.py +37 -1
- python_rako_2025-0.5.0/tests/test_listener.py +507 -0
- python_rako_2025-0.5.0/tests/test_measure_interval.py +126 -0
- python_rako_2025-0.5.0/tests/test_protocol.py +528 -0
- python_rako_2025-0.5.0/tests/test_state.py +482 -0
- python_rako_2025-0.5.0/tests_integration/conftest.py +151 -0
- python_rako_2025-0.5.0/tests_integration/test_bridge_info_live.py +32 -0
- python_rako_2025-0.5.0/tests_integration/test_command_live.py +131 -0
- python_rako_2025-0.5.0/tests_integration/test_discovery_live.py +40 -0
- python_rako_2025-0.5.0/tests_integration/test_listener_live.py +45 -0
- python_rako_2025-0.5.0/tests_integration/test_state_live.py +52 -0
- python_rako_2025-0.4.4/.claude/settings.local.json +0 -14
- python_rako_2025-0.4.4/.github/workflows/ci.yml +0 -54
- python_rako_2025-0.4.4/.github/workflows/release.yml +0 -50
- python_rako_2025-0.4.4/PKG-INFO +0 -177
- python_rako_2025-0.4.4/README.md +0 -138
- python_rako_2025-0.4.4/python_rako/__init__.py +0 -69
- python_rako_2025-0.4.4/python_rako/__version__.py +0 -1
- python_rako_2025-0.4.4/python_rako/bridge.py +0 -382
- python_rako_2025-0.4.4/python_rako/const.py +0 -59
- python_rako_2025-0.4.4/python_rako/exceptions.py +0 -12
- python_rako_2025-0.4.4/tests/README_TESTING.md +0 -46
- python_rako_2025-0.4.4/tests_integration/conftest.py +0 -21
- python_rako_2025-0.4.4/tests_integration/test_command_live.py +0 -106
- python_rako_2025-0.4.4/tests_integration/test_general_live.py +0 -41
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.editorconfig +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.flake8 +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.gitattributes +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.github/dependabot.yml +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.isort.cfg +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/.yamllint +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/LICENSE +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/catalog-info.yaml +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/conftest.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/doc/accessing-the-rako-bridge.pdf +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/examples/discover_all_devices.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/examples/example.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/examples/ventilation_example.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/examples/view_updates.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/python_rako/py.typed +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/resources/rako.xml +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/resources/rako2.xml +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/resources/rako3.xml +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_bridge.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_edge_cases.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_model.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests/test_xml_parsing.py +0 -0
- {python_rako_2025-0.4.4 → python_rako_2025-0.5.0}/tests_integration/__init__.py +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
[run]
|
|
2
2
|
source = python_rako
|
|
3
|
+
# Keep this in step with [tool.coverage.run] in pyproject.toml -- this file
|
|
4
|
+
# takes precedence over it. __init__.py and bridge.py used to be omitted here,
|
|
5
|
+
# which silently excluded the bridge API from the coverage gate.
|
|
3
6
|
omit =
|
|
4
|
-
python_rako/
|
|
5
|
-
python_rako/bridge.py
|
|
7
|
+
python_rako/__version__.py
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
[report]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Continuous Integration
|
|
3
|
+
|
|
4
|
+
on: [push, pull_request]
|
|
5
|
+
|
|
6
|
+
concurrency:
|
|
7
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
8
|
+
cancel-in-progress: true
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
linting:
|
|
12
|
+
name: Linting
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checking out code from GitHub
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v5
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
- name: Create virtual environment
|
|
22
|
+
run: uv venv .venv --python 3.13
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv pip install --python .venv/bin/python -e '.[dev]'
|
|
25
|
+
- name: Run pre-commit on all files
|
|
26
|
+
run: .venv/bin/pre-commit run --all-files --show-diff-on-failure
|
|
27
|
+
|
|
28
|
+
test:
|
|
29
|
+
name: Python ${{ matrix.python }} on ${{ matrix.os }}
|
|
30
|
+
runs-on: ${{ matrix.os }}-latest
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
os: [ubuntu]
|
|
35
|
+
python: ["3.12", "3.13"]
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checking out code from GitHub
|
|
38
|
+
uses: actions/checkout@v4
|
|
39
|
+
- name: Install uv
|
|
40
|
+
uses: astral-sh/setup-uv@v5
|
|
41
|
+
with:
|
|
42
|
+
enable-cache: true
|
|
43
|
+
- name: Create virtual environment
|
|
44
|
+
run: uv venv .venv --python ${{ matrix.python }}
|
|
45
|
+
- name: Install dependencies
|
|
46
|
+
run: uv pip install --python .venv/bin/python -e '.[test]'
|
|
47
|
+
- name: Run tests with coverage
|
|
48
|
+
run: .venv/bin/python -m pytest
|
|
49
|
+
- name: Upload coverage to Codecov
|
|
50
|
+
if: matrix.python == '3.12' && matrix.os == 'ubuntu'
|
|
51
|
+
uses: codecov/codecov-action@v5
|
|
52
|
+
with:
|
|
53
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
54
|
+
file: ./coverage.xml
|
|
55
|
+
flags: unittests
|
|
56
|
+
name: codecov-umbrella
|
|
57
|
+
|
|
58
|
+
packaging:
|
|
59
|
+
name: Build & verify distribution
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
steps:
|
|
62
|
+
- name: Checking out code from GitHub
|
|
63
|
+
uses: actions/checkout@v4
|
|
64
|
+
- name: Install uv
|
|
65
|
+
uses: astral-sh/setup-uv@v5
|
|
66
|
+
with:
|
|
67
|
+
enable-cache: true
|
|
68
|
+
- name: Create virtual environment
|
|
69
|
+
run: uv venv .venv --python 3.13
|
|
70
|
+
- name: Install build tooling
|
|
71
|
+
run: uv pip install --python .venv/bin/python build twine
|
|
72
|
+
- name: Build sdist and wheel
|
|
73
|
+
run: .venv/bin/python -m build
|
|
74
|
+
- name: Check distribution metadata (twine)
|
|
75
|
+
run: .venv/bin/python -m twine check dist/*
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Release
|
|
3
|
+
|
|
4
|
+
# Two ways to run this workflow:
|
|
5
|
+
#
|
|
6
|
+
# - "release: published" -> real release. Builds, verifies the tag matches
|
|
7
|
+
# python_rako/__version__.py, and publishes to the real PyPI (environment: pypi).
|
|
8
|
+
#
|
|
9
|
+
# - "workflow_dispatch" -> dry run. Builds and publishes to TestPyPI
|
|
10
|
+
# (environment: testpypi) instead. Safe to run at any time; never touches
|
|
11
|
+
# the real PyPI. Use this to sanity-check the pipeline before cutting a
|
|
12
|
+
# real release.
|
|
13
|
+
#
|
|
14
|
+
# See RELEASING.md for the full maintainer walkthrough and the one-time
|
|
15
|
+
# Trusted Publisher setup this workflow depends on.
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
release:
|
|
19
|
+
types: [published]
|
|
20
|
+
workflow_dispatch: {}
|
|
21
|
+
|
|
22
|
+
permissions: {}
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
build:
|
|
26
|
+
name: Build & verify distribution
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
permissions:
|
|
29
|
+
contents: read
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checking out code from GitHub
|
|
32
|
+
uses: actions/checkout@v4
|
|
33
|
+
|
|
34
|
+
- name: Install uv
|
|
35
|
+
uses: astral-sh/setup-uv@v5
|
|
36
|
+
with:
|
|
37
|
+
enable-cache: true
|
|
38
|
+
|
|
39
|
+
- name: Create virtual environment
|
|
40
|
+
run: uv venv .venv --python 3.13
|
|
41
|
+
|
|
42
|
+
- name: Verify the release tag matches python_rako/__version__.py
|
|
43
|
+
if: github.event_name == 'release'
|
|
44
|
+
run: |
|
|
45
|
+
.venv/bin/python scripts/bump_version.py check "${{ github.event.release.tag_name }}"
|
|
46
|
+
|
|
47
|
+
- name: Install build tooling
|
|
48
|
+
run: uv pip install --python .venv/bin/python build twine
|
|
49
|
+
|
|
50
|
+
- name: Build sdist and wheel
|
|
51
|
+
run: .venv/bin/python -m build
|
|
52
|
+
|
|
53
|
+
- name: Check distribution metadata (twine)
|
|
54
|
+
run: .venv/bin/python -m twine check dist/*
|
|
55
|
+
|
|
56
|
+
- name: Smoke-test the built wheel in a clean venv
|
|
57
|
+
run: |
|
|
58
|
+
uv venv /tmp/smoke-venv --python 3.13
|
|
59
|
+
uv pip install --python /tmp/smoke-venv/bin/python dist/*.whl
|
|
60
|
+
/tmp/smoke-venv/bin/python -c "import python_rako; print('python_rako', python_rako.__version__)"
|
|
61
|
+
|
|
62
|
+
- name: Upload build artifacts
|
|
63
|
+
uses: actions/upload-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
if-no-files-found: error
|
|
68
|
+
|
|
69
|
+
publish-testpypi:
|
|
70
|
+
name: Publish to TestPyPI (dry run)
|
|
71
|
+
if: github.event_name == 'workflow_dispatch'
|
|
72
|
+
needs: build
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
environment:
|
|
75
|
+
name: testpypi
|
|
76
|
+
url: https://test.pypi.org/p/python-rako-2025
|
|
77
|
+
permissions:
|
|
78
|
+
id-token: write # required for PyPI Trusted Publishing
|
|
79
|
+
attestations: write # required for build provenance attestations
|
|
80
|
+
contents: read
|
|
81
|
+
steps:
|
|
82
|
+
- name: Download build artifacts
|
|
83
|
+
uses: actions/download-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: dist
|
|
86
|
+
path: dist/
|
|
87
|
+
|
|
88
|
+
- name: Publish to TestPyPI
|
|
89
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
90
|
+
with:
|
|
91
|
+
repository-url: https://test.pypi.org/legacy/
|
|
92
|
+
attestations: true
|
|
93
|
+
skip-existing: true # dry runs of an unchanged version must not fail
|
|
94
|
+
|
|
95
|
+
publish-pypi:
|
|
96
|
+
name: Publish to PyPI
|
|
97
|
+
if: github.event_name == 'release'
|
|
98
|
+
needs: build
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
environment:
|
|
101
|
+
name: pypi
|
|
102
|
+
url: https://pypi.org/p/python-rako-2025
|
|
103
|
+
permissions:
|
|
104
|
+
id-token: write # required for PyPI Trusted Publishing
|
|
105
|
+
attestations: write # required for build provenance attestations
|
|
106
|
+
contents: read
|
|
107
|
+
steps:
|
|
108
|
+
- name: Download build artifacts
|
|
109
|
+
uses: actions/download-artifact@v4
|
|
110
|
+
with:
|
|
111
|
+
name: dist
|
|
112
|
+
path: dist/
|
|
113
|
+
|
|
114
|
+
- name: Publish to PyPI
|
|
115
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
116
|
+
with:
|
|
117
|
+
attestations: true
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
repos:
|
|
3
3
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
4
|
-
rev: v0.
|
|
4
|
+
rev: v0.16.4
|
|
5
5
|
hooks:
|
|
6
|
-
- id: ruff
|
|
6
|
+
- id: ruff-check
|
|
7
7
|
args: [--fix]
|
|
8
8
|
- id: ruff-format
|
|
9
9
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
10
|
-
rev:
|
|
10
|
+
rev: v6.0.0
|
|
11
11
|
hooks:
|
|
12
12
|
- id: trailing-whitespace
|
|
13
13
|
- id: end-of-file-fixer
|
|
@@ -16,20 +16,20 @@ repos:
|
|
|
16
16
|
- id: check-docstring-first
|
|
17
17
|
- id: check-json
|
|
18
18
|
- id: check-yaml
|
|
19
|
-
- id:
|
|
19
|
+
- id: fix-byte-order-marker
|
|
20
20
|
- id: check-case-conflict
|
|
21
21
|
- id: check-executables-have-shebangs
|
|
22
22
|
- id: check-ast
|
|
23
23
|
- id: detect-private-key
|
|
24
24
|
- id: forbid-new-submodules
|
|
25
25
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
26
|
-
rev:
|
|
26
|
+
rev: v2.3.1
|
|
27
27
|
hooks:
|
|
28
28
|
- id: mypy
|
|
29
29
|
files: ^python_rako/.+\.py$
|
|
30
30
|
exclude: ^python_rako/__version__\.py$
|
|
31
31
|
additional_dependencies: [types-requests]
|
|
32
32
|
- repo: https://github.com/adrienverge/yamllint.git
|
|
33
|
-
rev: v1.
|
|
33
|
+
rev: v1.38.0
|
|
34
34
|
hooks:
|
|
35
35
|
- id: yamllint
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
Nothing yet.
|
|
11
|
+
|
|
12
|
+
## [0.5.0] - 2026-08-30
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Full UDP status decoder (`python_rako.protocol`): every documented instruction
|
|
17
|
+
(OFF, FADE_UP/DOWN, SC1–SC4, IDENT, LEVEL_SET, STORE, STOP, CUSTOM_232,
|
|
18
|
+
HOLIDAY, SET_SCENE, FADE, SET_LEVEL), the empirically observed undocumented
|
|
19
|
+
0x33 level-toggle, and a typed `UnknownStatusMessage` for anything else —
|
|
20
|
+
nothing is silently dropped any more. Messages carry a `MessageOrigin`
|
|
21
|
+
(sensor vs control, derived from flags bit 3) and 10-bit room ids.
|
|
22
|
+
- `StatusListener`: supervised broadcast listener with automatic restart and
|
|
23
|
+
backoff, health reporting, a 300 ms duplicate window (the bridge re-sends
|
|
24
|
+
some keypad events ~200 ms apart), and subscriber fan-out.
|
|
25
|
+
- Echo-verified commands: `Bridge.send_command`, `set_room_scene`,
|
|
26
|
+
`set_room_level`, `set_channel_level`, `fade_up`, `fade_down`, `stop_fade`
|
|
27
|
+
wait for the bridge's own status broadcast to confirm the command took
|
|
28
|
+
effect (typically 150–300 ms), retry once on silence, then raise
|
|
29
|
+
`RakoCommandError`. The echoed message is returned so callers update state
|
|
30
|
+
from what the bridge actually did.
|
|
31
|
+
- `BridgeStateSnapshot`: room/channel state with per-channel provenance
|
|
32
|
+
(`StateSource`) and a `reconcile()` rule that never overwrites a fresher
|
|
33
|
+
level broadcast with a stale scene-derived level, nor resurrects a scene for
|
|
34
|
+
a room whose last event was a fade.
|
|
35
|
+
- `Bridge.get_scene_cache_http()` reads the scene cache over HTTP
|
|
36
|
+
(`scenes.htm`) so polling never contends with the UDP listener socket.
|
|
37
|
+
- **Command pacing** (`python_rako.pacing.CommandQueue`): every command now goes
|
|
38
|
+
through a per-bridge FIFO queue that sends no faster than
|
|
39
|
+
`min_command_interval` (default `DEFAULT_MIN_COMMAND_INTERVAL` = 1.25 s —
|
|
40
|
+
measured on a live bridge: 1.0 s spacing was loss-free, 0.75 s silently
|
|
41
|
+
dropped a command; default = fastest clean interval x 1.25 margin) and never
|
|
42
|
+
overlaps a command still waiting
|
|
43
|
+
for its echo. Requests that arrive too fast are queued, never dropped — the
|
|
44
|
+
bridge silently ignores commands sent too close together. Commands for the
|
|
45
|
+
same `(room, channel)` coalesce: a newer one replaces a waiting one in place,
|
|
46
|
+
keeping its queue position, so a slider drag becomes a single send and the
|
|
47
|
+
superseded callers get the echo of the command that actually ran. Diagnostics
|
|
48
|
+
via `bridge.command_queue.stats` (depth, oldest age, sent/coalesced/failed),
|
|
49
|
+
`drain()` for orderly shutdown, `paced=False` on `send_command`/`set_*` as a
|
|
50
|
+
direct escape hatch, and a runtime-settable `bridge.min_command_interval`.
|
|
51
|
+
A fade and its stop are treated as one gesture: the stop for the target of
|
|
52
|
+
the fade just sent skips the queue and the interval (so a short tap stays
|
|
53
|
+
short), neither half can coalesce the other away, and pacing resumes from the
|
|
54
|
+
stop. New exception `RakoQueueClosedError` (a `RakoCommandError`) for
|
|
55
|
+
commands a closed queue will never send.
|
|
56
|
+
- `scripts/measure_interval.py`: live tool that finds the bridge's real minimum
|
|
57
|
+
safe interval by sending echo-verified off/on pairs at decreasing intervals,
|
|
58
|
+
and recommends a `min_interval` from the result.
|
|
59
|
+
- `Bridge` is now an async context manager; `Bridge.close()` releases sockets.
|
|
60
|
+
- `discover_bridge(timeout=5.0)`; new exceptions `RakoDiscoveryError`,
|
|
61
|
+
`RakoUnsupportedCommandError`, `RakoProtocolError`.
|
|
62
|
+
- `tests_integration/` rewritten on the new state/listener/echo-verify API,
|
|
63
|
+
gated behind `RAKO_LIVE=1` (mutating tests additionally behind
|
|
64
|
+
`RAKO_LIVE_MUTATE=1` and an operator-chosen `RAKO_TEST_ROOM`/
|
|
65
|
+
`RAKO_TEST_CHANNEL`) and the `live` pytest marker, so a plain `pytest` run
|
|
66
|
+
never collects them; `tests/test_state.py` gained a full-pipeline regression
|
|
67
|
+
test replaying every Phase-0 capture through `decode_packet` and
|
|
68
|
+
`BridgeStateSnapshot.apply`. New characterisation tools under `scripts/`
|
|
69
|
+
(`listen.py`, `snapshot.py`, `latency.py`) mirror the Phase 0 tooling
|
|
70
|
+
against the new API for exploring a live bridge by hand.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- **Behaviour change:** `set_*` methods no longer report success on a UDP
|
|
75
|
+
timeout. With a listener attached they raise `RakoCommandError` when the
|
|
76
|
+
bridge does not confirm; without one they return `None` and warn.
|
|
77
|
+
`BridgeCommanderUDP`/`BridgeCommanderHTTP` are deprecated delegates.
|
|
78
|
+
- `rako.xml` parsing runs off the event loop (`asyncio.to_thread`); the
|
|
79
|
+
unnecessary parse lock was removed.
|
|
80
|
+
- Scene-cache parsing now handles extended (10-bit) room ids correctly.
|
|
81
|
+
- Tooling refresh: ruff/mypy/pre-commit pins updated, Python 3.12/3.13 CI matrix.
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
- Dead code: `UDPMessageRateLimit`, `get_predicted_channel_brightness`.
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- Release pipeline: the release workflow no longer overwrites
|
|
90
|
+
`python_rako/__version__.py` with the raw git tag (which produced an
|
|
91
|
+
invalid Python file). It now verifies the release tag matches
|
|
92
|
+
`__version__.py` and fails loudly on mismatch instead of publishing a
|
|
93
|
+
broken build.
|
|
94
|
+
- Release workflow now publishes to PyPI using **Trusted Publishing**
|
|
95
|
+
(OIDC) instead of long-lived API tokens, with build attestations, a
|
|
96
|
+
pre-publish smoke test (build the wheel, install it into a clean venv,
|
|
97
|
+
import it), and a `workflow_dispatch`-triggered TestPyPI dry run.
|
|
98
|
+
- CI now also builds the sdist/wheel and runs `twine check` on every pull
|
|
99
|
+
request, so packaging breakage is caught before release day, not during
|
|
100
|
+
it.
|
|
101
|
+
|
|
102
|
+
<!--
|
|
103
|
+
When cutting a release, move the entries above into a new section here,
|
|
104
|
+
e.g.:
|
|
105
|
+
|
|
106
|
+
## [0.5.0] - 2026-09-01
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- ...
|
|
111
|
+
-->
|
|
112
|
+
|
|
113
|
+
[Unreleased]: https://github.com/SimonLeigh/python-rako/compare/v0.5.0...master
|
|
114
|
+
[0.5.0]: https://github.com/SimonLeigh/python-rako/releases/tag/v0.5.0
|
|
115
|
+
|
|
116
|
+
<!--
|
|
117
|
+
Note for the first tagged release under this process: no git tags exist in
|
|
118
|
+
this repository yet (0.4.1 was released without ever tagging the commit).
|
|
119
|
+
Once v0.5.0 (or whichever version comes first) is tagged, switch the link
|
|
120
|
+
above to a compare link, e.g.:
|
|
121
|
+
[Unreleased]: https://github.com/SimonLeigh/python-rako/compare/v0.5.0...HEAD
|
|
122
|
+
[0.5.0]: https://github.com/SimonLeigh/python-rako/releases/tag/v0.5.0
|
|
123
|
+
-->
|
|
@@ -107,18 +107,18 @@ install-dev: clean
|
|
|
107
107
|
|
|
108
108
|
.PHONY: bump-patch
|
|
109
109
|
bump-patch: ## Bump patch version (x.y.Z) and commit
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
python scripts/bump_version.py bump patch
|
|
111
|
+
git add python_rako/__version__.py
|
|
112
|
+
git commit -m "Bump version to $$(python scripts/bump_version.py current)"
|
|
113
113
|
|
|
114
114
|
.PHONY: bump-minor
|
|
115
115
|
bump-minor: ## Bump minor version (x.Y.z) and commit
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
python scripts/bump_version.py bump minor
|
|
117
|
+
git add python_rako/__version__.py
|
|
118
|
+
git commit -m "Bump version to $$(python scripts/bump_version.py current)"
|
|
119
119
|
|
|
120
120
|
.PHONY: bump-major
|
|
121
121
|
bump-major: ## Bump major version (X.y.z) and commit
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
python scripts/bump_version.py bump major
|
|
123
|
+
git add python_rako/__version__.py
|
|
124
|
+
git commit -m "Bump version to $$(python scripts/bump_version.py current)"
|