python-bsblan 4.2.0__tar.gz → 5.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.
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/copilot-instructions.md +17 -21
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/prompts/add-parameter.prompt.md +1 -1
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/prompts/code-review.prompt.md +3 -3
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/skills/bsblan-parameters/SKILL.md +4 -5
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/skills/bsblan-testing/SKILL.md +2 -3
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/codeql.yaml +2 -2
- python_bsblan-5.0.0/.github/workflows/linting.yaml +66 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/stale.yaml +1 -1
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.pre-commit-config.yaml +0 -6
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/PKG-INFO +7 -8
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/README.md +5 -5
- python_bsblan-5.0.0/examples/fetch_param.py +67 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/pyproject.toml +8 -9
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/__init__.py +2 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/bsblan.py +9 -9
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/constants.py +1 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/models.py +180 -148
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/sensor.json +11 -0
- python_bsblan-5.0.0/tests/test_entity_info.py +224 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_entity_info_ha.py +2 -2
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_sensor.py +8 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_state.py +1 -1
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_temperature_unit.py +6 -6
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/uv.lock +209 -286
- python_bsblan-4.2.0/.github/workflows/linting.yaml +0 -170
- python_bsblan-4.2.0/.github/workflows/typing.yaml +0 -36
- python_bsblan-4.2.0/tests/test_entity_info.py +0 -99
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.editorconfig +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.gitattributes +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/CODE_OF_CONDUCT.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/CONTRIBUTING.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/labels.yml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/release-drafter.yml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/renovate.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/auto-approve-renovate.yml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/labels.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/lock.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/pr-labels.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/release-drafter.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/release.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.github/workflows/tests.yaml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.gitignore +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.nvmrc +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.prettierignore +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/.yamllint +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/AGENTS.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/CLAUDE.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/LICENSE.md +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/examples/control.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/examples/discovery.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/examples/profile_init.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/examples/ruff.toml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/examples/speed_test.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/package-lock.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/package.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/sonar-project.properties +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/exceptions.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/py.typed +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/src/bsblan/utility.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/__init__.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/conftest.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/device.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/dict_version.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/hot_water_state.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/info.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/password.txt +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/state.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/static_state.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/thermostat_hvac.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/thermostat_temp.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/fixtures/time.json +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/ruff.toml +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_api_initialization.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_api_validation.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_auth.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_backoff_retry.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_bsblan.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_bsblan_edge_cases.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_configuration.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_constants.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_context_manager.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_device.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_dhw_time_switch.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_hot_water_additional.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_hotwater_state.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_include_parameter.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_info.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_initialization.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_read_parameters.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_reset_validation.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_schedule_models.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_set_hot_water_schedule.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_set_hotwater.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_static_state.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_temperature_validation.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_thermostat.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_time.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_utility.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_utility_additional.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_utility_edge_cases.py +0 -0
- {python_bsblan-4.2.0 → python_bsblan-5.0.0}/tests/test_version_errors.py +0 -0
|
@@ -16,15 +16,14 @@ This repository contains the `python-bsblan` library, an asynchronous Python cli
|
|
|
16
16
|
Always run these commands after making changes:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
# Run all
|
|
20
|
-
uv run
|
|
19
|
+
# Run all prek hooks (ruff, mypy, pylint)
|
|
20
|
+
uv run prek run --all-files
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Prek Includes
|
|
24
24
|
- **Ruff**: Linting and formatting (88 char line limit)
|
|
25
25
|
- **MyPy**: Static type checking
|
|
26
26
|
- **Pylint**: Code analysis
|
|
27
|
-
- **Pytest**: Test execution with coverage
|
|
28
27
|
|
|
29
28
|
### Coverage Requirements
|
|
30
29
|
- Maintain **95%+ total test coverage**
|
|
@@ -77,9 +76,8 @@ Parameters are identified by numeric IDs and mapped to readable names in `consta
|
|
|
77
76
|
|
|
78
77
|
2. **Add to model in `models.py`**:
|
|
79
78
|
```python
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
legionella_function_setpoint: ParameterValue | None = None
|
|
79
|
+
class HotWaterConfig(BaseModel):
|
|
80
|
+
legionella_function_setpoint: EntityInfo[float] | None = None
|
|
83
81
|
```
|
|
84
82
|
|
|
85
83
|
3. **Update method in `bsblan.py`** if the parameter is settable:
|
|
@@ -129,25 +127,23 @@ Defined in `constants.py`:
|
|
|
129
127
|
## Data Models
|
|
130
128
|
|
|
131
129
|
### Model Pattern
|
|
132
|
-
All models use `
|
|
130
|
+
All models use `pydantic` `BaseModel` for validation and serialization:
|
|
133
131
|
|
|
134
132
|
```python
|
|
135
|
-
from
|
|
136
|
-
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
133
|
+
from pydantic import BaseModel
|
|
137
134
|
|
|
138
|
-
|
|
139
|
-
class HotWaterConfig(DataClassORJSONMixin):
|
|
135
|
+
class HotWaterConfig(BaseModel):
|
|
140
136
|
"""Hot water configuration parameters."""
|
|
141
|
-
operating_mode:
|
|
142
|
-
nominal_setpoint:
|
|
137
|
+
operating_mode: EntityInfo[int] | None = None
|
|
138
|
+
nominal_setpoint: EntityInfo[float] | None = None
|
|
143
139
|
```
|
|
144
140
|
|
|
145
|
-
###
|
|
146
|
-
Each parameter returns
|
|
147
|
-
- `value`: The actual value
|
|
141
|
+
### EntityInfo Structure
|
|
142
|
+
Each parameter returns an `EntityInfo[T]` (generic `BaseModel`) with:
|
|
143
|
+
- `value`: The actual value (typed via generic `T`)
|
|
148
144
|
- `unit`: Unit of measurement
|
|
149
145
|
- `desc`: Human-readable description
|
|
150
|
-
- `
|
|
146
|
+
- `data_type`: Data type information
|
|
151
147
|
|
|
152
148
|
## Async Patterns
|
|
153
149
|
|
|
@@ -223,7 +219,7 @@ Test fixtures (JSON responses) are in `tests/fixtures/`
|
|
|
223
219
|
4. Update docstring with parameter description
|
|
224
220
|
5. Add state preparation logic in `_prepare_*_state()` method
|
|
225
221
|
6. Add tests for the new parameter
|
|
226
|
-
7. Run `uv run
|
|
222
|
+
7. Run `uv run prek run --all-files`
|
|
227
223
|
|
|
228
224
|
### Renaming a Parameter
|
|
229
225
|
|
|
@@ -233,7 +229,7 @@ When renaming parameters for consistency:
|
|
|
233
229
|
3. Update `bsblan.py` - method parameters and state handling
|
|
234
230
|
4. Update `tests/` - all test files using the parameter
|
|
235
231
|
5. Update `examples/` - any example code
|
|
236
|
-
6. Run `uv run
|
|
232
|
+
6. Run `uv run prek run --all-files`
|
|
237
233
|
|
|
238
234
|
## API Versions
|
|
239
235
|
|
|
@@ -245,7 +241,7 @@ Version-specific parameters are handled in `constants.py` with extension diction
|
|
|
245
241
|
|
|
246
242
|
## Don't Forget
|
|
247
243
|
|
|
248
|
-
- ✅ Run `uv run
|
|
244
|
+
- ✅ Run `uv run prek run --all-files` after every change
|
|
249
245
|
- ✅ Maintain 95%+ test coverage
|
|
250
246
|
- ✅ Use type hints on all functions
|
|
251
247
|
- ✅ Add docstrings to public methods
|
|
@@ -21,12 +21,12 @@ Review the changes against the python-bsblan coding standards.
|
|
|
21
21
|
- [ ] Patch coverage 100%
|
|
22
22
|
|
|
23
23
|
### Patterns
|
|
24
|
-
- [ ] Uses `
|
|
24
|
+
- [ ] Uses `pydantic` `BaseModel` for validation and serialization
|
|
25
25
|
- [ ] Uses `aiohttp` for async HTTP
|
|
26
26
|
- [ ] Follows existing parameter naming conventions
|
|
27
27
|
- [ ] Error handling uses custom exceptions (`BSBLANError`, `BSBLANConnectionError`)
|
|
28
28
|
|
|
29
|
-
###
|
|
29
|
+
### Prek
|
|
30
30
|
- [ ] Ruff passes (linting + formatting)
|
|
31
31
|
- [ ] MyPy passes (type checking)
|
|
32
32
|
- [ ] Pylint passes (code analysis)
|
|
@@ -35,6 +35,6 @@ Review the changes against the python-bsblan coding standards.
|
|
|
35
35
|
## Run Validation
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
uv run
|
|
38
|
+
uv run prek run --all-files
|
|
39
39
|
uv run pytest --cov=src/bsblan --cov-report=term-missing
|
|
40
40
|
```
|
|
@@ -28,12 +28,11 @@ BASE_HOT_WATER_PARAMS: Final[dict[str, str]] = {
|
|
|
28
28
|
|
|
29
29
|
### 2. Add to Model in `models.py`
|
|
30
30
|
|
|
31
|
-
Add the field to the appropriate
|
|
31
|
+
Add the field to the appropriate model:
|
|
32
32
|
|
|
33
33
|
```python
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
legionella_function_setpoint: ParameterValue | None = None
|
|
34
|
+
class HotWaterConfig(BaseModel):
|
|
35
|
+
legionella_function_setpoint: EntityInfo[float] | None = None
|
|
37
36
|
```
|
|
38
37
|
|
|
39
38
|
### 3. Update Method in `bsblan.py` (if settable)
|
|
@@ -100,7 +99,7 @@ When adding new sections or groups, the lock is created automatically on first a
|
|
|
100
99
|
Always run after changes:
|
|
101
100
|
|
|
102
101
|
```bash
|
|
103
|
-
uv run
|
|
102
|
+
uv run prek run --all-files
|
|
104
103
|
uv run pytest --cov=src/bsblan --cov-report=term-missing
|
|
105
104
|
```
|
|
106
105
|
|
|
@@ -101,12 +101,12 @@ uv run pytest -v
|
|
|
101
101
|
uv run pytest tests/test_bsblan.py::test_function_name
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
##
|
|
104
|
+
## Prek Hooks
|
|
105
105
|
|
|
106
106
|
Always run before committing:
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
|
-
uv run
|
|
109
|
+
uv run prek run --all-files
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
This runs:
|
|
@@ -114,7 +114,6 @@ This runs:
|
|
|
114
114
|
- **Ruff**: Linting and formatting (88 char line limit)
|
|
115
115
|
- **MyPy**: Static type checking
|
|
116
116
|
- **Pylint**: Code analysis
|
|
117
|
-
- **Pytest**: Test execution with coverage
|
|
118
117
|
|
|
119
118
|
## Mock Patterns
|
|
120
119
|
|
|
@@ -24,6 +24,6 @@ jobs:
|
|
|
24
24
|
- name: ⤵️ Check out code from GitHub
|
|
25
25
|
uses: actions/checkout@v6.0.2
|
|
26
26
|
- name: 🏗 Initialize CodeQL
|
|
27
|
-
uses: github/codeql-action/init@v4.32.
|
|
27
|
+
uses: github/codeql-action/init@v4.32.4
|
|
28
28
|
- name: 🚀 Perform CodeQL Analysis
|
|
29
|
-
uses: github/codeql-action/analyze@v4.32.
|
|
29
|
+
uses: github/codeql-action/analyze@v4.32.4
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Linting
|
|
3
|
+
|
|
4
|
+
# yamllint disable-line rule:truthy
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
DEFAULT_PYTHON: "3.13"
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
lint:
|
|
20
|
+
name: Prek hooks
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- name: ⤵️ Check out code from GitHub
|
|
24
|
+
uses: actions/checkout@v6.0.2
|
|
25
|
+
- name: 🏗 Set up uv
|
|
26
|
+
uses: astral-sh/setup-uv@v7
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
- name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
30
|
+
id: python
|
|
31
|
+
uses: actions/setup-python@v6.2.0
|
|
32
|
+
with:
|
|
33
|
+
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
34
|
+
- name: 🏗 Install Python dependencies
|
|
35
|
+
run: uv sync --dev
|
|
36
|
+
- name: 🚀 Run all prek hooks
|
|
37
|
+
env:
|
|
38
|
+
SKIP: no-commit-to-branch
|
|
39
|
+
run: uv run prek run --all-files
|
|
40
|
+
|
|
41
|
+
prettier:
|
|
42
|
+
name: Prettier
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- name: ⤵️ Check out code from GitHub
|
|
46
|
+
uses: actions/checkout@v6.0.2
|
|
47
|
+
- name: 🏗 Set up uv
|
|
48
|
+
uses: astral-sh/setup-uv@v7
|
|
49
|
+
with:
|
|
50
|
+
enable-cache: true
|
|
51
|
+
- name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
|
|
52
|
+
id: python
|
|
53
|
+
uses: actions/setup-python@v6.2.0
|
|
54
|
+
with:
|
|
55
|
+
python-version: ${{ env.DEFAULT_PYTHON }}
|
|
56
|
+
- name: 🏗 Install Python dependencies
|
|
57
|
+
run: uv sync --dev
|
|
58
|
+
- name: 🏗 Set up Node.js
|
|
59
|
+
uses: actions/setup-node@v6.2.0
|
|
60
|
+
with:
|
|
61
|
+
node-version-file: ".nvmrc"
|
|
62
|
+
cache: "npm"
|
|
63
|
+
- name: 🏗 Install NPM dependencies
|
|
64
|
+
run: npm install
|
|
65
|
+
- name: 🚀 Run prettier
|
|
66
|
+
run: uv run prek run prettier --all-files
|
|
@@ -109,12 +109,6 @@ repos:
|
|
|
109
109
|
language: system
|
|
110
110
|
types: [python]
|
|
111
111
|
entry: uv run pylint --exit-zero
|
|
112
|
-
- id: pytest
|
|
113
|
-
name: 🧪 Running tests and test coverage with pytest
|
|
114
|
-
language: system
|
|
115
|
-
types: [python]
|
|
116
|
-
entry: uv run pytest
|
|
117
|
-
pass_filenames: false
|
|
118
112
|
- id: trailing-whitespace
|
|
119
113
|
name: ✄ Trim Trailing Whitespace
|
|
120
114
|
language: system
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-bsblan
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.0.0
|
|
4
4
|
Summary: Asynchronous Python client for BSBLAN API
|
|
5
5
|
Project-URL: Homepage, https://github.com/liudger/python-bsblan
|
|
6
6
|
Project-URL: Repository, https://github.com/liudger/python-bsblan
|
|
@@ -25,9 +25,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
25
25
|
Requires-Python: >=3.12
|
|
26
26
|
Requires-Dist: aiohttp>=3.8.1
|
|
27
27
|
Requires-Dist: backoff>=2.2.1
|
|
28
|
-
Requires-Dist: mashumaro>=3.13.1
|
|
29
|
-
Requires-Dist: orjson>=3.9.10
|
|
30
28
|
Requires-Dist: packaging>=21.3
|
|
29
|
+
Requires-Dist: pydantic>=2.0
|
|
31
30
|
Requires-Dist: yarl>=1.7.2
|
|
32
31
|
Description-Content-Type: text/markdown
|
|
33
32
|
|
|
@@ -186,12 +185,12 @@ npm install
|
|
|
186
185
|
uv sync --dev
|
|
187
186
|
```
|
|
188
187
|
|
|
189
|
-
As this repository uses
|
|
190
|
-
are linted and tested with each commit. You can
|
|
191
|
-
manually, using the following command:
|
|
188
|
+
As this repository uses [prek][prek] (a faster, Rust-based drop-in replacement
|
|
189
|
+
for pre-commit), all changes are linted and tested with each commit. You can
|
|
190
|
+
run all checks and tests manually, using the following command:
|
|
192
191
|
|
|
193
192
|
```bash
|
|
194
|
-
uv run
|
|
193
|
+
uv run prek run --all-files
|
|
195
194
|
```
|
|
196
195
|
|
|
197
196
|
To run just the Python tests:
|
|
@@ -247,7 +246,7 @@ SOFTWARE.
|
|
|
247
246
|
[maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
|
|
248
247
|
[uv]: https://docs.astral.sh/uv/
|
|
249
248
|
[uv-install]: https://docs.astral.sh/uv/getting-started/installation/
|
|
250
|
-
[
|
|
249
|
+
[prek]: https://github.com/j178/prek
|
|
251
250
|
[project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg
|
|
252
251
|
[pypi]: https://pypi.org/project/python-bsblan/
|
|
253
252
|
[python-versions-shield]: https://img.shields.io/pypi/pyversions/python-bsblan
|
|
@@ -153,12 +153,12 @@ npm install
|
|
|
153
153
|
uv sync --dev
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
As this repository uses
|
|
157
|
-
are linted and tested with each commit. You can
|
|
158
|
-
manually, using the following command:
|
|
156
|
+
As this repository uses [prek][prek] (a faster, Rust-based drop-in replacement
|
|
157
|
+
for pre-commit), all changes are linted and tested with each commit. You can
|
|
158
|
+
run all checks and tests manually, using the following command:
|
|
159
159
|
|
|
160
160
|
```bash
|
|
161
|
-
uv run
|
|
161
|
+
uv run prek run --all-files
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
To run just the Python tests:
|
|
@@ -214,7 +214,7 @@ SOFTWARE.
|
|
|
214
214
|
[maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
|
|
215
215
|
[uv]: https://docs.astral.sh/uv/
|
|
216
216
|
[uv-install]: https://docs.astral.sh/uv/getting-started/installation/
|
|
217
|
-
[
|
|
217
|
+
[prek]: https://github.com/j178/prek
|
|
218
218
|
[project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg
|
|
219
219
|
[pypi]: https://pypi.org/project/python-bsblan/
|
|
220
220
|
[python-versions-shield]: https://img.shields.io/pypi/pyversions/python-bsblan
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Fetch one or more BSB-LAN parameters and print the raw API response.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
export BSBLAN_HOST=10.0.2.60
|
|
5
|
+
export BSBLAN_PASSKEY=your_passkey # if needed
|
|
6
|
+
|
|
7
|
+
# Single parameter
|
|
8
|
+
cd examples && python fetch_param.py 3113
|
|
9
|
+
|
|
10
|
+
# Multiple parameters
|
|
11
|
+
cd examples && python fetch_param.py 3113 8700 8740
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import asyncio
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from bsblan import BSBLAN, BSBLANConfig
|
|
21
|
+
from discovery import get_bsblan_host, get_config_from_env
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def fetch_parameters(param_ids: list[str]) -> None:
|
|
25
|
+
"""Fetch and print raw API response for the given parameter IDs.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
param_ids: List of BSB-LAN parameter IDs to fetch.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
host, port = await get_bsblan_host()
|
|
32
|
+
env = get_config_from_env()
|
|
33
|
+
|
|
34
|
+
config = BSBLANConfig(
|
|
35
|
+
host=host,
|
|
36
|
+
port=port,
|
|
37
|
+
passkey=str(env["passkey"]) if env.get("passkey") else None,
|
|
38
|
+
username=str(env["username"]) if env.get("username") else None,
|
|
39
|
+
password=str(env["password"]) if env.get("password") else None,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
params_string = ",".join(param_ids)
|
|
43
|
+
|
|
44
|
+
async with BSBLAN(config) as client:
|
|
45
|
+
result = await client._request( # noqa: SLF001
|
|
46
|
+
params={"Parameter": params_string},
|
|
47
|
+
)
|
|
48
|
+
print(f"Raw API response for parameter(s) {params_string}:")
|
|
49
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def main() -> None:
|
|
53
|
+
"""Parse arguments and run the fetch."""
|
|
54
|
+
parser = argparse.ArgumentParser(
|
|
55
|
+
description="Fetch BSB-LAN parameters and print raw JSON response.",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"params",
|
|
59
|
+
nargs="+",
|
|
60
|
+
help="One or more BSB-LAN parameter IDs (e.g. 3113 8700)",
|
|
61
|
+
)
|
|
62
|
+
args = parser.parse_args()
|
|
63
|
+
asyncio.run(fetch_parameters(args.params))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-bsblan"
|
|
3
|
-
version = "
|
|
3
|
+
version = "5.0.0"
|
|
4
4
|
description = "Asynchronous Python client for BSBLAN API"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Willem-Jan van Rootselaar", email = "liudgervr@gmail.com"}
|
|
@@ -29,8 +29,7 @@ dependencies = [
|
|
|
29
29
|
"yarl>=1.7.2",
|
|
30
30
|
"packaging>=21.3",
|
|
31
31
|
"backoff>=2.2.1",
|
|
32
|
-
"
|
|
33
|
-
"orjson>=3.9.10",
|
|
32
|
+
"pydantic>=2.0",
|
|
34
33
|
]
|
|
35
34
|
|
|
36
35
|
[project.urls]
|
|
@@ -148,7 +147,7 @@ ignore = [
|
|
|
148
147
|
"D213", # Conflicts with other rules
|
|
149
148
|
"D417", # False positives in some occasions
|
|
150
149
|
"PLR2004", # Just annoying, not really useful
|
|
151
|
-
|
|
150
|
+
"UP046", # Pydantic v2 does not support PEP 695 type parameter syntax
|
|
152
151
|
# Conflicts with the Ruff formatter
|
|
153
152
|
"COM812",
|
|
154
153
|
"ISC001",
|
|
@@ -162,7 +161,7 @@ fixture-parentheses = false
|
|
|
162
161
|
known-first-party = ["bsblan"]
|
|
163
162
|
|
|
164
163
|
[tool.ruff.lint.flake8-type-checking]
|
|
165
|
-
runtime-evaluated-base-classes = ["
|
|
164
|
+
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
|
166
165
|
|
|
167
166
|
[tool.ruff.lint.mccabe]
|
|
168
167
|
max-complexity = 25
|
|
@@ -189,16 +188,16 @@ dev = [
|
|
|
189
188
|
# hatch is required to support type hinting and proper packaging of the py.typed file.
|
|
190
189
|
"hatch>=1.14.1",
|
|
191
190
|
"isort==7.0.0",
|
|
192
|
-
"ty==0.0.
|
|
193
|
-
"
|
|
191
|
+
"ty==0.0.18",
|
|
192
|
+
"prek>=0.3.3",
|
|
194
193
|
"pre-commit-hooks==6.0.0",
|
|
195
|
-
"pylint==4.0.
|
|
194
|
+
"pylint==4.0.5",
|
|
196
195
|
"pytest>=8.3.5",
|
|
197
196
|
"pytest-asyncio==1.3.0",
|
|
198
197
|
"pytest-cov==7.0.0",
|
|
199
198
|
"pytest-xdist>=3.8.0",
|
|
200
199
|
"pyupgrade==3.21.2",
|
|
201
|
-
"ruff==0.15.
|
|
200
|
+
"ruff==0.15.2",
|
|
202
201
|
"safety==3.7.0",
|
|
203
202
|
"vulture==2.14",
|
|
204
203
|
"yamllint==1.38.0",
|
|
@@ -16,6 +16,7 @@ from .models import (
|
|
|
16
16
|
DHWSchedule,
|
|
17
17
|
DHWTimeSwitchPrograms,
|
|
18
18
|
EntityInfo,
|
|
19
|
+
EntityValue,
|
|
19
20
|
HotWaterConfig,
|
|
20
21
|
HotWaterSchedule,
|
|
21
22
|
HotWaterState,
|
|
@@ -41,6 +42,7 @@ __all__ = [
|
|
|
41
42
|
"Device",
|
|
42
43
|
"DeviceTime",
|
|
43
44
|
"EntityInfo",
|
|
45
|
+
"EntityValue",
|
|
44
46
|
"HVACActionCategory",
|
|
45
47
|
"HeatingCircuitStatus",
|
|
46
48
|
"HotWaterConfig",
|
|
@@ -524,8 +524,8 @@ class BSBLAN:
|
|
|
524
524
|
try:
|
|
525
525
|
static_values = await self.static_values()
|
|
526
526
|
if static_values.min_temp is not None:
|
|
527
|
-
self._min_temp =
|
|
528
|
-
logger.debug("Min temperature initialized: %
|
|
527
|
+
self._min_temp = static_values.min_temp.value
|
|
528
|
+
logger.debug("Min temperature initialized: %s", self._min_temp)
|
|
529
529
|
else:
|
|
530
530
|
logger.warning(
|
|
531
531
|
"min_temp not available from device, "
|
|
@@ -533,8 +533,8 @@ class BSBLAN:
|
|
|
533
533
|
)
|
|
534
534
|
|
|
535
535
|
if static_values.max_temp is not None:
|
|
536
|
-
self._max_temp =
|
|
537
|
-
logger.debug("Max temperature initialized: %
|
|
536
|
+
self._max_temp = static_values.max_temp.value
|
|
537
|
+
logger.debug("Max temperature initialized: %s", self._max_temp)
|
|
538
538
|
else:
|
|
539
539
|
logger.warning(
|
|
540
540
|
"max_temp not available from device, "
|
|
@@ -841,7 +841,7 @@ class BSBLAN:
|
|
|
841
841
|
params = await self._extract_params_summary(section_params)
|
|
842
842
|
data = await self._request(params={"Parameter": params["string_par"]})
|
|
843
843
|
data = dict(zip(params["list"], list(data.values()), strict=True))
|
|
844
|
-
return model_class.
|
|
844
|
+
return model_class.model_validate(data)
|
|
845
845
|
|
|
846
846
|
async def state(self, include: list[str] | None = None) -> State:
|
|
847
847
|
"""Get the current state from BSBLAN device.
|
|
@@ -911,7 +911,7 @@ class BSBLAN:
|
|
|
911
911
|
|
|
912
912
|
"""
|
|
913
913
|
device_info = await self._request(base_path="/JI")
|
|
914
|
-
return Device.
|
|
914
|
+
return Device.model_validate(device_info)
|
|
915
915
|
|
|
916
916
|
async def info(self, include: list[str] | None = None) -> Info:
|
|
917
917
|
"""Get information about the current heating system config.
|
|
@@ -942,7 +942,7 @@ class BSBLAN:
|
|
|
942
942
|
data = await self._request(params={"Parameter": "0"})
|
|
943
943
|
# Create the data dictionary in the expected format
|
|
944
944
|
time_data = {"time": data["0"]}
|
|
945
|
-
return DeviceTime.
|
|
945
|
+
return DeviceTime.model_validate(time_data)
|
|
946
946
|
|
|
947
947
|
async def set_time(self, time_value: str) -> None:
|
|
948
948
|
"""Set the time on the BSB-LAN device.
|
|
@@ -1146,7 +1146,7 @@ class BSBLAN:
|
|
|
1146
1146
|
params = await self._extract_params_summary(filtered_params)
|
|
1147
1147
|
data = await self._request(params={"Parameter": params["string_par"]})
|
|
1148
1148
|
data = dict(zip(params["list"], list(data.values()), strict=True))
|
|
1149
|
-
return model_class.
|
|
1149
|
+
return model_class.model_validate(data)
|
|
1150
1150
|
|
|
1151
1151
|
async def hot_water_state(self, include: list[str] | None = None) -> HotWaterState:
|
|
1152
1152
|
"""Get essential hot water state for frequent polling.
|
|
@@ -1436,7 +1436,7 @@ class BSBLAN:
|
|
|
1436
1436
|
if param_id in response_data:
|
|
1437
1437
|
param_data = response_data[param_id]
|
|
1438
1438
|
if param_data and isinstance(param_data, dict):
|
|
1439
|
-
result[param_id] = EntityInfo.
|
|
1439
|
+
result[param_id] = EntityInfo.model_validate(param_data)
|
|
1440
1440
|
|
|
1441
1441
|
return result
|
|
1442
1442
|
|