python-bsblan 4.1.0b2__tar.gz → 4.2.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 (102) hide show
  1. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/codeql.yaml +8 -3
  2. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/labels.yaml +5 -1
  3. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/linting.yaml +16 -13
  4. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/lock.yaml +4 -0
  5. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/pr-labels.yaml +3 -0
  6. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/release-drafter.yaml +6 -1
  7. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/release.yaml +2 -2
  8. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/stale.yaml +4 -0
  9. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/tests.yaml +9 -4
  10. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/typing.yaml +2 -2
  11. python_bsblan-4.2.0/.nvmrc +1 -0
  12. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/PKG-INFO +1 -1
  13. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/examples/control.py +2 -2
  14. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/package-lock.json +4 -4
  15. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/package.json +1 -1
  16. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/pyproject.toml +7 -7
  17. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/__init__.py +4 -0
  18. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/constants.py +71 -0
  19. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/models.py +48 -1
  20. python_bsblan-4.2.0/tests/test_entity_info_ha.py +220 -0
  21. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/uv.lock +532 -498
  22. python_bsblan-4.1.0b2/.nvmrc +0 -1
  23. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.editorconfig +0 -0
  24. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.gitattributes +0 -0
  25. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/CODE_OF_CONDUCT.md +0 -0
  26. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/CONTRIBUTING.md +0 -0
  27. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
  28. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  29. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  30. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/copilot-instructions.md +0 -0
  31. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/labels.yml +0 -0
  32. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/prompts/add-parameter.prompt.md +0 -0
  33. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/prompts/code-review.prompt.md +0 -0
  34. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/release-drafter.yml +0 -0
  35. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/renovate.json +0 -0
  36. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/skills/bsblan-parameters/SKILL.md +0 -0
  37. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/skills/bsblan-testing/SKILL.md +0 -0
  38. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.github/workflows/auto-approve-renovate.yml +0 -0
  39. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.gitignore +0 -0
  40. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.pre-commit-config.yaml +0 -0
  41. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.prettierignore +0 -0
  42. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/.yamllint +0 -0
  43. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/AGENTS.md +0 -0
  44. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/CLAUDE.md +0 -0
  45. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/LICENSE.md +0 -0
  46. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/README.md +0 -0
  47. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/examples/discovery.py +0 -0
  48. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/examples/profile_init.py +0 -0
  49. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/examples/ruff.toml +0 -0
  50. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/examples/speed_test.py +0 -0
  51. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/sonar-project.properties +0 -0
  52. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/bsblan.py +0 -0
  53. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/exceptions.py +0 -0
  54. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/py.typed +0 -0
  55. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/src/bsblan/utility.py +0 -0
  56. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/__init__.py +0 -0
  57. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/conftest.py +0 -0
  58. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/device.json +0 -0
  59. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/dict_version.json +0 -0
  60. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/hot_water_state.json +0 -0
  61. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/info.json +0 -0
  62. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/password.txt +0 -0
  63. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/sensor.json +0 -0
  64. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/state.json +0 -0
  65. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/static_state.json +0 -0
  66. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/thermostat_hvac.json +0 -0
  67. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/thermostat_temp.json +0 -0
  68. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/fixtures/time.json +0 -0
  69. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/ruff.toml +0 -0
  70. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_api_initialization.py +0 -0
  71. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_api_validation.py +0 -0
  72. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_auth.py +0 -0
  73. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_backoff_retry.py +0 -0
  74. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_bsblan.py +0 -0
  75. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_bsblan_edge_cases.py +0 -0
  76. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_configuration.py +0 -0
  77. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_constants.py +0 -0
  78. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_context_manager.py +0 -0
  79. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_device.py +0 -0
  80. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_dhw_time_switch.py +0 -0
  81. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_entity_info.py +0 -0
  82. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_hot_water_additional.py +0 -0
  83. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_hotwater_state.py +0 -0
  84. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_include_parameter.py +0 -0
  85. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_info.py +0 -0
  86. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_initialization.py +0 -0
  87. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_read_parameters.py +0 -0
  88. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_reset_validation.py +0 -0
  89. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_schedule_models.py +0 -0
  90. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_sensor.py +0 -0
  91. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_set_hot_water_schedule.py +0 -0
  92. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_set_hotwater.py +0 -0
  93. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_state.py +0 -0
  94. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_static_state.py +0 -0
  95. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_temperature_unit.py +0 -0
  96. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_temperature_validation.py +0 -0
  97. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_thermostat.py +0 -0
  98. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_time.py +0 -0
  99. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_utility.py +0 -0
  100. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_utility_additional.py +0 -0
  101. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_utility_edge_cases.py +0 -0
  102. {python_bsblan-4.1.0b2 → python_bsblan-4.2.0}/tests/test_version_errors.py +0 -0
@@ -11,14 +11,19 @@ on:
11
11
  schedule:
12
12
  - cron: "30 1 * * 0"
13
13
 
14
+ permissions:
15
+ actions: read
16
+ contents: read
17
+ security-events: write
18
+
14
19
  jobs:
15
20
  codeql:
16
21
  name: Scanning
17
22
  runs-on: ubuntu-latest
18
23
  steps:
19
24
  - name: ⤵️ Check out code from GitHub
20
- uses: actions/checkout@v6.0.1
25
+ uses: actions/checkout@v6.0.2
21
26
  - name: 🏗 Initialize CodeQL
22
- uses: github/codeql-action/init@v4.31.9
27
+ uses: github/codeql-action/init@v4.32.2
23
28
  - name: 🚀 Perform CodeQL Analysis
24
- uses: github/codeql-action/analyze@v4.31.9
29
+ uses: github/codeql-action/analyze@v4.32.2
@@ -10,13 +10,17 @@ on:
10
10
  - .github/labels.yml
11
11
  workflow_dispatch:
12
12
 
13
+ permissions:
14
+ contents: read
15
+ issues: write
16
+
13
17
  jobs:
14
18
  labels:
15
19
  name: ♻️ Sync labels
16
20
  runs-on: ubuntu-latest
17
21
  steps:
18
22
  - name: ⤵️ Check out code from GitHub
19
- uses: actions/checkout@v6.0.1
23
+ uses: actions/checkout@v6.0.2
20
24
  - name: 🚀 Run Label Syncer
21
25
  uses: micnncim/action-label-syncer@v1.3.0
22
26
  env:
@@ -9,6 +9,9 @@ on:
9
9
  branches: [main]
10
10
  workflow_dispatch:
11
11
 
12
+ permissions:
13
+ contents: read
14
+
12
15
  env:
13
16
  DEFAULT_PYTHON: "3.13"
14
17
 
@@ -18,14 +21,14 @@ jobs:
18
21
  runs-on: ubuntu-latest
19
22
  steps:
20
23
  - name: ⤵️ Check out code from GitHub
21
- uses: actions/checkout@v6.0.1
24
+ uses: actions/checkout@v6.0.2
22
25
  - name: 🏗 Set up uv
23
26
  uses: astral-sh/setup-uv@v7
24
27
  with:
25
28
  enable-cache: true
26
29
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
27
30
  id: python
28
- uses: actions/setup-python@v6.1.0
31
+ uses: actions/setup-python@v6.2.0
29
32
  with:
30
33
  python-version: ${{ env.DEFAULT_PYTHON }}
31
34
  - name: 🏗 Install Python dependencies
@@ -38,14 +41,14 @@ jobs:
38
41
  runs-on: ubuntu-latest
39
42
  steps:
40
43
  - name: ⤵️ Check out code from GitHub
41
- uses: actions/checkout@v6.0.1
44
+ uses: actions/checkout@v6.0.2
42
45
  - name: 🏗 Set up uv
43
46
  uses: astral-sh/setup-uv@v7
44
47
  with:
45
48
  enable-cache: true
46
49
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
47
50
  id: python
48
- uses: actions/setup-python@v6.1.0
51
+ uses: actions/setup-python@v6.2.0
49
52
  with:
50
53
  python-version: ${{ env.DEFAULT_PYTHON }}
51
54
  - name: 🏗 Install Python dependencies
@@ -60,14 +63,14 @@ jobs:
60
63
  runs-on: ubuntu-latest
61
64
  steps:
62
65
  - name: ⤵️ Check out code from GitHub
63
- uses: actions/checkout@v6.0.1
66
+ uses: actions/checkout@v6.0.2
64
67
  - name: 🏗 Set up uv
65
68
  uses: astral-sh/setup-uv@v7
66
69
  with:
67
70
  enable-cache: true
68
71
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
69
72
  id: python
70
- uses: actions/setup-python@v6.1.0
73
+ uses: actions/setup-python@v6.2.0
71
74
  with:
72
75
  python-version: ${{ env.DEFAULT_PYTHON }}
73
76
  - name: 🏗 Install Python dependencies
@@ -104,14 +107,14 @@ jobs:
104
107
  runs-on: ubuntu-latest
105
108
  steps:
106
109
  - name: ⤵️ Check out code from GitHub
107
- uses: actions/checkout@v6.0.1
110
+ uses: actions/checkout@v6.0.2
108
111
  - name: 🏗 Set up uv
109
112
  uses: astral-sh/setup-uv@v7
110
113
  with:
111
114
  enable-cache: true
112
115
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
113
116
  id: python
114
- uses: actions/setup-python@v6.1.0
117
+ uses: actions/setup-python@v6.2.0
115
118
  with:
116
119
  python-version: ${{ env.DEFAULT_PYTHON }}
117
120
  - name: 🏗 Install Python dependencies
@@ -124,14 +127,14 @@ jobs:
124
127
  runs-on: ubuntu-latest
125
128
  steps:
126
129
  - name: ⤵️ Check out code from GitHub
127
- uses: actions/checkout@v6.0.1
130
+ uses: actions/checkout@v6.0.2
128
131
  - name: 🏗 Set up uv
129
132
  uses: astral-sh/setup-uv@v7
130
133
  with:
131
134
  enable-cache: true
132
135
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
133
136
  id: python
134
- uses: actions/setup-python@v6.1.0
137
+ uses: actions/setup-python@v6.2.0
135
138
  with:
136
139
  python-version: ${{ env.DEFAULT_PYTHON }}
137
140
  - name: 🏗 Install Python dependencies
@@ -144,20 +147,20 @@ jobs:
144
147
  runs-on: ubuntu-latest
145
148
  steps:
146
149
  - name: ⤵️ Check out code from GitHub
147
- uses: actions/checkout@v6.0.1
150
+ uses: actions/checkout@v6.0.2
148
151
  - name: 🏗 Set up uv
149
152
  uses: astral-sh/setup-uv@v7
150
153
  with:
151
154
  enable-cache: true
152
155
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
153
156
  id: python
154
- uses: actions/setup-python@v6.1.0
157
+ uses: actions/setup-python@v6.2.0
155
158
  with:
156
159
  python-version: ${{ env.DEFAULT_PYTHON }}
157
160
  - name: 🏗 Install Python dependencies
158
161
  run: uv sync --dev
159
162
  - name: 🏗 Set up Node.js
160
- uses: actions/setup-node@v6.1.0
163
+ uses: actions/setup-node@v6.2.0
161
164
  with:
162
165
  node-version-file: ".nvmrc"
163
166
  cache: "npm"
@@ -7,6 +7,10 @@ on:
7
7
  - cron: "0 9 * * *"
8
8
  workflow_dispatch:
9
9
 
10
+ permissions:
11
+ issues: write
12
+ pull-requests: write
13
+
10
14
  jobs:
11
15
  lock:
12
16
  name: 🔒 Lock closed issues and PRs
@@ -11,6 +11,9 @@ on:
11
11
  - synchronize
12
12
  workflow_call:
13
13
 
14
+ permissions:
15
+ pull-requests: read
16
+
14
17
  jobs:
15
18
  pr_labels:
16
19
  name: Verify
@@ -23,13 +23,18 @@ on:
23
23
  - alpha
24
24
  - rc
25
25
 
26
+ permissions:
27
+ contents: write
28
+ issues: read
29
+ pull-requests: read
30
+
26
31
  jobs:
27
32
  update_release_draft:
28
33
  name: ✏️ Draft release
29
34
  runs-on: ubuntu-latest
30
35
  steps:
31
36
  - name: 🚀 Run Release Drafter
32
- uses: release-drafter/release-drafter@v6.1.0
37
+ uses: release-drafter/release-drafter@v6.2.0
33
38
  with:
34
39
  prerelease: ${{ github.event.inputs.prerelease == 'true' }}
35
40
  prerelease-identifier: ${{ github.event.inputs.prerelease_identifier }}
@@ -22,14 +22,14 @@ jobs:
22
22
  id-token: write
23
23
  steps:
24
24
  - name: ⤵️ Check out code from GitHub
25
- uses: actions/checkout@v6.0.1
25
+ uses: actions/checkout@v6.0.2
26
26
  - name: 🏗 Set up uv
27
27
  uses: astral-sh/setup-uv@v7
28
28
  with:
29
29
  enable-cache: true
30
30
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
31
31
  id: python
32
- uses: actions/setup-python@v6.1.0
32
+ uses: actions/setup-python@v6.2.0
33
33
  with:
34
34
  python-version: ${{ env.DEFAULT_PYTHON }}
35
35
  - name: 🏗 Install dependencies
@@ -7,6 +7,10 @@ on:
7
7
  - cron: "0 8 * * *"
8
8
  workflow_dispatch:
9
9
 
10
+ permissions:
11
+ issues: write
12
+ pull-requests: write
13
+
10
14
  jobs:
11
15
  stale:
12
16
  name: 🧹 Clean up stale issues and PRs
@@ -9,6 +9,11 @@ on:
9
9
  branches: [main]
10
10
  workflow_dispatch:
11
11
 
12
+ permissions:
13
+ actions: write
14
+ contents: read
15
+ pull-requests: read
16
+
12
17
  env:
13
18
  DEFAULT_PYTHON: "3.13"
14
19
 
@@ -21,14 +26,14 @@ jobs:
21
26
  python: ["3.12", "3.13", "3.14"]
22
27
  steps:
23
28
  - name: ⤵️ Check out code from GitHub
24
- uses: actions/checkout@v6.0.1
29
+ uses: actions/checkout@v6.0.2
25
30
  - name: 🏗 Set up uv
26
31
  uses: astral-sh/setup-uv@v7
27
32
  with:
28
33
  enable-cache: true
29
34
  - name: 🏗 Set up Python ${{ matrix.python }}
30
35
  id: python
31
- uses: actions/setup-python@v6.1.0
36
+ uses: actions/setup-python@v6.2.0
32
37
  with:
33
38
  python-version: ${{ matrix.python }}
34
39
  - name: 🏗 Install dependencies
@@ -47,7 +52,7 @@ jobs:
47
52
  needs: pytest
48
53
  steps:
49
54
  - name: ⤵️ Check out code from GitHub
50
- uses: actions/checkout@v6.0.1
55
+ uses: actions/checkout@v6.0.2
51
56
  with:
52
57
  fetch-depth: 0
53
58
  - name: ⬇️ Download coverage data
@@ -58,7 +63,7 @@ jobs:
58
63
  enable-cache: true
59
64
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
60
65
  id: python
61
- uses: actions/setup-python@v6.1.0
66
+ uses: actions/setup-python@v6.2.0
62
67
  with:
63
68
  python-version: ${{ env.DEFAULT_PYTHON }}
64
69
  - name: 🏗 Install dependencies
@@ -20,14 +20,14 @@ jobs:
20
20
  contents: read
21
21
  steps:
22
22
  - name: ⤵️ Check out code from GitHub
23
- uses: actions/checkout@v6.0.1
23
+ uses: actions/checkout@v6.0.2
24
24
  - name: 🏗 Set up uv
25
25
  uses: astral-sh/setup-uv@v7
26
26
  with:
27
27
  enable-cache: true
28
28
  - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }}
29
29
  id: python
30
- uses: actions/setup-python@v6.1.0
30
+ uses: actions/setup-python@v6.2.0
31
31
  with:
32
32
  python-version: ${{ env.DEFAULT_PYTHON }}
33
33
  - name: 🏗 Install dependencies
@@ -0,0 +1 @@
1
+ 24.13.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-bsblan
3
- Version: 4.1.0b2
3
+ Version: 4.2.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
@@ -177,8 +177,8 @@ async def print_device_info(device: Device, info: Info) -> None:
177
177
  )
178
178
 
179
179
  attributes = {
180
- "Device Name": device.name if device.name else "N/A",
181
- "Version": device.version if device.version else "N/A",
180
+ "Device Name": device.name or "N/A",
181
+ "Version": device.version or "N/A",
182
182
  "Device Identification": device_identification,
183
183
  }
184
184
  print_attributes("Device Information", attributes)
@@ -12,13 +12,13 @@
12
12
  "url-parse": "1.5.10"
13
13
  },
14
14
  "devDependencies": {
15
- "prettier": "3.7.4"
15
+ "prettier": "3.8.1"
16
16
  }
17
17
  },
18
18
  "node_modules/prettier": {
19
- "version": "3.7.4",
20
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
21
- "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
19
+ "version": "3.8.1",
20
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
21
+ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
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.7.4"
12
+ "prettier": "3.8.1"
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 = "4.1.0-beta.2"
3
+ version = "4.2.0"
4
4
  description = "Asynchronous Python client for BSBLAN API"
5
5
  authors = [
6
6
  {name = "Willem-Jan van Rootselaar", email = "liudgervr@gmail.com"}
@@ -177,19 +177,19 @@ build-backend = "hatchling.build"
177
177
  [dependency-groups]
178
178
  dev = [
179
179
  "aresponses==3.0.0",
180
- "bandit==1.9.2",
181
- "black==25.12.0",
180
+ "bandit==1.9.3",
181
+ "black==26.1.0",
182
182
  "blacken-docs==1.20.0",
183
183
  "codespell==2.4.1",
184
184
  "covdefaults==2.3.0",
185
- "coverage==7.13.1",
185
+ "coverage==7.13.4",
186
186
  "darglint==1.8.1",
187
187
  "flake8==7.3.0",
188
188
  "flake8-simplify==0.30.0",
189
189
  # hatch is required to support type hinting and proper packaging of the py.typed file.
190
190
  "hatch>=1.14.1",
191
191
  "isort==7.0.0",
192
- "ty==0.0.11",
192
+ "ty==0.0.16",
193
193
  "pre-commit==4.5.1",
194
194
  "pre-commit-hooks==6.0.0",
195
195
  "pylint==4.0.4",
@@ -198,9 +198,9 @@ dev = [
198
198
  "pytest-cov==7.0.0",
199
199
  "pytest-xdist>=3.8.0",
200
200
  "pyupgrade==3.21.2",
201
- "ruff==0.14.11",
201
+ "ruff==0.15.0",
202
202
  "safety==3.7.0",
203
203
  "vulture==2.14",
204
- "yamllint==1.37.1",
204
+ "yamllint==1.38.0",
205
205
  "zeroconf>=0.148.0",
206
206
  ]
@@ -2,6 +2,8 @@
2
2
 
3
3
  from .bsblan import BSBLAN, BSBLANConfig
4
4
  from .constants import (
5
+ UNIT_DEVICE_CLASS_MAP,
6
+ UNIT_STATE_CLASS_MAP,
5
7
  HeatingCircuitStatus,
6
8
  HVACActionCategory,
7
9
  get_hvac_action_category,
@@ -27,6 +29,8 @@ from .models import (
27
29
 
28
30
  __all__ = [
29
31
  "BSBLAN",
32
+ "UNIT_DEVICE_CLASS_MAP",
33
+ "UNIT_STATE_CLASS_MAP",
30
34
  "BSBLANAuthError",
31
35
  "BSBLANConfig",
32
36
  "BSBLANConnectionError",
@@ -415,6 +415,77 @@ EMPTY_INCLUDE_LIST_ERROR_MSG: Final[str] = (
415
415
  # Handle both ASCII and Unicode degree symbols
416
416
  TEMPERATURE_UNITS = {"°C", "°F", "&#176;C", "&#176;F", "&deg;C", "&deg;F"}
417
417
 
418
+ # HA-compatible device class mapping from BSB-LAN units
419
+ # Maps unit strings (incl. HTML-encoded variants)
420
+ # to HA SensorDeviceClass values
421
+ UNIT_DEVICE_CLASS_MAP: Final[dict[str, str]] = {
422
+ # Temperature
423
+ "°C": "temperature",
424
+ "°F": "temperature",
425
+ "&#176;C": "temperature",
426
+ "&#176;F": "temperature",
427
+ "&deg;C": "temperature",
428
+ "&deg;F": "temperature",
429
+ # Energy
430
+ "kWh": "energy",
431
+ "MWh": "energy",
432
+ "Wh": "energy",
433
+ # Power
434
+ "kW": "power",
435
+ "W": "power",
436
+ # Pressure
437
+ "bar": "pressure",
438
+ "Pa": "pressure",
439
+ "hPa": "pressure",
440
+ # Voltage
441
+ "V": "voltage",
442
+ # Current
443
+ "A": "current",
444
+ "mA": "current",
445
+ # Frequency
446
+ "Hz": "frequency",
447
+ # Volume flow rate
448
+ "l/min": "volume_flow_rate",
449
+ "l/h": "volume_flow_rate",
450
+ # Duration
451
+ "h": "duration",
452
+ "min": "duration",
453
+ "s": "duration",
454
+ # Percentage
455
+ "%": "power_factor",
456
+ }
457
+
458
+ # HA-compatible state class mapping from BSB-LAN units
459
+ # Maps unit strings to HA SensorStateClass values
460
+ UNIT_STATE_CLASS_MAP: Final[dict[str, str]] = {
461
+ # Energy counters are always total_increasing
462
+ "kWh": "total_increasing",
463
+ "MWh": "total_increasing",
464
+ "Wh": "total_increasing",
465
+ # All other numeric measurements
466
+ "°C": "measurement",
467
+ "°F": "measurement",
468
+ "&#176;C": "measurement",
469
+ "&#176;F": "measurement",
470
+ "&deg;C": "measurement",
471
+ "&deg;F": "measurement",
472
+ "kW": "measurement",
473
+ "W": "measurement",
474
+ "bar": "measurement",
475
+ "Pa": "measurement",
476
+ "hPa": "measurement",
477
+ "V": "measurement",
478
+ "A": "measurement",
479
+ "mA": "measurement",
480
+ "Hz": "measurement",
481
+ "l/min": "measurement",
482
+ "l/h": "measurement",
483
+ "%": "measurement",
484
+ "h": "measurement",
485
+ "min": "measurement",
486
+ "s": "measurement",
487
+ }
488
+
418
489
  # Hot Water Parameter Groups
419
490
  # Essential parameters for frequent monitoring
420
491
  HOT_WATER_ESSENTIAL_PARAMS: Final[set[str]] = {
@@ -11,7 +11,11 @@ from typing import Any, Final
11
11
 
12
12
  from mashumaro.mixins.json import DataClassJSONMixin
13
13
 
14
- from bsblan.constants import TEMPERATURE_UNITS
14
+ from bsblan.constants import (
15
+ TEMPERATURE_UNITS,
16
+ UNIT_DEVICE_CLASS_MAP,
17
+ UNIT_STATE_CLASS_MAP,
18
+ )
15
19
 
16
20
  # Maximum number of time slots per day supported by BSB-LAN
17
21
  MAX_TIME_SLOTS_PER_DAY: Final[int] = 3
@@ -225,6 +229,8 @@ class EntityInfo(DataClassJSONMixin):
225
229
  readonly: Whether the value is read-only.
226
230
  readwrite: Whether the value is read-write.
227
231
  precision: Optional precision for numeric values.
232
+ data_type_name: BSB-LAN data type name (e.g., "TEMP", "ENUM").
233
+ data_type_family: BSB-LAN data type family (e.g., "VALS", "ENUM").
228
234
 
229
235
  """
230
236
 
@@ -237,6 +243,8 @@ class EntityInfo(DataClassJSONMixin):
237
243
  readonly: int = field(default=0)
238
244
  readwrite: int = field(default=0)
239
245
  precision: float | None = field(default=None)
246
+ data_type_name: str = field(default="", metadata={"alias": "dataType_name"})
247
+ data_type_family: str = field(default="", metadata={"alias": "dataType_family"})
240
248
 
241
249
  def __post_init__(self) -> None:
242
250
  """Convert values based on data_type after initialization."""
@@ -312,6 +320,45 @@ class EntityInfo(DataClassJSONMixin):
312
320
  """
313
321
  return self.desc if self.data_type == DataType.ENUM else None
314
322
 
323
+ @property
324
+ def suggested_device_class(self) -> str | None:
325
+ """Suggest HA SensorDeviceClass based on unit and data type.
326
+
327
+ Only PLAIN_NUMBER data types are considered sensor-like values.
328
+ Returns None for ENUM, TIME, WEEKDAY, STRING, and other
329
+ non-numeric types even if they carry a unit.
330
+
331
+ Returns:
332
+ str | None: The suggested HA device class (e.g., "temperature",
333
+ "energy", "power"), or None if no mapping exists or the
334
+ data type is not numeric.
335
+
336
+ """
337
+ if self.data_type != DataType.PLAIN_NUMBER:
338
+ return None
339
+ return UNIT_DEVICE_CLASS_MAP.get(self.unit)
340
+
341
+ @property
342
+ def suggested_state_class(self) -> str | None:
343
+ """Suggest HA SensorStateClass based on unit and data type.
344
+
345
+ Only PLAIN_NUMBER data types are considered sensor-like values.
346
+ Returns None for ENUM, TIME, WEEKDAY, STRING, and other
347
+ non-numeric types even if they carry a unit.
348
+
349
+ Energy counters (kWh, MWh, Wh) are mapped to "total_increasing",
350
+ while other numeric measurements use "measurement".
351
+
352
+ Returns:
353
+ str | None: The suggested HA state class (e.g., "measurement",
354
+ "total_increasing"), or None if the data type is not
355
+ numeric or no mapping exists.
356
+
357
+ """
358
+ if self.data_type != DataType.PLAIN_NUMBER:
359
+ return None
360
+ return UNIT_STATE_CLASS_MAP.get(self.unit)
361
+
315
362
 
316
363
  @dataclass
317
364
  class SetHotWaterParam: