python-bsblan 6.0.1__tar.gz → 6.1.1__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-6.1.1/.github/agents/security-reviewer.agent.md +32 -0
- python_bsblan-6.1.1/.github/copilot-instructions.md +7 -0
- python_bsblan-6.1.1/.github/hooks/run-validation-after-edits.json +11 -0
- python_bsblan-6.1.1/.github/hooks/run_validation_after_edits.sh +72 -0
- python_bsblan-6.1.1/.github/prompts/code-review.prompt.md +65 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/skills/bsblan-testing/SKILL.md +47 -1
- python_bsblan-6.1.1/.github/skills/feature-doc-updates/SKILL.md +75 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/lock.yaml +1 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/release-drafter.yaml +1 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/stale.yaml +1 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/tests.yaml +10 -2
- python_bsblan-6.1.1/.nvmrc +1 -0
- python_bsblan-6.1.1/AGENTS.md +98 -0
- python_bsblan-6.1.1/CLAUDE.md +1 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/PKG-INFO +1 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/getting-started.md +37 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/index.md +2 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/examples/control.py +97 -95
- python_bsblan-6.1.1/examples/fetch_param.py +165 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/pyproject.toml +3 -3
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/bsblan.py +134 -18
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/constants.py +50 -65
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/models.py +11 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/dict_version.json +3 -2
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/state.json +13 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/state_circuit2.json +13 -0
- python_bsblan-6.1.1/tests/fixtures/static_state.json +37 -0
- python_bsblan-6.1.1/tests/fixtures/static_state_circuit2.json +37 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_api_initialization.py +5 -5
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_api_validation.py +5 -5
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_circuit.py +99 -12
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_constants.py +56 -51
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_include_parameter.py +8 -5
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_initialization.py +5 -7
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_pps.py +18 -0
- python_bsblan-6.1.1/tests/test_state.py +158 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_static_state.py +11 -4
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_temperature_unit.py +6 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_temperature_validation.py +68 -8
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_thermostat.py +41 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_utility.py +2 -1
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_utility_additional.py +3 -2
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_version_errors.py +25 -10
- python_bsblan-6.0.1/.github/copilot-instructions.md +0 -277
- python_bsblan-6.0.1/.github/prompts/code-review.prompt.md +0 -40
- python_bsblan-6.0.1/.nvmrc +0 -1
- python_bsblan-6.0.1/AGENTS.md +0 -1
- python_bsblan-6.0.1/CLAUDE.md +0 -1
- python_bsblan-6.0.1/examples/fetch_param.py +0 -67
- python_bsblan-6.0.1/tests/fixtures/static_state.json +0 -16
- python_bsblan-6.0.1/tests/fixtures/static_state_circuit2.json +0 -16
- python_bsblan-6.0.1/tests/test_state.py +0 -85
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.editorconfig +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.gitattributes +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/CODE_OF_CONDUCT.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/CONTRIBUTING.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/SECURITY.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/labels.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/prompts/add-parameter.prompt.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/release-drafter.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/renovate.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/skills/bsblan-parameters/SKILL.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/auto-approve-renovate.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/codeql.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/dependency-review.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/docs.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/labels.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/linting.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/pr-labels.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/release.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/scorecard.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/workflows/typing.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.github/zizmor.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.gitignore +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.pre-commit-config.yaml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.prettierignore +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/.yamllint +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/LICENSE.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/Makefile +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/README.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/api/client.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/api/constants.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/api/exceptions.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/docs/api/models.md +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/examples/discovery.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/examples/profile_init.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/examples/ruff.toml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/examples/speed_test.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/mkdocs.yml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/package-lock.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/package.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/sonar-project.properties +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/__init__.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/exceptions.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/py.typed +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/src/bsblan/utility.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/__init__.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/conftest.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/device.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/hot_water_state.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/info.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/password.txt +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/pps_device.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/pps_state.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/pps_static_values.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/sensor.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/thermostat_hvac.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/thermostat_temp.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/fixtures/time.json +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/ruff.toml +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_auth.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_backoff_retry.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_bsblan.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_bsblan_edge_cases.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_configuration.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_context_manager.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_device.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_dhw_time_switch.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_entity_info.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_entity_info_ha.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_heating_schedule.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_hot_water_additional.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_hotwater_state.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_info.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_read_parameters.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_reset_validation.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_schedule_models.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_sensor.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_set_heating_schedule.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_set_hot_water_schedule.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_set_hotwater.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_time.py +0 -0
- {python_bsblan-6.0.1 → python_bsblan-6.1.1}/tests/test_utility_edge_cases.py +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use when you need a security review, threat modeling, vulnerability triage, secrets exposure checks, auth/session risk analysis, input validation review, dependency risk review, or secure coding feedback."
|
|
3
|
+
name: "Security Reviewer"
|
|
4
|
+
tools: [read, search]
|
|
5
|
+
argument-hint: "Provide scope (files, PR, or feature), threat context, and any known attack surface."
|
|
6
|
+
---
|
|
7
|
+
You are a specialist security code reviewer. Your job is to find exploitable risks and provide precise, actionable remediation guidance.
|
|
8
|
+
|
|
9
|
+
## Constraints
|
|
10
|
+
- DO NOT refactor for style or performance unless it directly affects security.
|
|
11
|
+
- DO NOT propose broad rewrites when a targeted fix is sufficient.
|
|
12
|
+
- DO NOT claim an issue without explaining exploitability, impact, and preconditions.
|
|
13
|
+
- ONLY report findings that are security-relevant or materially increase security risk.
|
|
14
|
+
|
|
15
|
+
## Approach
|
|
16
|
+
1. Map attack surface first: inputs, trust boundaries, secrets, authn/authz, network calls, file/system access, and third-party dependencies.
|
|
17
|
+
2. Prioritize exploitability over code smell; assess realistic attacker paths and blast radius.
|
|
18
|
+
3. Verify mitigations already present to avoid false positives.
|
|
19
|
+
4. Provide concrete fixes with smallest safe change and validation steps.
|
|
20
|
+
|
|
21
|
+
## Output Format
|
|
22
|
+
1. Findings (ordered by severity: critical, high, medium, low)
|
|
23
|
+
- Title
|
|
24
|
+
- Severity
|
|
25
|
+
- Location (file and line)
|
|
26
|
+
- Why this is vulnerable
|
|
27
|
+
- Exploit scenario
|
|
28
|
+
- Recommended fix
|
|
29
|
+
2. Open questions or assumptions
|
|
30
|
+
3. Residual risk and security test gaps
|
|
31
|
+
|
|
32
|
+
If no findings are discovered, explicitly state that and list residual risks or testing gaps.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
payload="$(cat)"
|
|
5
|
+
|
|
6
|
+
should_run="$(HOOK_PAYLOAD="$payload" python3 - <<'PY'
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
edit_tool_tokens = {
|
|
12
|
+
"edit",
|
|
13
|
+
"write",
|
|
14
|
+
"multi_edit",
|
|
15
|
+
"multiedit",
|
|
16
|
+
"apply_patch",
|
|
17
|
+
"create_file",
|
|
18
|
+
"edit_notebook_file",
|
|
19
|
+
"create_new_jupyter_notebook",
|
|
20
|
+
"mcp_github_create_or_update_file",
|
|
21
|
+
"mcp_io_github_git_create_or_update_file",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def walk(value):
|
|
25
|
+
if isinstance(value, dict):
|
|
26
|
+
for key, item in value.items():
|
|
27
|
+
yield str(key)
|
|
28
|
+
yield from walk(item)
|
|
29
|
+
elif isinstance(value, list):
|
|
30
|
+
for item in value:
|
|
31
|
+
yield from walk(item)
|
|
32
|
+
elif isinstance(value, str):
|
|
33
|
+
yield value
|
|
34
|
+
|
|
35
|
+
raw = os.environ.get("HOOK_PAYLOAD", "").strip()
|
|
36
|
+
if not raw:
|
|
37
|
+
print("skip")
|
|
38
|
+
raise SystemExit(0)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
data = json.loads(raw)
|
|
42
|
+
except json.JSONDecodeError:
|
|
43
|
+
print("skip")
|
|
44
|
+
raise SystemExit(0)
|
|
45
|
+
|
|
46
|
+
haystack = "\n".join(s.lower() for s in walk(data))
|
|
47
|
+
if any(token in haystack for token in edit_tool_tokens):
|
|
48
|
+
print("run")
|
|
49
|
+
else:
|
|
50
|
+
print("skip")
|
|
51
|
+
PY
|
|
52
|
+
)"
|
|
53
|
+
|
|
54
|
+
if [[ "$should_run" != "run" ]]; then
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "[hook] File edit detected. Running validation commands..."
|
|
59
|
+
|
|
60
|
+
echo "[hook] Running tests"
|
|
61
|
+
if ! uv run pytest --no-cov; then
|
|
62
|
+
echo "[hook] Tests failed"
|
|
63
|
+
exit 2
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
echo "[hook] Running prek"
|
|
67
|
+
if ! uv run prek run --all-files; then
|
|
68
|
+
echo "[hook] Prek failed"
|
|
69
|
+
exit 2
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "[hook] Validation passed"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Code Review
|
|
3
|
+
agent: agent
|
|
4
|
+
description: Review python-bsblan changes with findings first and repo quality gates
|
|
5
|
+
argument-hint: "Scope to review (staged changes, PR #, or file paths)"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Code Review
|
|
9
|
+
|
|
10
|
+
Review the requested scope for regressions, correctness issues, and missing
|
|
11
|
+
tests.
|
|
12
|
+
|
|
13
|
+
Prioritize findings over summaries and order findings by severity.
|
|
14
|
+
Use this output format:
|
|
15
|
+
|
|
16
|
+
1. Findings
|
|
17
|
+
- Severity (`high`, `medium`, `low`), location, and impact.
|
|
18
|
+
- Include precise file references and actionable fixes.
|
|
19
|
+
|
|
20
|
+
2. Open Questions / Assumptions
|
|
21
|
+
- Unknowns that block confidence in the review.
|
|
22
|
+
|
|
23
|
+
3. Change Summary
|
|
24
|
+
- Brief recap only after findings.
|
|
25
|
+
|
|
26
|
+
Reference these standards while reviewing:
|
|
27
|
+
- [CONTRIBUTING](../CONTRIBUTING.md)
|
|
28
|
+
- [Copilot instructions](../copilot-instructions.md)
|
|
29
|
+
|
|
30
|
+
## Review Checks
|
|
31
|
+
|
|
32
|
+
### Code Quality
|
|
33
|
+
- [ ] Type hints on all functions
|
|
34
|
+
- [ ] Docstrings on public methods
|
|
35
|
+
- [ ] Line length under 88 characters
|
|
36
|
+
- [ ] Consistent parameter naming (snake_case)
|
|
37
|
+
|
|
38
|
+
### Testing
|
|
39
|
+
- [ ] Tests added for new functionality
|
|
40
|
+
- [ ] Total coverage remains 95%+
|
|
41
|
+
- [ ] Patch coverage for changed code is 100%
|
|
42
|
+
|
|
43
|
+
### Patterns
|
|
44
|
+
- [ ] Response models use `pydantic` `BaseModel`
|
|
45
|
+
- [ ] Set-parameter models use `@dataclass`
|
|
46
|
+
- [ ] Uses `aiohttp` for async HTTP
|
|
47
|
+
- [ ] Follows existing parameter naming conventions
|
|
48
|
+
- [ ] Error handling uses custom exceptions (`BSBLANError`,
|
|
49
|
+
`BSBLANConnectionError`)
|
|
50
|
+
|
|
51
|
+
### Prek
|
|
52
|
+
- [ ] Ruff passes (linting + formatting)
|
|
53
|
+
- [ ] ty passes (type checking)
|
|
54
|
+
- [ ] Pylint passes (code analysis)
|
|
55
|
+
- [ ] Pytest passes (tests)
|
|
56
|
+
|
|
57
|
+
## Validation Commands
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv run prek run --all-files
|
|
61
|
+
uv run pytest --cov=src/bsblan --cov-report=term-missing
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If no findings are discovered, explicitly say so and list any residual testing
|
|
65
|
+
gaps.
|
|
@@ -39,7 +39,16 @@ Test fixtures (JSON responses) are in `tests/fixtures/`. Common fixtures:
|
|
|
39
39
|
- `hot_water_state.json` - Hot water state
|
|
40
40
|
- `sensor.json` - Sensor readings
|
|
41
41
|
|
|
42
|
-
Load fixtures using
|
|
42
|
+
Load fixtures using `load_fixture(filename: str) -> str` from `tests/__init__.py`.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import json
|
|
46
|
+
|
|
47
|
+
from tests import load_fixture
|
|
48
|
+
|
|
49
|
+
raw = load_fixture("device.json")
|
|
50
|
+
data = json.loads(raw) # parsed dict[str, Any]
|
|
51
|
+
```
|
|
43
52
|
|
|
44
53
|
## Coverage Requirements
|
|
45
54
|
|
|
@@ -84,6 +93,8 @@ CI enforces:
|
|
|
84
93
|
- Patch coverage = 100% (Codecov checks new/modified lines)
|
|
85
94
|
|
|
86
95
|
If CI fails with coverage issues, check the Codecov report in the PR for uncovered lines.
|
|
96
|
+
If a line is genuinely untestable (for example defensive guards), mark it with
|
|
97
|
+
`# pragma: no cover` and justify that choice in the PR description.
|
|
87
98
|
|
|
88
99
|
## Running Tests
|
|
89
100
|
|
|
@@ -126,6 +137,41 @@ mock_bsblan._request.assert_awaited_with(
|
|
|
126
137
|
)
|
|
127
138
|
```
|
|
128
139
|
|
|
140
|
+
### Fixture Setup and Registration
|
|
141
|
+
|
|
142
|
+
Define shared fixtures in `tests/conftest.py` so pytest auto-discovers them.
|
|
143
|
+
Use the `mock_bsblan` pattern for naming and setup:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
@pytest.fixture
|
|
147
|
+
async def mock_bsblan(
|
|
148
|
+
aresponses: ResponsesMockServer,
|
|
149
|
+
monkeypatch: Any,
|
|
150
|
+
) -> AsyncGenerator[BSBLAN, Any]:
|
|
151
|
+
...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Add new JSON payloads in `tests/fixtures/` with descriptive, snake_case names
|
|
155
|
+
that match the behavior under test.
|
|
156
|
+
|
|
157
|
+
### Mocking HTTP Response Handling
|
|
158
|
+
|
|
159
|
+
Use `monkeypatch` with `AsyncMock` to return fixture payloads when testing
|
|
160
|
+
response parsing logic (not only outgoing request arguments):
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import json
|
|
164
|
+
from unittest.mock import AsyncMock
|
|
165
|
+
|
|
166
|
+
from tests import load_fixture
|
|
167
|
+
|
|
168
|
+
request_mock = AsyncMock(return_value=json.loads(load_fixture("state.json")))
|
|
169
|
+
monkeypatch.setattr(bsblan, "_request", request_mock)
|
|
170
|
+
|
|
171
|
+
state = await bsblan.state()
|
|
172
|
+
assert state.current_temperature is not None
|
|
173
|
+
```
|
|
174
|
+
|
|
129
175
|
## Testing Lazy Loading
|
|
130
176
|
|
|
131
177
|
When testing hot water methods, mark param groups as validated to skip network calls:
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feature-doc-updates
|
|
3
|
+
description: Ensure README and documentation are updated when adding features in python-bsblan. Use when implementing new behavior, parameters, API surface changes, or user-visible capabilities.
|
|
4
|
+
argument-hint: What feature was added and which files changed?
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Feature Documentation Updates
|
|
8
|
+
|
|
9
|
+
Use this skill after implementing a feature so user-facing documentation stays accurate.
|
|
10
|
+
|
|
11
|
+
## When To Use
|
|
12
|
+
|
|
13
|
+
Use this workflow when a change includes one or more of the following:
|
|
14
|
+
- New public method, model field, parameter, or behavior.
|
|
15
|
+
- Changed defaults, constraints, validation, or supported API versions.
|
|
16
|
+
- New examples, setup steps, or migration considerations.
|
|
17
|
+
- Any change that would alter how users call or understand the library.
|
|
18
|
+
|
|
19
|
+
## Inputs
|
|
20
|
+
|
|
21
|
+
Collect these inputs before writing docs:
|
|
22
|
+
- Feature summary in one sentence.
|
|
23
|
+
- Files changed in src and tests.
|
|
24
|
+
- Any new parameter IDs and names.
|
|
25
|
+
- Breaking changes or renamed fields.
|
|
26
|
+
- Example usage snippet (if applicable).
|
|
27
|
+
|
|
28
|
+
## Procedure
|
|
29
|
+
|
|
30
|
+
1. Classify feature impact.
|
|
31
|
+
- User-facing: update README and docs pages.
|
|
32
|
+
- Internal-only refactor with identical behavior: docs update is optional; add a short rationale in PR notes.
|
|
33
|
+
|
|
34
|
+
2. Determine documentation targets.
|
|
35
|
+
- Update README when install, quick start, supported behavior, or public API usage changes.
|
|
36
|
+
- Update docs under docs/ when API, constants, models, or behavior explanations changed.
|
|
37
|
+
- Update examples/ when new behavior benefits from a runnable example.
|
|
38
|
+
|
|
39
|
+
3. Apply documentation updates.
|
|
40
|
+
- README: adjust feature lists, capability notes, usage snippets, and compatibility statements.
|
|
41
|
+
- docs/: update the relevant page in docs/api or docs/getting-started to match the implementation.
|
|
42
|
+
- Keep terms, parameter names, and types identical to source code.
|
|
43
|
+
|
|
44
|
+
4. Validate consistency with code.
|
|
45
|
+
- Confirm names in docs match constants and model fields exactly.
|
|
46
|
+
- Confirm examples call real methods and use valid arguments.
|
|
47
|
+
- Confirm version notes align with constants version-gating logic.
|
|
48
|
+
|
|
49
|
+
5. Check deprecations and renames.
|
|
50
|
+
- If a public field/parameter is renamed, document migration guidance.
|
|
51
|
+
- Mention deprecation behavior and replacement names in docs where users will see it.
|
|
52
|
+
|
|
53
|
+
6. Run quality checks.
|
|
54
|
+
- Run project checks: uv run prek run --all-files
|
|
55
|
+
- If API/docs behavior changed, run tests to verify examples and described behavior are still valid.
|
|
56
|
+
|
|
57
|
+
7. Final completion check.
|
|
58
|
+
- README updated if user-visible behavior changed.
|
|
59
|
+
- Relevant docs pages updated if API or behavior changed.
|
|
60
|
+
- Any required examples updated.
|
|
61
|
+
- PR description includes a short Docs Updated section listing touched doc files.
|
|
62
|
+
|
|
63
|
+
## Decision Rules
|
|
64
|
+
|
|
65
|
+
- Update README is required when feature discovery or onboarding changes.
|
|
66
|
+
- Update docs pages is required when API shape or semantics change.
|
|
67
|
+
- If neither changed, explicitly state why docs were not updated.
|
|
68
|
+
|
|
69
|
+
## Output Format
|
|
70
|
+
|
|
71
|
+
When using this skill, produce:
|
|
72
|
+
1. Documentation Impact Summary.
|
|
73
|
+
2. Files updated (README, docs pages, examples).
|
|
74
|
+
3. Any follow-up docs work still needed.
|
|
75
|
+
4. Validation status for checks/tests.
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
pull-requests: write
|
|
19
19
|
steps:
|
|
20
20
|
# yamllint disable-line rule:line-length
|
|
21
|
-
- uses: dessant/lock-threads@
|
|
21
|
+
- uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6.0.2
|
|
22
22
|
with:
|
|
23
23
|
github-token: ${{ github.token }}
|
|
24
24
|
issue-inactive-days: "30"
|
|
@@ -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@
|
|
39
|
+
uses: release-drafter/release-drafter@693d20e7c1ce1a81d3a41962f85914253b518449 # v7.3.1
|
|
40
40
|
with:
|
|
41
41
|
prerelease: ${{ github.event.inputs.prerelease == 'true' }}
|
|
42
42
|
prerelease-identifier: ${{ github.event.inputs.prerelease_identifier }}
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
pull-requests: write
|
|
19
19
|
steps:
|
|
20
20
|
- name: 🚀 Run stale
|
|
21
|
-
uses: actions/stale@
|
|
21
|
+
uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
|
22
22
|
with:
|
|
23
23
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
24
24
|
days-before-stale: 30
|
|
@@ -86,14 +86,22 @@ jobs:
|
|
|
86
86
|
if: env.HAS_CODECOV_TOKEN == 'true'
|
|
87
87
|
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
|
88
88
|
with:
|
|
89
|
+
fail_ci_if_error: true
|
|
90
|
+
files: coverage.xml
|
|
89
91
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
92
|
+
- name: 🚀 Upload coverage report (tokenless)
|
|
93
|
+
if: env.HAS_CODECOV_TOKEN != 'true' && github.event_name == 'pull_request'
|
|
94
|
+
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
|
95
|
+
with:
|
|
96
|
+
fail_ci_if_error: false
|
|
97
|
+
files: coverage.xml
|
|
90
98
|
- name: ℹ️ Skip Codecov upload (missing token)
|
|
91
|
-
if: env.HAS_CODECOV_TOKEN != 'true'
|
|
99
|
+
if: env.HAS_CODECOV_TOKEN != 'true' && github.event_name != 'pull_request'
|
|
92
100
|
run: echo "CODECOV_TOKEN is not set; skipping Codecov upload."
|
|
93
101
|
- name: SonarQube Cloud Scan
|
|
94
102
|
if: env.HAS_SONAR_TOKEN == 'true' && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork)
|
|
95
103
|
# yamllint disable-line rule:line-length
|
|
96
|
-
uses: SonarSource/sonarqube-scan-action@
|
|
104
|
+
uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1
|
|
97
105
|
env:
|
|
98
106
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
99
107
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
24.16.0
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Agent Instructions for python-bsblan
|
|
2
|
+
|
|
3
|
+
This file is the canonical AI agent guide for this repository.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
- Applies to the whole workspace.
|
|
8
|
+
- Prefer links to project docs instead of duplicating large policy text.
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
|
|
12
|
+
- Python 3.12+
|
|
13
|
+
- uv for Python dependency management
|
|
14
|
+
- Node.js (used by formatting hooks)
|
|
15
|
+
|
|
16
|
+
Setup commands:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install
|
|
20
|
+
make setup
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Required Validation
|
|
24
|
+
|
|
25
|
+
Before finishing changes, run:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv run prek run --all-files
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Useful test commands:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv run pytest
|
|
35
|
+
uv run pytest --cov=src/bsblan --cov-report=term-missing
|
|
36
|
+
uv run pytest --no-cov tests/test_file.py -k test_name
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Quality gate expectations:
|
|
40
|
+
|
|
41
|
+
- Keep total coverage at 95%+.
|
|
42
|
+
- Keep patch coverage at 100% for modified lines.
|
|
43
|
+
|
|
44
|
+
## Code Map
|
|
45
|
+
|
|
46
|
+
- `src/bsblan/bsblan.py`: main async client (`BSBLAN`), request handling, lazy loading
|
|
47
|
+
- `src/bsblan/constants.py`: parameter IDs and name mappings
|
|
48
|
+
- `src/bsblan/models.py`: response models (`pydantic`) and set-param models (`dataclass`)
|
|
49
|
+
- `src/bsblan/utility.py`: helpers and API validation
|
|
50
|
+
- `src/bsblan/exceptions.py`: library exceptions
|
|
51
|
+
- `tests/conftest.py`: shared pytest fixtures (`mock_bsblan`)
|
|
52
|
+
|
|
53
|
+
## Project Conventions
|
|
54
|
+
|
|
55
|
+
- Use type hints on all functions.
|
|
56
|
+
- Keep line length <= 88 chars (Ruff).
|
|
57
|
+
- Response/state models use `pydantic.BaseModel`.
|
|
58
|
+
- Set-parameter payload models use `@dataclass`.
|
|
59
|
+
- Parameter names use `snake_case`.
|
|
60
|
+
- For set operations, send one `/JS` request per populated parameter.
|
|
61
|
+
- Treat API v3 as the supported baseline (do not reintroduce v1-only behavior).
|
|
62
|
+
|
|
63
|
+
Naming patterns to preserve:
|
|
64
|
+
|
|
65
|
+
- `legionella_function_*`
|
|
66
|
+
- `dhw_*`
|
|
67
|
+
|
|
68
|
+
## Parameter Change Workflow
|
|
69
|
+
|
|
70
|
+
When adding or renaming parameters:
|
|
71
|
+
|
|
72
|
+
1. Query real-device raw data with `examples/fetch_param.py`.
|
|
73
|
+
2. Update mappings in `src/bsblan/constants.py`.
|
|
74
|
+
3. Update response models in `src/bsblan/models.py`.
|
|
75
|
+
4. If settable, update set dataclass and client setter logic.
|
|
76
|
+
5. Add/adjust tests in `tests/`.
|
|
77
|
+
6. Run full validation (`uv run prek run --all-files`).
|
|
78
|
+
|
|
79
|
+
If raw responses are incomplete or `data_type` is unknown, prefer
|
|
80
|
+
`EntityInfo[str] | None` and avoid guessing numeric types.
|
|
81
|
+
|
|
82
|
+
## Common Pitfalls
|
|
83
|
+
|
|
84
|
+
- Partial pytest runs can fail coverage gates; use `--no-cov` for focused checks.
|
|
85
|
+
- Missing Node.js dependencies can break formatting hooks.
|
|
86
|
+
- Do not confuse comfort/protective/cooling bounds when selecting IDs.
|
|
87
|
+
|
|
88
|
+
## Source-of-Truth Docs
|
|
89
|
+
|
|
90
|
+
- Contribution and development process: `.github/CONTRIBUTING.md`
|
|
91
|
+
- User-facing usage and setup: `README.md`
|
|
92
|
+
- Developer docs index: `docs/index.md`
|
|
93
|
+
- Getting started examples: `docs/getting-started.md`
|
|
94
|
+
- API reference: `docs/api/client.md`
|
|
95
|
+
|
|
96
|
+
## Legacy Compatibility
|
|
97
|
+
|
|
98
|
+
- `.github/copilot-instructions.md` and `CLAUDE.md` should reference this file.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -63,6 +63,43 @@ async def main() -> None:
|
|
|
63
63
|
asyncio.run(main())
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
## Temperature bounds
|
|
67
|
+
|
|
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.
|
|
73
|
+
|
|
74
|
+
## Cooling setpoint support
|
|
75
|
+
|
|
76
|
+
Some BSB/LPB controllers expose a cooling comfort setpoint for each heating
|
|
77
|
+
circuit. The client maps BSB-LAN parameter `902` for circuit 1 and `1202` for
|
|
78
|
+
circuit 2 to `target_temperature_high`; the duplicate decimal parameters
|
|
79
|
+
`902.1` and `902.2` are not used.
|
|
80
|
+
|
|
81
|
+
When available, cooling setpoint validation uses `905`/`1205` (comfort setpoint
|
|
82
|
+
minimum) as the lower bound and `903`/`1203` (room temperature reduced setpoint)
|
|
83
|
+
as the upper bound. Parameters `908` and `1208` are flow setpoints and are not
|
|
84
|
+
used for room setpoint validation.
|
|
85
|
+
|
|
86
|
+
Cooling support is optional. During section validation, unsupported parameters
|
|
87
|
+
are removed from the active API map, so integrations can detect support by
|
|
88
|
+
checking whether `state.target_temperature_high` is present.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
async with BSBLAN(config) as client:
|
|
92
|
+
state = await client.state(include=["target_temperature_high"])
|
|
93
|
+
|
|
94
|
+
if state.target_temperature_high is not None:
|
|
95
|
+
print(f"Cooling setpoint: {state.target_temperature_high.value}")
|
|
96
|
+
await client.thermostat(target_temperature_high="24.0")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
BSB-LAN writes one parameter at a time. If an application exposes a heat/cool
|
|
100
|
+
temperature range, write `target_temperature` and `target_temperature_high` with
|
|
101
|
+
separate `thermostat()` calls.
|
|
102
|
+
|
|
66
103
|
## PPS bus support
|
|
67
104
|
|
|
68
105
|
PPS bus devices are detected from the device metadata returned by BSB-LAN. The
|
|
@@ -7,8 +7,9 @@ Asynchronous Python client for [BSB-LAN](https://github.com/fredlcore/bsb_lan) d
|
|
|
7
7
|
- Async/await support using `aiohttp`
|
|
8
8
|
- Read heating state, sensor data, and device information
|
|
9
9
|
- Control thermostat settings and hot water parameters
|
|
10
|
+
- Detect optional cooling setpoints for heat/cool range controls
|
|
10
11
|
- Fully typed with PEP 561 support
|
|
11
|
-
-
|
|
12
|
+
- API v3 parameter support
|
|
12
13
|
- Lazy loading with per-section validation
|
|
13
14
|
|
|
14
15
|
## Quick example
|