Skip to content

Models

Data models for BSB-LAN API responses.

Core types

EntityInfo

bsblan.EntityInfo

Bases: BaseModel, Generic[T]

BSB-LAN parameter info with automatic type conversion.

This object holds info about specific objects and handles automatic type conversion based on data_type and unit.

The generic parameter T indicates the expected value type after conversion:

  • EntityInfo[float] for temperature / numeric sensor values
  • EntityInfo[int] for enums, weekdays and plain integers
  • EntityInfo[time] for HH:MM time values
  • EntityInfo[str] for string / datetime values

When the device returns "---" (sensor not in use), value is set to None.

Attributes:

Name Type Description
name str

Name attribute.

value T | None

Converted value, or None when sensor/parameter is inactive.

unit str

Unit of measurement.

desc str

Description of the entity.

data_type int

Type of data (see DataType enum).

error int

Error code (0 for no error).

readonly int

Whether the value is read-only.

readwrite int

Whether the value is read-write.

precision float | None

Optional precision for numeric values.

data_type_name str

BSB-LAN data type name (e.g., "TEMP", "ENUM").

data_type_family str

BSB-LAN data type family (e.g., "VALS", "ENUM").

enum_description property

enum_description: str | None

Get the description for ENUM values.

Returns:

Type Description
str | None

str | None: The description of the ENUM value, or None.

suggested_device_class property

suggested_device_class: str | None

Suggest HA SensorDeviceClass based on unit and data type.

Only PLAIN_NUMBER data types are considered sensor-like values. Returns None for ENUM, TIME, WEEKDAY, STRING, and other non-numeric types even if they carry a unit.

Returns:

Type Description
str | None

str | None: The suggested HA device class (e.g., "temperature", "energy", "power"), or None if no mapping exists or the data type is not numeric.

suggested_state_class property

suggested_state_class: str | None

Suggest HA SensorStateClass based on unit and data type.

Only PLAIN_NUMBER data types are considered sensor-like values. Returns None for ENUM, TIME, WEEKDAY, STRING, and other non-numeric types even if they carry a unit.

Energy counters (kWh, MWh, Wh) are mapped to "total_increasing", while other numeric measurements use "measurement".

Returns:

Type Description
str | None

str | None: The suggested HA state class (e.g., "measurement", "total_increasing"), or None if the data type is not numeric or no mapping exists.

convert_raw_value classmethod

convert_raw_value(data: dict[str, Any]) -> dict[str, Any]

Convert raw string values before pydantic validates types.

BSB-LAN always sends values as strings. This validator converts them to the correct Python type (float, int, time) before pydantic's type checking runs.

Some STRING-type parameters (e.g. "7968 kWh") embed a numeric value with a unit suffix. When the unit field is empty and the value matches <number> <known-unit>, the numeric part is extracted and the unit field is populated automatically.

Source code in src/bsblan/models.py
@model_validator(mode="before")
@classmethod
def convert_raw_value(cls, data: dict[str, Any]) -> dict[str, Any]:
    """Convert raw string values before pydantic validates types.

    BSB-LAN always sends values as strings. This validator converts
    them to the correct Python type (float, int, time) before
    pydantic's type checking runs.

    Some STRING-type parameters (e.g. "7968 kWh") embed a numeric
    value with a unit suffix.  When the ``unit`` field is empty and
    the value matches ``<number> <known-unit>``, the numeric part is
    extracted and the ``unit`` field is populated automatically.
    """
    raw_value = data.get("value")
    # Resolve data_type from either alias or field name
    data_type = data.get("dataType", data.get("data_type", 0))
    unit = data.get("unit", "")

    data["value"] = _convert_bsblan_value(raw_value, data_type, unit)

    # Handle STRING values with embedded units (e.g. "7968 kWh")
    converted = data["value"]
    if isinstance(converted, str) and not unit and data_type == DataType.STRING:
        match = re.match(r"^(\d+(?:\.\d+)?)\s+(\S+)$", converted)
        if match and match.group(2) in UNIT_DEVICE_CLASS_MAP:
            num_str = match.group(1)
            data["value"] = float(num_str) if "." in num_str else int(num_str)
            data["unit"] = match.group(2)

    return data

EntityValue

bsblan.EntityValue module-attribute

EntityValue = float | int | str | time

Heating

State

bsblan.State

Bases: BaseModel

Object that holds information about the state of a climate system.

All fields are optional to support partial fetching via the include parameter. When using state() without include, all required parameters will be populated.

StaticState

bsblan.StaticState

Bases: BaseModel

Class for entities that are not changing.

Sensor

bsblan.Sensor

Bases: BaseModel

Object holds info about object for sensor climate.

Hot water

HotWaterState

bsblan.HotWaterState

Bases: BaseModel

Essential hot water state information (READ from device).

This class contains only the most important hot water parameters that are typically checked frequently for monitoring purposes.

Note

This is for READING from the device. For WRITING parameters, use SetHotWaterParam with set_hot_water().

HotWaterConfig

bsblan.HotWaterConfig

Bases: BaseModel

Hot water configuration and advanced settings (READ from device).

This class contains configuration parameters that are typically set once and checked less frequently.

Note

This is for READING from the device. For WRITING parameters, use SetHotWaterParam with set_hot_water().

HotWaterSchedule

bsblan.HotWaterSchedule

Bases: BaseModel

Hot water time program schedules (READ from device).

This class contains time program settings that are typically configured once and rarely changed.

The daily time programs (Monday-Sunday) use BSB-LAN dataType 9 (TIMEPROG) and return schedule strings like "13:00-15:00 ##:##-##:## ##:##-##:##" where ##:## marks unused time slots.

dhw_time_program_standard_values is a YESNO enum (0=No, 1=Yes) that resets all daily schedules back to the controller's factory defaults when set to Yes. It is typically read-only via the API.

Note

This is for READING from the device. For WRITING time programs, use SetHotWaterParam with set_hot_water().

SetHotWaterParam

bsblan.SetHotWaterParam dataclass

SetHotWaterParam(
    nominal_setpoint: float | None = None,
    reduced_setpoint: float | None = None,
    nominal_setpoint_max: float | None = None,
    operating_mode: str | None = None,
    dhw_time_programs: DHWTimeSwitchPrograms | None = None,
    eco_mode_selection: str | None = None,
    dhw_charging_priority: str | None = None,
    legionella_function_setpoint: float | None = None,
    legionella_function_periodicity: str | None = None,
    legionella_function_day: str | None = None,
    legionella_function_time: str | None = None,
    legionella_function_dwelling_time: float | None = None,
    operating_mode_changeover: str | None = None,
)

Parameters for setting hot water configuration.

Use this dataclass to pass parameters to set_hot_water(). Only one parameter should be set at a time (BSB-LAN API limitation).

Note

This is for WRITING to the device. For READING hot water data, use HotWaterState, HotWaterConfig, or HotWaterSchedule.

Attributes:

Name Type Description
nominal_setpoint float | None

The nominal setpoint temperature.

reduced_setpoint float | None

The reduced setpoint temperature.

nominal_setpoint_max float | None

The maximum nominal setpoint temperature.

operating_mode str | None

The operating mode (e.g., "0"=Off, "1"=On).

dhw_time_programs DHWTimeSwitchPrograms | None

Time switch programs for DHW.

eco_mode_selection str | None

Eco mode selection.

dhw_charging_priority str | None

DHW charging priority.

legionella_function_setpoint float | None

Legionella function setpoint temperature.

legionella_function_periodicity str | None

Legionella function periodicity.

legionella_function_day str | None

Day for legionella function.

legionella_function_time str | None

Time for legionella function (HH:MM).

legionella_function_dwelling_time float | None

Legionella dwelling time (min).

operating_mode_changeover str | None

Operating mode changeover.

Schedules

DHWSchedule

bsblan.DHWSchedule dataclass

DHWSchedule(
    monday: DaySchedule | None = None,
    tuesday: DaySchedule | None = None,
    wednesday: DaySchedule | None = None,
    thursday: DaySchedule | None = None,
    friday: DaySchedule | None = None,
    saturday: DaySchedule | None = None,
    sunday: DaySchedule | None = None,
)

Weekly hot water schedule for setting time programs.

Use this dataclass to set DHW time programs via set_hot_water_schedule(). Each day can have up to 3 time slots.

Example

schedule = DHWSchedule( ... monday=DaySchedule(slots=[ ... TimeSlot(time(6, 0), time(8, 0)), ... TimeSlot(time(17, 0), time(21, 0)), ... ]), ... tuesday=DaySchedule(slots=[ ... TimeSlot(time(6, 0), time(8, 0)), ... ]) ... ) await client.set_hot_water_schedule(schedule)

has_any_schedule

has_any_schedule() -> bool

Check if any day has a schedule set.

Returns:

Name Type Description
bool bool

True if at least one day has a schedule.

Source code in src/bsblan/models.py
def has_any_schedule(self) -> bool:
    """Check if any day has a schedule set.

    Returns:
        bool: True if at least one day has a schedule.

    """
    return any(
        day is not None
        for day in [
            self.monday,
            self.tuesday,
            self.wednesday,
            self.thursday,
            self.friday,
            self.saturday,
            self.sunday,
        ]
    )

DHWTimeSwitchPrograms

bsblan.DHWTimeSwitchPrograms dataclass

DHWTimeSwitchPrograms(
    monday: str | None = None,
    tuesday: str | None = None,
    wednesday: str | None = None,
    thursday: str | None = None,
    friday: str | None = None,
    saturday: str | None = None,
    sunday: str | None = None,
    standard_values: str | None = None,
)

Dataclass for DHW time switch programs.

DaySchedule

bsblan.DaySchedule dataclass

DaySchedule(slots: list[TimeSlot] = list())

Schedule for a single day with up to 3 time slots (BSB-LAN limit).

Attributes:

Name Type Description
slots list[TimeSlot]

List of time slots for the day.

Example

schedule = DaySchedule(slots=[ ... TimeSlot(time(6, 0), time(8, 0)), ... TimeSlot(time(17, 0), time(21, 0)), ... ]) schedule.to_bsblan_format() '06:00-08:00 17:00-21:00'

__post_init__

__post_init__() -> None

Validate max 3 slots per day (BSB-LAN limitation).

Source code in src/bsblan/models.py
def __post_init__(self) -> None:
    """Validate max 3 slots per day (BSB-LAN limitation)."""
    if len(self.slots) > MAX_TIME_SLOTS_PER_DAY:
        msg = (
            f"BSB-LAN supports maximum {MAX_TIME_SLOTS_PER_DAY} time slots per day"
        )
        raise ValueError(msg)

to_bsblan_format

to_bsblan_format() -> str

Convert to BSB-LAN string format like '06:00-08:00 17:00-21:00'.

Returns:

Name Type Description
str str

Day schedule in BSB-LAN format, or empty string if no slots.

Source code in src/bsblan/models.py
def to_bsblan_format(self) -> str:
    """Convert to BSB-LAN string format like '06:00-08:00 17:00-21:00'.

    Returns:
        str: Day schedule in BSB-LAN format, or empty string if no slots.

    """
    if not self.slots:
        return ""
    return " ".join(slot.to_bsblan_format() for slot in self.slots)

from_bsblan_format classmethod

from_bsblan_format(value: str) -> DaySchedule

Parse from BSB-LAN format like '06:00-08:00 17:00-21:00'.

Parameters:

Name Type Description Default
value str

Day schedule string in BSB-LAN format.

required

Returns:

Name Type Description
DaySchedule DaySchedule

Parsed day schedule.

Source code in src/bsblan/models.py
@classmethod
def from_bsblan_format(cls, value: str) -> DaySchedule:
    """Parse from BSB-LAN format like '06:00-08:00 17:00-21:00'.

    Args:
        value: Day schedule string in BSB-LAN format.

    Returns:
        DaySchedule: Parsed day schedule.

    """
    if not value or value == "---":
        return cls(slots=[])
    slot_strings = value.split()
    slots = [TimeSlot.from_bsblan_format(s) for s in slot_strings]
    return cls(slots=slots)

TimeSlot

bsblan.TimeSlot dataclass

TimeSlot(start: time, end: time)

A single time slot with start and end time.

Attributes:

Name Type Description
start time

Start time of the slot.

end time

End time of the slot.

Example

slot = TimeSlot(time(6, 0), time(8, 0)) slot.to_bsblan_format() '06:00-08:00'

__post_init__

__post_init__() -> None

Validate that start is before end.

Source code in src/bsblan/models.py
def __post_init__(self) -> None:
    """Validate that start is before end."""
    if self.start >= self.end:
        msg = f"Start time {self.start} must be before end time {self.end}"
        raise ValueError(msg)

to_bsblan_format

to_bsblan_format() -> str

Convert to BSB-LAN format 'HH:MM-HH:MM'.

Returns:

Name Type Description
str str

Time slot in BSB-LAN format.

Source code in src/bsblan/models.py
def to_bsblan_format(self) -> str:
    """Convert to BSB-LAN format 'HH:MM-HH:MM'.

    Returns:
        str: Time slot in BSB-LAN format.

    """
    return f"{self.start.strftime('%H:%M')}-{self.end.strftime('%H:%M')}"

from_bsblan_format classmethod

from_bsblan_format(value: str) -> TimeSlot

Parse from BSB-LAN format 'HH:MM-HH:MM'.

Parameters:

Name Type Description Default
value str

Time slot string in format 'HH:MM-HH:MM'.

required

Returns:

Name Type Description
TimeSlot TimeSlot

Parsed time slot.

Raises:

Type Description
ValueError

If the format is invalid.

Source code in src/bsblan/models.py
@classmethod
def from_bsblan_format(cls, value: str) -> TimeSlot:
    """Parse from BSB-LAN format 'HH:MM-HH:MM'.

    Args:
        value: Time slot string in format 'HH:MM-HH:MM'.

    Returns:
        TimeSlot: Parsed time slot.

    Raises:
        ValueError: If the format is invalid.

    """
    try:
        start_str, end_str = value.split("-")
        start_h, start_m = map(int, start_str.split(":"))
        end_h, end_m = map(int, end_str.split(":"))
        return cls(start=time(start_h, start_m), end=time(end_h, end_m))
    except (ValueError, AttributeError) as e:
        msg = f"Invalid time slot format: {value}"
        raise ValueError(msg) from e

Device

Device

bsblan.Device

Bases: BaseModel

Object holds bsblan device information.

Info

bsblan.Info

Bases: BaseModel

Object holding the heatingSystem info.

All fields are optional to support partial fetching via the include parameter.

DeviceTime

bsblan.DeviceTime

Bases: BaseModel

Object holds device time information.