1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
# GitHub Copilot Instructions for python-bsblan
This repository contains the `python-bsblan` library, an asynchronous Python client for BSB-LAN devices (heating controllers).
## Project Overview
- **Language**: Python 3.12+
- **Type**: Async library using `aiohttp`
- **Purpose**: Communicate with BSB-LAN devices to read/write heating parameters
- **License**: MIT
## Code Quality Standards
### Required Before Committing
Always run these commands after making changes:
```bash
# Run all pre-commit hooks (ruff, mypy, pylint, pytest)
uv run pre-commit run --all-files
```
### Pre-commit Includes
- **Ruff**: Linting and formatting (88 char line limit)
- **MyPy**: Static type checking
- **Pylint**: Code analysis
- **Pytest**: Test execution with coverage
### Coverage Requirements
- Maintain **95%+ total test coverage**
- **Patch coverage must be 100%** - all new/modified code must be fully tested
- GitHub Actions will fail if patch coverage is below 100%
- Run coverage check: `uv run pytest --cov=src/bsblan --cov-report=term-missing`
## Project Structure
```
src/bsblan/
├── __init__.py # Package exports
├── bsblan.py # Main BSBLAN client class
├── constants.py # Parameter IDs and mappings
├── models.py # Dataclass models for API responses
├── utility.py # Helper utilities
├── exceptions.py # Custom exceptions
└── py.typed # PEP-561 marker
tests/
├── conftest.py # Pytest fixtures
├── fixtures/ # JSON test data
└── test_*.py # Test files
```
## Parameter Naming Conventions
### BSB-LAN Parameters
Parameters are identified by numeric IDs and mapped to readable names in `constants.py`.
**Naming Rules:**
- Use `snake_case` for all parameter names
- Group related parameters with common prefixes
- Legionella-related parameters use `legionella_function_*` prefix:
- `legionella_function_setpoint` (ID: 1645)
- `legionella_function_periodicity` (ID: 1641)
- `legionella_function_day` (ID: 1642)
- `legionella_function_time` (ID: 1644)
- `legionella_function_dwelling_time` (ID: 1646)
- DHW (Domestic Hot Water) parameters use `dhw_*` prefix
### Adding New Parameters
1. **Add to `constants.py`**:
```python
BASE_HOT_WATER_PARAMS: Final[dict[str, str]] = {
"1645": "legionella_function_setpoint", # Parameter ID: name
}
```
2. **Add to model in `models.py`**:
```python
@dataclass
class HotWaterConfig(DataClassORJSONMixin):
legionella_function_setpoint: ParameterValue | None = None
```
3. **Update method in `bsblan.py`** if the parameter is settable:
```python
async def set_hot_water(
self,
legionella_function_setpoint: float | None = None,
) -> None:
```
4. **Add tests in `tests/test_*.py`**
## Polling Categories
Parameters are organized into polling categories based on how frequently they change:
### Fast Poll (State - every update)
- Current temperatures
- HVAC action/state
- Pump states
### Slow Poll (Config - every 5 minutes)
- Operating modes
- Setpoints
- Legionella function settings
- Time programs
### Static (rarely changes)
- Device identification
- Min/max temperature limits
## Data Models
### Model Pattern
All models use `mashumaro` for JSON serialization:
```python
from dataclasses import dataclass
from mashumaro.mixins.orjson import DataClassORJSONMixin
@dataclass
class HotWaterConfig(DataClassORJSONMixin):
"""Hot water configuration parameters."""
operating_mode: ParameterValue | None = None
nominal_setpoint: ParameterValue | None = None
```
### ParameterValue Structure
Each parameter returns a `ParameterValue` with:
- `value`: The actual value
- `unit`: Unit of measurement
- `desc`: Human-readable description
- `dataType`: Data type information
## Async Patterns
### Client Usage
```python
async with BSBLAN(host="192.168.1.100") as client:
state = await client.state()
await client.set_hot_water(nominal_setpoint=55.0)
```
### Error Handling
- Use `BSBLANError` for general errors
- Use `BSBLANConnectionError` for connection issues
- Always validate only one parameter is set per API call
## Testing Patterns
### Test Structure
```python
@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(nominal_setpoint=60.0)
mock_bsblan._request.assert_awaited_with(
base_path="/JS",
data={"Parameter": "1610", "Value": "60.0", "Type": "1"},
)
```
### Fixtures Location
Test fixtures (JSON responses) are in `tests/fixtures/`
## Common Tasks
### Adding a New Settable Parameter
1. Add parameter ID mapping in `constants.py`
2. Add field to appropriate model in `models.py`
3. Add parameter to method signature in `bsblan.py`
4. Update docstring with parameter description
5. Add state preparation logic in `_prepare_*_state()` method
6. Add tests for the new parameter
7. Run `uv run pre-commit run --all-files`
### Renaming a Parameter
When renaming parameters for consistency:
1. Update `constants.py` - parameter mapping
2. Update `models.py` - dataclass field
3. Update `bsblan.py` - method parameters and state handling
4. Update `tests/` - all test files using the parameter
5. Update `examples/` - any example code
6. Run `uv run pre-commit run --all-files`
## API Versions
The library supports BSB-LAN API versions:
- **v1**: Original API
- **v3**: Extended API with additional parameters
Version-specific parameters are handled in `constants.py` with extension dictionaries.
## Don't Forget
- ✅ Run `uv run pre-commit run --all-files` after every change
- ✅ Maintain 95%+ test coverage
- ✅ Use type hints on all functions
- ✅ Add docstrings to public methods
- ✅ Keep line length under 88 characters
- ✅ Use consistent parameter naming (check existing patterns)
|