python-bsblan 5.2.0__tar.gz → 6.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/codeql.yaml +2 -2
  2. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/dependency-review.yaml +1 -1
  3. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/docs.yaml +1 -1
  4. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/linting.yaml +2 -2
  5. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/release-drafter.yaml +1 -1
  6. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/release.yaml +1 -1
  7. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/scorecard.yml +1 -1
  8. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/tests.yaml +4 -4
  9. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/typing.yaml +1 -1
  10. python_bsblan-6.0.0/.nvmrc +1 -0
  11. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/PKG-INFO +1 -1
  12. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/api/client.md +2 -0
  13. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/getting-started.md +36 -0
  14. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/control.py +34 -14
  15. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/pyproject.toml +5 -5
  16. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/bsblan.py +160 -64
  17. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/constants.py +26 -0
  18. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/models.py +23 -3
  19. python_bsblan-6.0.0/tests/fixtures/pps_device.json +16 -0
  20. python_bsblan-6.0.0/tests/fixtures/pps_state.json +23 -0
  21. python_bsblan-6.0.0/tests/fixtures/pps_static_values.json +16 -0
  22. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_circuit.py +49 -120
  23. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_device.py +5 -0
  24. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_include_parameter.py +31 -0
  25. python_bsblan-6.0.0/tests/test_pps.py +380 -0
  26. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_time.py +13 -1
  27. python_bsblan-5.2.0/.nvmrc +0 -1
  28. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.editorconfig +0 -0
  29. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.gitattributes +0 -0
  30. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/CODE_OF_CONDUCT.md +0 -0
  31. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/CONTRIBUTING.md +0 -0
  32. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
  33. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/SECURITY.md +0 -0
  36. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/copilot-instructions.md +0 -0
  37. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/labels.yml +0 -0
  38. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/prompts/add-parameter.prompt.md +0 -0
  39. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/prompts/code-review.prompt.md +0 -0
  40. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/release-drafter.yml +0 -0
  41. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/renovate.json +0 -0
  42. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/skills/bsblan-parameters/SKILL.md +0 -0
  43. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/skills/bsblan-testing/SKILL.md +0 -0
  44. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/auto-approve-renovate.yml +0 -0
  45. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/labels.yaml +0 -0
  46. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/lock.yaml +0 -0
  47. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/pr-labels.yaml +0 -0
  48. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/workflows/stale.yaml +0 -0
  49. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.github/zizmor.yml +0 -0
  50. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.gitignore +0 -0
  51. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.pre-commit-config.yaml +0 -0
  52. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.prettierignore +0 -0
  53. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/.yamllint +0 -0
  54. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/AGENTS.md +0 -0
  55. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/CLAUDE.md +0 -0
  56. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/LICENSE.md +0 -0
  57. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/Makefile +0 -0
  58. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/README.md +0 -0
  59. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/api/constants.md +0 -0
  60. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/api/exceptions.md +0 -0
  61. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/api/models.md +0 -0
  62. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/docs/index.md +0 -0
  63. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/discovery.py +0 -0
  64. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/fetch_param.py +0 -0
  65. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/profile_init.py +0 -0
  66. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/ruff.toml +0 -0
  67. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/examples/speed_test.py +0 -0
  68. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/mkdocs.yml +0 -0
  69. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/package-lock.json +0 -0
  70. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/package.json +0 -0
  71. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/sonar-project.properties +0 -0
  72. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/__init__.py +0 -0
  73. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/exceptions.py +0 -0
  74. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/py.typed +0 -0
  75. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/src/bsblan/utility.py +0 -0
  76. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/__init__.py +0 -0
  77. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/conftest.py +0 -0
  78. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/device.json +0 -0
  79. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/dict_version.json +0 -0
  80. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/hot_water_state.json +0 -0
  81. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/info.json +0 -0
  82. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/password.txt +0 -0
  83. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/sensor.json +0 -0
  84. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/state.json +0 -0
  85. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/state_circuit2.json +0 -0
  86. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/static_state.json +0 -0
  87. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/static_state_circuit2.json +0 -0
  88. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/thermostat_hvac.json +0 -0
  89. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/thermostat_temp.json +0 -0
  90. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/fixtures/time.json +0 -0
  91. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/ruff.toml +0 -0
  92. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_api_initialization.py +0 -0
  93. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_api_validation.py +0 -0
  94. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_auth.py +0 -0
  95. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_backoff_retry.py +0 -0
  96. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_bsblan.py +0 -0
  97. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_bsblan_edge_cases.py +0 -0
  98. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_configuration.py +0 -0
  99. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_constants.py +0 -0
  100. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_context_manager.py +0 -0
  101. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_dhw_time_switch.py +0 -0
  102. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_entity_info.py +0 -0
  103. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_entity_info_ha.py +0 -0
  104. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_heating_schedule.py +0 -0
  105. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_hot_water_additional.py +0 -0
  106. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_hotwater_state.py +0 -0
  107. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_info.py +0 -0
  108. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_initialization.py +0 -0
  109. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_read_parameters.py +0 -0
  110. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_reset_validation.py +0 -0
  111. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_schedule_models.py +0 -0
  112. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_sensor.py +0 -0
  113. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_set_heating_schedule.py +0 -0
  114. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_set_hot_water_schedule.py +0 -0
  115. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_set_hotwater.py +0 -0
  116. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_state.py +0 -0
  117. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_static_state.py +0 -0
  118. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_temperature_unit.py +0 -0
  119. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_temperature_validation.py +0 -0
  120. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_thermostat.py +0 -0
  121. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_utility.py +0 -0
  122. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_utility_additional.py +0 -0
  123. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_utility_edge_cases.py +0 -0
  124. {python_bsblan-5.2.0 → python_bsblan-6.0.0}/tests/test_version_errors.py +0 -0
@@ -27,6 +27,6 @@ jobs:
27
27
  with:
28
28
  persist-credentials: false
29
29
  - name: 🏗 Initialize CodeQL
30
- uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
30
+ uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
31
31
  - name: 🚀 Perform CodeQL Analysis
32
- uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
32
+ uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
@@ -18,4 +18,4 @@ jobs:
18
18
  persist-credentials: false
19
19
  - name: 👀 Dependency review
20
20
  # yamllint disable-line rule:line-length
21
- uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
21
+ uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
@@ -27,7 +27,7 @@ jobs:
27
27
  with:
28
28
  persist-credentials: false
29
29
  - name: 🏗 Set up uv
30
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
30
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
31
31
  with:
32
32
  enable-cache: true
33
33
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -25,7 +25,7 @@ jobs:
25
25
  with:
26
26
  persist-credentials: false
27
27
  - name: 🏗 Set up uv
28
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
28
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
29
29
  with:
30
30
  enable-cache: true
31
31
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -49,7 +49,7 @@ jobs:
49
49
  with:
50
50
  persist-credentials: false
51
51
  - name: 🏗 Set up uv
52
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
52
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
53
53
  with:
54
54
  enable-cache: true
55
55
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -36,7 +36,7 @@ jobs:
36
36
  steps:
37
37
  - name: 🚀 Run Release Drafter
38
38
  # yamllint disable-line rule:line-length
39
- uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7.2.0
39
+ uses: release-drafter/release-drafter@c2e2804cc59f45f57076a99af580d0fedb697927 # v7.3.0
40
40
  with:
41
41
  prerelease: ${{ github.event.inputs.prerelease == 'true' }}
42
42
  prerelease-identifier: ${{ github.event.inputs.prerelease_identifier }}
@@ -29,7 +29,7 @@ jobs:
29
29
  with:
30
30
  persist-credentials: false
31
31
  - name: 🏗 Set up uv
32
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
32
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
33
33
  with:
34
34
  enable-cache: false
35
35
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -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@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
69
+ uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
70
70
  with:
71
71
  sarif_file: results.sarif
@@ -33,7 +33,7 @@ jobs:
33
33
  with:
34
34
  persist-credentials: false
35
35
  - name: 🏗 Set up uv
36
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
36
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
37
37
  with:
38
38
  enable-cache: true
39
39
  - name: 🏗 Set up Python ${{ matrix.python }}
@@ -68,7 +68,7 @@ jobs:
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@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
71
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
72
72
  with:
73
73
  enable-cache: true
74
74
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -84,7 +84,7 @@ 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@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
87
+ uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
88
88
  with:
89
89
  token: ${{ secrets.CODECOV_TOKEN }}
90
90
  - name: ℹ️ Skip Codecov upload (missing token)
@@ -93,7 +93,7 @@ jobs:
93
93
  - name: SonarQube Cloud Scan
94
94
  if: env.HAS_SONAR_TOKEN == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork)
95
95
  # yamllint disable-line rule:line-length
96
- uses: SonarSource/sonarqube-scan-action@299e4b793aaa83bf2aba7c9c14bedbb485688ec4 # v7.1.0
96
+ uses: SonarSource/sonarqube-scan-action@59db25f34e16620e48ab4bb9e4a5dce155cb5432 # v8.0
97
97
  env:
98
98
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99
99
  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -27,7 +27,7 @@ jobs:
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@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
30
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
31
31
  with:
32
32
  enable-cache: true
33
33
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
@@ -0,0 +1 @@
1
+ 24.15.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-bsblan
3
- Version: 5.2.0
3
+ Version: 6.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
@@ -10,6 +10,8 @@ The main entry point for interacting with BSB-LAN devices.
10
10
  members:
11
11
  - __init__
12
12
  - initialize
13
+ - device_info
14
+ - supports_time_sync
13
15
  - get_available_circuits
14
16
  - state
15
17
  - sensor
@@ -63,6 +63,42 @@ async def main() -> None:
63
63
  asyncio.run(main())
64
64
  ```
65
65
 
66
+ ## PPS bus support
67
+
68
+ PPS bus devices are detected from the device metadata returned by BSB-LAN. The
69
+ client provides minimal climate support for PPS devices through the same climate
70
+ methods used by BSB/LPB devices.
71
+
72
+ Supported PPS climate operations:
73
+
74
+ - `state()` for `hvac_mode`, `target_temperature`, and `current_temperature`
75
+ - `static_values()` for `min_temp` and `max_temp`
76
+ - `thermostat()` for target temperature and HVAC mode
77
+ - `get_available_circuits()`, which returns `[1]` when the single PPS
78
+ climate circuit is available, otherwise `[]`; PPS devices only ever expose
79
+ circuit `1`
80
+
81
+ PPS devices currently have these limitations:
82
+
83
+ - Only circuit `1` is supported.
84
+ - `time()` and `set_time()` are not supported for PPS devices.
85
+ - `thermostat(hvac_mode=2)` is not supported on PPS devices. Valid PPS modes
86
+ are `0` (off), `1` (auto), and `3` (heat/manual).
87
+ - Hot water and schedule helpers are intended for BSB/LPB devices.
88
+
89
+ Check `supports_time_sync` before showing or calling time synchronization in
90
+ applications:
91
+
92
+ ```python
93
+ async with BSBLAN(config) as client:
94
+ device = client.device_info or await client.device()
95
+ print(f"Bus type: {device.bus or 'unknown'}")
96
+
97
+ if client.supports_time_sync:
98
+ device_time = await client.time()
99
+ print(device_time.time.value)
100
+ ```
101
+
66
102
  ## Hot water control
67
103
 
68
104
  ```python
@@ -68,6 +68,16 @@ def print_attributes(title: str, attributes: dict[str, str]) -> None:
68
68
  print(f"{label}: {value}")
69
69
 
70
70
 
71
+ def format_yes_no(*, value: bool) -> str:
72
+ """Format a boolean as a readable yes/no value."""
73
+ return "yes" if value else "no"
74
+
75
+
76
+ def format_optional(value: Any) -> str:
77
+ """Format optional device metadata for display."""
78
+ return "N/A" if value is None else str(value)
79
+
80
+
71
81
  def get_hvac_action_name(status_code: int) -> str:
72
82
  """Map BSB-LAN parameter 8000 status code to a human-readable HVAC action.
73
83
 
@@ -180,6 +190,11 @@ async def print_device_info(device: Device, info: Info) -> None:
180
190
  "Device Name": device.name or "N/A",
181
191
  "Version": device.version or "N/A",
182
192
  "Device Identification": device_identification,
193
+ "Bus Type": format_optional(device.bus),
194
+ "Bus Writable Flag": format_optional(device.buswritable),
195
+ "Bus Address": format_optional(device.busaddr),
196
+ "Bus Destination": format_optional(device.busdest),
197
+ "Supports Time Sync": format_yes_no(value=device.supports_time_sync),
183
198
  }
184
199
  print_attributes("Device Information", attributes)
185
200
 
@@ -319,6 +334,11 @@ async def main() -> None:
319
334
 
320
335
  # Initialize BSBLAN with the configuration object
321
336
  async with BSBLAN(config) as bsblan:
337
+ # Get and print device and general info, including bus metadata
338
+ device: Device = bsblan.device_info or await bsblan.device()
339
+ info: Info = await bsblan.info()
340
+ await print_device_info(device, info)
341
+
322
342
  # Get and print state
323
343
  state: State = await bsblan.state()
324
344
  await print_state(state)
@@ -335,14 +355,12 @@ async def main() -> None:
335
355
  sensor: Sensor = await bsblan.sensor()
336
356
  await print_sensor(sensor)
337
357
 
338
- # Get and print device and general info
339
- device: Device = await bsblan.device()
340
- info: Info = await bsblan.info()
341
- await print_device_info(device, info)
342
-
343
358
  # Get and print device time
344
- device_time: DeviceTime = await bsblan.time()
345
- await print_device_time(device_time)
359
+ if bsblan.supports_time_sync:
360
+ device_time: DeviceTime = await bsblan.time()
361
+ await print_device_time(device_time)
362
+ else:
363
+ print("\nDevice time is not available for this bus type")
346
364
 
347
365
  # Get and print static state
348
366
  static_state: StaticState = await bsblan.static_values()
@@ -375,13 +393,15 @@ async def main() -> None:
375
393
  await bsblan.set_hot_water(SetHotWaterParam(dhw_time_programs=dhw_programs))
376
394
 
377
395
  # Example: Set device time
378
- print("\nSetting device time to current system time")
379
- # Get current local system time and format it for BSB-LAN (DD.MM.YYYY HH:MM:SS)
380
- # Note: Using local time intentionally for this demo to sync BSB-LAN
381
- current_time = datetime.now().replace(microsecond=0) # noqa: DTZ005 - Demo uses local time
382
- formatted_time = current_time.strftime("%d.%m.%Y %H:%M:%S")
383
- print(f"Current system time: {formatted_time}")
384
- await bsblan.set_time(formatted_time)
396
+ if bsblan.supports_time_sync:
397
+ print("\nSetting device time to current system time")
398
+ # Get current local system time and format it for BSB-LAN.
399
+ current_time = datetime.now().replace(microsecond=0) # noqa: DTZ005
400
+ formatted_time = current_time.strftime("%d.%m.%Y %H:%M:%S")
401
+ print(f"Current system time: {formatted_time}")
402
+ await bsblan.set_time(formatted_time)
403
+ else:
404
+ print("\nSkipping device time sync for this bus type")
385
405
 
386
406
 
387
407
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-bsblan"
3
- version = "5.2.0"
3
+ version = "6.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"}
@@ -185,18 +185,18 @@ build-backend = "hatchling.build"
185
185
  dev = [
186
186
  "aresponses==3.0.0",
187
187
  "bandit==1.9.4",
188
- "black==26.3.1",
188
+ "black==26.5.1",
189
189
  "blacken-docs==1.20.0",
190
190
  "codespell==2.4.2",
191
191
  "covdefaults==2.3.0",
192
- "coverage==7.13.5",
192
+ "coverage==7.14.0",
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.32",
199
+ "ty==0.0.38",
200
200
  "prek>=0.3.3",
201
201
  "pre-commit-hooks==6.0.0",
202
202
  "pylint==4.0.5",
@@ -205,7 +205,7 @@ 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.11",
208
+ "ruff==0.15.13",
209
209
  "safety==3.7.0",
210
210
  "vulture==2.16",
211
211
  "yamllint==1.38.0",