Add new BSB-LAN parameters to the python-bsblan library. Use this skill when adding parameter IDs, updating models, or extending the API to support new heating controller parameters.
This skill guides you through adding new parameters to the python-bsblan library.
snake_case for all parameter nameslegionella_function_* prefixdhw_* prefixBefore adding a new parameter, use examples/fetch_param.py to retrieve the raw API response from a real BSB-LAN device. This shows the exact structure, data types, units, and descriptions returned by the device.
# Set environment variables for your device
export BSBLAN_HOST=<ip-or-host> # Your BSB-LAN IP address; leave unset to use autodiscovery
export BSBLAN_PASSKEY=your_passkey # Optional: if your device requires a passkey
export BSBLAN_USER=username # Optional: if authentication is enabled
export BSBLAN_PASS=password # Optional: if authentication is enabled
export BSBLAN_PORT=80 # Optional: defaults to 80
# Fetch a single parameter
cd examples && python fetch_param.py 1645
# Fetch multiple parameters at once
cd examples && python fetch_param.py 1645 1641 1642 1644 1646
The raw API response shows the exact structure you need to model:
{
"1645": {
"name": "Legionella function setpoint",
"value": "70.0",
"unit": "°C",
"desc": "",
"dataType": 0
}
}
Use this output to determine:
float, int, or str based on the value formatunit field (e.g., °C, %, -)name field for docstringsdataType field for EntityInfo typingfetch_param.py uses mDNS/Zeroconf discovery (via examples/discovery.py) to find your BSB-LAN device automatically when BSBLAN_HOST is not set. If mDNS is unavailable, set the BSBLAN_HOST environment variable directly.
constants.pyAdd the parameter ID mapping:
BASE_HOT_WATER_PARAMS: Final[dict[str, str]] = {
"1645": "legionella_function_setpoint", # Parameter ID: name
}
models.pyAdd the field to the appropriate model:
class HotWaterConfig(BaseModel):
legionella_function_setpoint: EntityInfo[float] | None = None
bsblan.py (if settable)Add parameter to the method signature:
async def set_hot_water(
self,
legionella_function_setpoint: float | None = None,
) -> None:
Create tests in tests/test_*.py:
@pytest.mark.asyncio
async def test_set_hot_water(mock_bsblan: BSBLAN) -> None:
"""Test setting BSBLAN hot water state."""
await mock_bsblan.set_hot_water(
SetHotWaterParam(nominal_setpoint=60.0)
)
mock_bsblan._request.assert_awaited_with(
base_path="/JS",
data={"Parameter": "1610", "Value": "60.0", "Type": "1"},
)
Parameters are organized by update frequency:
Hot water parameters use granular lazy loading. When adding a new hot water param, add it to the appropriate group in constants.py:
| Group | Constant | Method |
|---|---|---|
| Essential (5 params) | HOT_WATER_ESSENTIAL_PARAMS |
hot_water_state() |
| Config (16 params) | HOT_WATER_CONFIG_PARAMS |
hot_water_config() |
| Schedule (8 params) | HOT_WATER_SCHEDULE_PARAMS |
hot_water_schedule() |
# In constants.py - add to appropriate group set:
HOT_WATER_ESSENTIAL_PARAMS: Final[set[str]] = {"1600", "1610", ...}
HOT_WATER_CONFIG_PARAMS: Final[set[str]] = {"1601", "1614", ...}
The library uses asyncio locks to prevent race conditions:
_section_locks: Per-section locks for lazy loading_hot_water_group_locks: Per-group locks for hot water validationWhen adding new sections or groups, the lock is created automatically on first access.
Always run after changes:
uv run prek run --all-files
uv run pytest --cov=src/bsblan --cov-report=term-missing
Coverage requirements: 95%+ total, 100% patch coverage.