python-bsblan 6.1.1__tar.gz → 6.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. python_bsblan-6.1.3/.github/agents/pr-review.agent.md +39 -0
  2. python_bsblan-6.1.3/.github/agents/tdd-refactor.agent.md +97 -0
  3. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/codeql.yaml +3 -3
  4. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/dependency-review.yaml +1 -1
  5. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/docs.yaml +2 -2
  6. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/labels.yaml +1 -1
  7. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/linting.yaml +4 -4
  8. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/release.yaml +3 -3
  9. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/scorecard.yml +2 -2
  10. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/tests.yaml +7 -7
  11. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/typing.yaml +2 -2
  12. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/PKG-INFO +22 -1
  13. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/README.md +21 -0
  14. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/api/models.md +4 -0
  15. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/getting-started.md +29 -5
  16. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/index.md +2 -1
  17. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/control.py +13 -2
  18. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/package-lock.json +4 -4
  19. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/package.json +1 -1
  20. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/pyproject.toml +5 -5
  21. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/__init__.py +9 -1
  22. python_bsblan-6.1.3/src/bsblan/_temperature.py +324 -0
  23. python_bsblan-6.1.3/src/bsblan/_transport.py +221 -0
  24. python_bsblan-6.1.3/src/bsblan/_validation.py +402 -0
  25. python_bsblan-6.1.3/src/bsblan/_version.py +77 -0
  26. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/bsblan.py +216 -634
  27. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/constants.py +51 -15
  28. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/exceptions.py +17 -0
  29. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/models.py +11 -0
  30. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/conftest.py +3 -3
  31. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_api_initialization.py +6 -6
  32. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_api_validation.py +48 -48
  33. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_auth.py +2 -2
  34. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_bsblan_edge_cases.py +4 -4
  35. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_circuit.py +138 -60
  36. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_configuration.py +5 -5
  37. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_constants.py +34 -12
  38. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_hot_water_additional.py +76 -76
  39. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_hotwater_state.py +16 -16
  40. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_include_parameter.py +49 -47
  41. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_info.py +3 -3
  42. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_initialization.py +9 -20
  43. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_pps.py +25 -17
  44. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_read_parameters.py +7 -7
  45. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_sensor.py +7 -7
  46. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_state.py +12 -12
  47. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_static_state.py +5 -5
  48. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_temperature_unit.py +23 -23
  49. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_temperature_validation.py +38 -29
  50. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_thermostat.py +3 -3
  51. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_utility_edge_cases.py +3 -3
  52. python_bsblan-6.1.3/tests/test_version_errors.py +297 -0
  53. python_bsblan-6.1.1/tests/test_version_errors.py +0 -219
  54. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.editorconfig +0 -0
  55. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.gitattributes +0 -0
  56. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/CODE_OF_CONDUCT.md +0 -0
  57. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/CONTRIBUTING.md +0 -0
  58. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
  59. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  60. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  61. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/SECURITY.md +0 -0
  62. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/agents/security-reviewer.agent.md +0 -0
  63. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/copilot-instructions.md +0 -0
  64. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/hooks/run-validation-after-edits.json +0 -0
  65. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/hooks/run_validation_after_edits.sh +0 -0
  66. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/labels.yml +0 -0
  67. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/prompts/add-parameter.prompt.md +0 -0
  68. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/prompts/code-review.prompt.md +0 -0
  69. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/release-drafter.yml +0 -0
  70. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/renovate.json +0 -0
  71. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/skills/bsblan-parameters/SKILL.md +0 -0
  72. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/skills/bsblan-testing/SKILL.md +0 -0
  73. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/skills/feature-doc-updates/SKILL.md +0 -0
  74. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/auto-approve-renovate.yml +0 -0
  75. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/lock.yaml +0 -0
  76. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/pr-labels.yaml +0 -0
  77. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/release-drafter.yaml +0 -0
  78. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/workflows/stale.yaml +0 -0
  79. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.github/zizmor.yml +0 -0
  80. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.gitignore +0 -0
  81. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.nvmrc +0 -0
  82. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.pre-commit-config.yaml +0 -0
  83. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.prettierignore +0 -0
  84. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/.yamllint +0 -0
  85. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/AGENTS.md +0 -0
  86. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/CLAUDE.md +0 -0
  87. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/LICENSE.md +0 -0
  88. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/Makefile +0 -0
  89. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/api/client.md +0 -0
  90. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/api/constants.md +0 -0
  91. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/docs/api/exceptions.md +0 -0
  92. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/discovery.py +0 -0
  93. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/fetch_param.py +0 -0
  94. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/profile_init.py +0 -0
  95. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/ruff.toml +0 -0
  96. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/examples/speed_test.py +0 -0
  97. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/mkdocs.yml +0 -0
  98. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/sonar-project.properties +0 -0
  99. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/py.typed +0 -0
  100. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/src/bsblan/utility.py +0 -0
  101. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/__init__.py +0 -0
  102. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/device.json +0 -0
  103. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/dict_version.json +0 -0
  104. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/hot_water_state.json +0 -0
  105. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/info.json +0 -0
  106. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/password.txt +0 -0
  107. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/pps_device.json +0 -0
  108. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/pps_state.json +0 -0
  109. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/pps_static_values.json +0 -0
  110. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/sensor.json +0 -0
  111. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/state.json +0 -0
  112. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/state_circuit2.json +0 -0
  113. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/static_state.json +0 -0
  114. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/static_state_circuit2.json +0 -0
  115. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/thermostat_hvac.json +0 -0
  116. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/thermostat_temp.json +0 -0
  117. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/fixtures/time.json +0 -0
  118. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/ruff.toml +0 -0
  119. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_backoff_retry.py +0 -0
  120. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_bsblan.py +0 -0
  121. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_context_manager.py +0 -0
  122. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_device.py +0 -0
  123. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_dhw_time_switch.py +0 -0
  124. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_entity_info.py +0 -0
  125. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_entity_info_ha.py +0 -0
  126. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_heating_schedule.py +0 -0
  127. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_reset_validation.py +0 -0
  128. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_schedule_models.py +0 -0
  129. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_set_heating_schedule.py +0 -0
  130. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_set_hot_water_schedule.py +0 -0
  131. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_set_hotwater.py +0 -0
  132. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_time.py +0 -0
  133. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_utility.py +0 -0
  134. {python_bsblan-6.1.1 → python_bsblan-6.1.3}/tests/test_utility_additional.py +0 -0
@@ -0,0 +1,39 @@
1
+ ---
2
+ description: "Use when reviewing code changes, diffs, or a branch before opening or updating a pull request. Checks that changes are clean, lean, minimal, idiomatic, well-tested, and ready for review. Trigger phrases: review my changes, review the diff, PR review, is this ready to merge, check before pushing."
3
+ name: "PR Reviewer"
4
+ tools: [read, search, execute]
5
+ argument-hint: "What to review (branch, diff, or files) and any specific concerns"
6
+ user-invocable: true
7
+ ---
8
+ You are a meticulous code reviewer for the python-bsblan library. Your job is to
9
+ review pending changes and confirm they are clean, lean, and minimal before a
10
+ pull request — nothing more.
11
+
12
+ ## Constraints
13
+ - DO NOT edit, refactor, or write code. You review only; report findings and let the author act.
14
+ - DO NOT suggest features, abstractions, or "improvements" beyond the diff's stated purpose.
15
+ - DO NOT approve changes that add docstrings, comments, or type hints to lines the diff did not already touch.
16
+ - ONLY assess the actual changes (working tree + commits vs the default branch `main`).
17
+
18
+ ## Approach
19
+ 1. Establish the diff scope. Run `git fetch` if needed, then `git --no-pager diff main...HEAD` and `git --no-pager diff` to capture committed and uncommitted changes.
20
+ 2. Read each changed file's surrounding context so feedback reflects real code, not the diff in isolation.
21
+ 3. Evaluate against the checklist below, flagging the smallest set of concrete problems.
22
+ 4. Verify the repo quality gate when changes are non-trivial: run `uv run pytest` and confirm coverage stays at 95%+ total with 100% patch coverage (via CI/Codecov), and run `SKIP=no-commit-to-branch uv run prek run --all-files`.
23
+
24
+ ## Review Checklist
25
+ - **Minimal**: every hunk is necessary for the stated goal; no drive-by edits, reformatting, or unrelated files.
26
+ - **Lean**: no dead code, duplication, unused imports/vars, or speculative error handling for cases that can't occur.
27
+ - **Idiomatic**: follows AGENTS.md conventions — type hints, <=88 char lines, `snake_case` params, pydantic for response models, `@dataclass` for set-param payloads, one `/JS` request per populated parameter.
28
+ - **Correct**: logic is sound; edge cases and version gating align with the constants.
29
+ - **Tested**: new behavior has focused tests; patch coverage is 100%.
30
+ - **Docs**: user-visible changes update README/docs/examples to match the code exactly.
31
+ - **Secure**: no secrets, injection risks, or OWASP Top 10 issues.
32
+
33
+ ## Output Format
34
+ Return a single review:
35
+ - **Verdict**: Ready / Needs changes / Blocked.
36
+ - **Must fix**: numbered list, each with `path:line`, the problem, and the minimal fix.
37
+ - **Consider**: optional, lower-priority notes (clearly non-blocking).
38
+ - **Validation**: the commands you ran and their result (pass/fail), or why you skipped them.
39
+ Keep it concise. If the diff is clean, say so plainly without inventing issues.
@@ -0,0 +1,97 @@
1
+ ---
2
+ description: "Improve code quality, apply security best practices, and enhance design whilst maintaining green tests and GitHub issue compliance."
3
+ name: "TDD Refactor Phase - Improve Quality & Security"
4
+ tools: ["github/*", "search/fileSearch", "edit/editFiles", "execute/runTests", "execute/runInTerminal", "execute/getTerminalOutput", "execute/testFailure", "read/readFile", "read/terminalLastCommand", "read/terminalSelection", "read/problems", "search/codebase"]
5
+ ---
6
+
7
+ # TDD Refactor Phase - Improve Quality & Security
8
+
9
+ Clean up code, apply security best practices, and enhance design whilst keeping all tests green and maintaining GitHub issue compliance.
10
+
11
+ ## Repository Standards
12
+ Follow `AGENTS.md` for python-bsblan conventions and required validation (at minimum: `uv run prek run --all-files` and `uv run pytest`).
13
+
14
+ ## GitHub Issue Integration
15
+
16
+ ### Issue Completion Validation
17
+
18
+ - **Verify all acceptance criteria met** - Cross-check implementation against GitHub issue requirements
19
+ - **Update issue status** - Mark issue as completed or identify remaining work
20
+ - **Document design decisions** - Comment on issue with architectural choices made during refactor
21
+ - **Link related issues** - Identify technical debt or follow-up issues created during refactoring
22
+
23
+ ### Quality Gates
24
+
25
+ - **Definition of Done adherence** - Ensure all issue checklist items are satisfied
26
+ - **Security requirements** - Address any security considerations mentioned in issue
27
+ - **Performance criteria** - Meet any performance requirements specified in issue
28
+ - **Documentation updates** - Update any documentation referenced in issue
29
+
30
+ ## Core Principles
31
+
32
+ ### Code Quality Improvements
33
+
34
+ - **Remove duplication** - Extract common code into reusable methods or classes
35
+ - **Improve readability** - Use intention-revealing names and clear structure aligned with issue domain
36
+ - **Apply SOLID principles** - Single responsibility, dependency inversion, etc.
37
+ - **Simplify complexity** - Break down large methods, reduce cyclomatic complexity
38
+
39
+ ### Security Hardening
40
+
41
+ - **Input validation** - Sanitise and validate all external inputs per issue security requirements
42
+ - **Authentication/Authorisation** - Implement proper access controls if specified in issue
43
+ - **Data protection** - Encrypt sensitive data, use secure connection strings
44
+ - **Error handling** - Avoid information disclosure through exception details
45
+ - **Dependency scanning** - Check for vulnerable packages (`npm audit`, `pip audit`, `dotnet list package --vulnerable`, etc.)
46
+ - **Secrets management** - Use environment variables or a secrets manager; never hard-code credentials
47
+ - **OWASP compliance** - Address security concerns mentioned in issue or related security tickets
48
+
49
+ ### Design Excellence
50
+
51
+ - **Design patterns** - Apply appropriate patterns (Repository, Factory, Strategy, etc.)
52
+ - **Dependency injection** - Use DI container or constructor injection for loose coupling
53
+ - **Configuration management** - Externalise settings using environment variables or config files
54
+ - **Logging and monitoring** - Add structured logging appropriate to your stack for issue troubleshooting
55
+ - **Performance optimisation** - Use async/await or equivalent concurrency primitives, efficient collections, caching
56
+
57
+ ### Language Best Practices (Polyglot)
58
+
59
+ - **Null safety** - Enable strict null checks (TypeScript), nullable reference types (C#), or Optional types (Java/Kotlin)
60
+ - **Modern language features** - Use pattern matching, destructuring, and idiomatic constructs for your language
61
+ - **Memory & performance** - Apply language-specific optimisations only when profiling reveals a bottleneck
62
+ - **Error handling** - Use specific error/exception types; avoid swallowing errors silently
63
+
64
+ ## Security Checklist
65
+
66
+ - [ ] Input validation on all public methods
67
+ - [ ] SQL injection prevention (parameterised queries)
68
+ - [ ] XSS protection for web applications
69
+ - [ ] Authorisation checks on sensitive operations
70
+ - [ ] Secure configuration (no secrets in code)
71
+ - [ ] Error handling without information disclosure
72
+ - [ ] Dependency vulnerability scanning
73
+ - [ ] OWASP Top 10 considerations addressed
74
+
75
+ ## Execution Guidelines
76
+
77
+ 1. **Review issue completion** - Ensure GitHub issue acceptance criteria are fully met
78
+ 2. **Ensure green tests** - All tests must pass before refactoring
79
+ 3. **Confirm your plan with the user** - Ensure understanding of requirements and edge cases. NEVER start making changes without user confirmation
80
+ 4. **Small incremental changes** - Refactor in tiny steps, running tests frequently
81
+ 5. **Apply one improvement at a time** - Focus on single refactoring technique
82
+ 6. **Run security analysis** - Use static analysis tools (SonarQube, Checkmarx)
83
+ 7. **Document security decisions** - Add comments for security-critical code
84
+ 8. **Update issue** - Comment on final implementation and close issue if complete
85
+
86
+ ## Refactor Phase Checklist
87
+
88
+ - [ ] GitHub issue acceptance criteria fully satisfied
89
+ - [ ] Code duplication eliminated
90
+ - [ ] Names clearly express intent aligned with issue domain
91
+ - [ ] Methods have single responsibility
92
+ - [ ] Security vulnerabilities addressed per issue requirements
93
+ - [ ] Performance considerations applied
94
+ - [ ] All tests remain green
95
+ - [ ] Code coverage maintained or improved
96
+ - [ ] Issue marked as complete or follow-up issues created
97
+ - [ ] Documentation updated as specified in issue
@@ -23,10 +23,10 @@ jobs:
23
23
  security-events: write
24
24
  steps:
25
25
  - name: ⤵️ Check out code from GitHub
26
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
27
27
  with:
28
28
  persist-credentials: false
29
29
  - name: 🏗 Initialize CodeQL
30
- uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
30
+ uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
31
31
  - name: 🚀 Perform CodeQL Analysis
32
- uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
32
+ uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
@@ -13,7 +13,7 @@ jobs:
13
13
  steps:
14
14
  - name: ⤵️ Check out code from GitHub
15
15
  # yamllint disable-line rule:line-length
16
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
16
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
17
17
  with:
18
18
  persist-credentials: false
19
19
  - name: 👀 Dependency review
@@ -23,11 +23,11 @@ jobs:
23
23
  runs-on: ubuntu-latest
24
24
  steps:
25
25
  - name: ⤵️ Check out code from GitHub
26
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
27
27
  with:
28
28
  persist-credentials: false
29
29
  - name: 🏗 Set up uv
30
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
30
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
31
31
  with:
32
32
  enable-cache: true
33
33
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -21,7 +21,7 @@ jobs:
21
21
  issues: write
22
22
  steps:
23
23
  - name: ⤵️ Check out code from GitHub
24
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
24
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
25
25
  with:
26
26
  persist-credentials: false
27
27
  - name: 🚀 Run Label Syncer
@@ -21,11 +21,11 @@ jobs:
21
21
  runs-on: ubuntu-latest
22
22
  steps:
23
23
  - name: ⤵️ Check out code from GitHub
24
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
24
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
25
25
  with:
26
26
  persist-credentials: false
27
27
  - name: 🏗 Set up uv
28
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
28
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
29
29
  with:
30
30
  enable-cache: true
31
31
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -45,11 +45,11 @@ jobs:
45
45
  runs-on: ubuntu-latest
46
46
  steps:
47
47
  - name: ⤵️ Check out code from GitHub
48
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
48
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
49
49
  with:
50
50
  persist-credentials: false
51
51
  - name: 🏗 Set up uv
52
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
52
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
53
53
  with:
54
54
  enable-cache: true
55
55
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -25,11 +25,11 @@ jobs:
25
25
  id-token: write
26
26
  steps:
27
27
  - name: ⤵️ Check out code from GitHub
28
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
28
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
29
29
  with:
30
30
  persist-credentials: false
31
31
  - name: 🏗 Set up uv
32
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
32
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
33
33
  with:
34
34
  enable-cache: false
35
35
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -59,7 +59,7 @@ jobs:
59
59
  verbose: true
60
60
  print-hash: true
61
61
  - name: ✍️ Sign published artifacts
62
- uses: sigstore/gh-action-sigstore-python@04cffa1d795717b140764e8b640de88853c92acc # v3.3.0
62
+ uses: sigstore/gh-action-sigstore-python@5b79a39c381910c090341a2c9b0bf022c8b387e1 # v3.4.0
63
63
  with:
64
64
  inputs: ./dist/*.tar.gz ./dist/*.whl
65
65
  release-signing-artifacts: false
@@ -34,7 +34,7 @@ jobs:
34
34
  steps:
35
35
  - name: "Checkout code"
36
36
  # yamllint disable-line rule:line-length
37
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
37
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
38
38
  with:
39
39
  persist-credentials: false
40
40
 
@@ -66,6 +66,6 @@ jobs:
66
66
  # Upload the results to GitHub's code scanning dashboard (optional).
67
67
  - name: "Upload to code-scanning"
68
68
  # yamllint disable-line rule:line-length
69
- uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
69
+ uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
70
70
  with:
71
71
  sarif_file: results.sarif
@@ -29,11 +29,11 @@ jobs:
29
29
  python: ["3.12", "3.13", "3.14"]
30
30
  steps:
31
31
  - name: ⤵️ Check out code from GitHub
32
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
33
33
  with:
34
34
  persist-credentials: false
35
35
  - name: 🏗 Set up uv
36
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
36
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
37
37
  with:
38
38
  enable-cache: true
39
39
  - name: 🏗 Set up Python ${{ matrix.python }}
@@ -61,14 +61,14 @@ jobs:
61
61
  pull-requests: read
62
62
  steps:
63
63
  - name: ⤵️ Check out code from GitHub
64
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
64
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
65
65
  with:
66
66
  fetch-depth: 0
67
67
  persist-credentials: false
68
68
  - name: ⬇️ Download coverage data
69
69
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
70
70
  - name: 🏗 Set up uv
71
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
71
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
72
72
  with:
73
73
  enable-cache: true
74
74
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -84,14 +84,14 @@ jobs:
84
84
  uv run python -m coverage xml -i
85
85
  - name: 🚀 Upload coverage report
86
86
  if: env.HAS_CODECOV_TOKEN == 'true'
87
- uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
87
+ uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
88
88
  with:
89
89
  fail_ci_if_error: true
90
90
  files: coverage.xml
91
91
  token: ${{ secrets.CODECOV_TOKEN }}
92
92
  - name: 🚀 Upload coverage report (tokenless)
93
93
  if: env.HAS_CODECOV_TOKEN != 'true' && github.event_name == 'pull_request'
94
- uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
94
+ uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
95
95
  with:
96
96
  fail_ci_if_error: false
97
97
  files: coverage.xml
@@ -101,7 +101,7 @@ jobs:
101
101
  - name: SonarQube Cloud Scan
102
102
  if: env.HAS_SONAR_TOKEN == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork)
103
103
  # yamllint disable-line rule:line-length
104
- uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1
104
+ uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2
105
105
  env:
106
106
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107
107
  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -22,12 +22,12 @@ jobs:
22
22
  steps:
23
23
  - name: ⤵️ Check out code from GitHub
24
24
  # yamllint disable-line rule:line-length
25
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
26
26
  with:
27
27
  persist-credentials: false
28
28
  - name: 🏗 Set up uv
29
29
  # yamllint disable-line rule:line-length
30
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
30
+ uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
31
31
  with:
32
32
  enable-cache: true
33
33
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-bsblan
3
- Version: 6.1.1
3
+ Version: 6.1.3
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
@@ -83,6 +83,27 @@ asyncio.run(main())
83
83
  For more examples, including hot water control, multi-circuit support, and
84
84
  authentication setup, see the [Getting Started][docs-getting-started] guide.
85
85
 
86
+ ## Compatibility
87
+
88
+ The client automatically detects the device's capabilities during
89
+ `initialize()` and selects a matching configuration based on the BSB-LAN
90
+ JSON-API version reported by the `/JV` endpoint:
91
+
92
+ - **Full configuration** — JSON-API version 2.0 or newer. All features are
93
+ available: multiple heating circuits, hot water control, schedules, sensors,
94
+ and cooling setpoints.
95
+ - **Basic configuration** — JSON-API version 1.x. A reduced, single-circuit
96
+ configuration covering essential heating, hot water, and sensor parameters.
97
+
98
+ The JSON-API version is the documented, firmware-independent compatibility
99
+ signal. The adapter firmware version (from `/JI`) is still retrieved and
100
+ exposed via `device_info`, but it is not used to determine support. A device
101
+ that does not expose `/JV`, or reports a JSON-API version below 1.0, is not
102
+ supported and raises `BSBLANVersionError` during `initialize()`.
103
+
104
+ > Note: basic (JSON-API 1.x) support is best-effort and may not cover every
105
+ > parameter your heating system exposes.
106
+
86
107
  ## Changelog & Releases
87
108
 
88
109
  This repository keeps a change log using [GitHub's releases][releases]
@@ -51,6 +51,27 @@ asyncio.run(main())
51
51
  For more examples, including hot water control, multi-circuit support, and
52
52
  authentication setup, see the [Getting Started][docs-getting-started] guide.
53
53
 
54
+ ## Compatibility
55
+
56
+ The client automatically detects the device's capabilities during
57
+ `initialize()` and selects a matching configuration based on the BSB-LAN
58
+ JSON-API version reported by the `/JV` endpoint:
59
+
60
+ - **Full configuration** — JSON-API version 2.0 or newer. All features are
61
+ available: multiple heating circuits, hot water control, schedules, sensors,
62
+ and cooling setpoints.
63
+ - **Basic configuration** — JSON-API version 1.x. A reduced, single-circuit
64
+ configuration covering essential heating, hot water, and sensor parameters.
65
+
66
+ The JSON-API version is the documented, firmware-independent compatibility
67
+ signal. The adapter firmware version (from `/JI`) is still retrieved and
68
+ exposed via `device_info`, but it is not used to determine support. A device
69
+ that does not expose `/JV`, or reports a JSON-API version below 1.0, is not
70
+ supported and raises `BSBLANVersionError` during `initialize()`.
71
+
72
+ > Note: basic (JSON-API 1.x) support is best-effort and may not cover every
73
+ > parameter your heating system exposes.
74
+
54
75
  ## Changelog & Releases
55
76
 
56
77
  This repository keeps a change log using [GitHub's releases][releases]
@@ -76,6 +76,10 @@ Data models for BSB-LAN API responses.
76
76
 
77
77
  ::: bsblan.Device
78
78
 
79
+ ### ApiVersion
80
+
81
+ ::: bsblan.ApiVersion
82
+
79
83
  ### Info
80
84
 
81
85
  ::: bsblan.Info
@@ -63,13 +63,37 @@ async def main() -> None:
63
63
  asyncio.run(main())
64
64
  ```
65
65
 
66
+ ## Firmware compatibility
67
+
68
+ On the first request the client lazily runs `initialize()`, which detects the
69
+ device's capabilities and selects a matching configuration based on the BSB-LAN
70
+ JSON-API version reported by the `/JV` endpoint:
71
+
72
+ - **Full configuration** — JSON-API version 2.0 or newer. All features are
73
+ available, including multiple heating circuits, hot water control, schedules,
74
+ sensors, and cooling setpoints.
75
+ - **Basic configuration** — JSON-API version 1.x. A reduced, single-circuit
76
+ configuration covering essential heating, hot water, and sensor parameters.
77
+
78
+ The JSON-API version is the documented, firmware-independent compatibility
79
+ signal. The adapter firmware version (from `/JI`) is still retrieved and exposed
80
+ via `device_info`, but it is not used to determine support. A device that does
81
+ not expose `/JV`, or reports a JSON-API version below 1.0, raises
82
+ `BSBLANVersionError`.
83
+
84
+ Basic (JSON-API 1.x) support is best-effort and may not cover every parameter
85
+ your heating system exposes.
86
+
66
87
  ## Temperature bounds
67
88
 
68
- For heating comfort setpoint writes (`target_temperature`), `min_temp` maps to
69
- the reduced setpoint (`712` for circuit 1, `1012` for circuit 2). The protective
70
- setpoints (`714` and `1014`) are exposed separately and are not used as the
71
- comfort setpoint lower bound. The upper heating bound is `716` for circuit 1 and
72
- `1016` for circuit 2 when the device exposes those parameters.
89
+ For heating comfort setpoint writes (`target_temperature`), the lower bound is
90
+ the protective (frost) setpoint (`714` for circuit 1, `1014` for circuit 2),
91
+ which allows setpoints down to the frost-protection temperature. The reduced
92
+ setpoint (`712`/`1012`) is exposed as `min_temp` for reference and is used as a
93
+ fallback lower bound only when the protective setpoint is unavailable (for
94
+ example, on PPS devices). The upper heating bound is the comfort maximum (`716`
95
+ for circuit 1 and `1016` for circuit 2) when the device exposes those
96
+ parameters.
73
97
 
74
98
  ## Cooling setpoint support
75
99
 
@@ -9,7 +9,8 @@ Asynchronous Python client for [BSB-LAN](https://github.com/fredlcore/bsb_lan) d
9
9
  - Control thermostat settings and hot water parameters
10
10
  - Detect optional cooling setpoints for heat/cool range controls
11
11
  - Fully typed with PEP 561 support
12
- - API v3 parameter support
12
+ - Full parameter support, plus basic support for JSON-API 1.x devices
13
+ - Automatic capability detection via the BSB-LAN JSON-API (`/JV`)
13
14
  - Lazy loading with per-section validation
14
15
 
15
16
  ## Quick example
@@ -171,17 +171,24 @@ def print_device_time(device_time: DeviceTime) -> None:
171
171
  print_attributes("Device Time", attributes)
172
172
 
173
173
 
174
- def print_device_info(device: Device, info: Info) -> None:
174
+ def print_device_info(
175
+ device: Device,
176
+ info: Info,
177
+ json_api_version: str | None = None,
178
+ ) -> None:
175
179
  """Print device and general information.
176
180
 
177
181
  Args:
178
182
  device (Device): The device information from the BSBLan device.
179
183
  info (Info): The general information from the BSBLan device.
184
+ json_api_version (str | None): The BSB-LAN JSON-API version reported by
185
+ the ``/JV`` endpoint, if available.
180
186
 
181
187
  """
182
188
  attributes = {
183
189
  "Device Name": device.name or "N/A",
184
190
  "Version": device.version or "N/A",
191
+ "JSON-API Version (/JV)": format_optional(json_api_version),
185
192
  "Device Identification": get_attribute(info.device_identification),
186
193
  "Bus Type": format_optional(device.bus),
187
194
  "Bus Writable Flag": format_optional(device.buswritable),
@@ -339,7 +346,11 @@ async def main() -> None:
339
346
  # Get and print device and general info, including bus metadata
340
347
  device: Device = bsblan.device_info or await bsblan.device()
341
348
  info: Info = await bsblan.info()
342
- print_device_info(device, info)
349
+ print_device_info(
350
+ device,
351
+ info,
352
+ json_api_version=bsblan.json_api_version,
353
+ )
343
354
 
344
355
  # Get and print state
345
356
  state: State = await bsblan.state()
@@ -12,13 +12,13 @@
12
12
  "url-parse": "1.5.10"
13
13
  },
14
14
  "devDependencies": {
15
- "prettier": "3.8.3"
15
+ "prettier": "3.8.4"
16
16
  }
17
17
  },
18
18
  "node_modules/prettier": {
19
- "version": "3.8.3",
20
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
21
- "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
19
+ "version": "3.8.4",
20
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz",
21
+ "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==",
22
22
  "dev": true,
23
23
  "license": "MIT",
24
24
  "bin": {
@@ -9,7 +9,7 @@
9
9
  "author": "WJL van Rootselaar <liudgervr@gmail.com>",
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
- "prettier": "3.8.3"
12
+ "prettier": "3.8.4"
13
13
  },
14
14
  "dependencies": {
15
15
  "url-parse": "1.5.10"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-bsblan"
3
- version = "6.1.1"
3
+ version = "6.1.3"
4
4
  description = "Asynchronous Python client for BSBLAN API"
5
5
  authors = [
6
6
  {name = "Willem-Jan van Rootselaar", email = "liudgervr@gmail.com"}
@@ -189,14 +189,14 @@ dev = [
189
189
  "blacken-docs==1.20.0",
190
190
  "codespell==2.4.2",
191
191
  "covdefaults==2.3.0",
192
- "coverage==7.14.0",
192
+ "coverage==7.14.1",
193
193
  "darglint==1.8.1",
194
194
  "flake8==7.3.0",
195
195
  "flake8-simplify==0.30.0",
196
196
  # hatch is required to support type hinting and proper packaging of the py.typed file.
197
197
  "hatch>=1.14.1",
198
198
  "isort==8.0.1",
199
- "ty==0.0.40",
199
+ "ty==0.0.44",
200
200
  "prek>=0.3.3",
201
201
  "pre-commit-hooks==6.0.0",
202
202
  "pylint==4.0.5",
@@ -205,8 +205,8 @@ dev = [
205
205
  "pytest-cov==7.1.0",
206
206
  "pytest-xdist>=3.8.0",
207
207
  "pyupgrade==3.21.2",
208
- "ruff==0.15.14",
209
- "safety==3.7.0",
208
+ "ruff==0.15.16",
209
+ "safety==3.8.1",
210
210
  "vulture==2.16",
211
211
  "yamllint==1.38.0",
212
212
  "zeroconf>=0.148.0",
@@ -8,8 +8,14 @@ from .constants import (
8
8
  HVACActionCategory,
9
9
  get_hvac_action_category,
10
10
  )
11
- from .exceptions import BSBLANAuthError, BSBLANConnectionError, BSBLANError
11
+ from .exceptions import (
12
+ BSBLANAuthError,
13
+ BSBLANConnectionError,
14
+ BSBLANError,
15
+ BSBLANVersionError,
16
+ )
12
17
  from .models import (
18
+ ApiVersion,
13
19
  DaySchedule,
14
20
  Device,
15
21
  DeviceTime,
@@ -34,10 +40,12 @@ __all__ = [
34
40
  "BSBLAN",
35
41
  "UNIT_DEVICE_CLASS_MAP",
36
42
  "UNIT_STATE_CLASS_MAP",
43
+ "ApiVersion",
37
44
  "BSBLANAuthError",
38
45
  "BSBLANConfig",
39
46
  "BSBLANConnectionError",
40
47
  "BSBLANError",
48
+ "BSBLANVersionError",
41
49
  "DHWSchedule",
42
50
  "DHWTimeSwitchPrograms",
43
51
  "DaySchedule",