You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classDiagram
direction TB
class DataUpdateCoordinator {
<<Home Assistant>>
}
class BMWWallboxCoordinator {
+data: dict
+charge_point: WallboxChargePoint
}
class WallboxChargePoint {
+id: str
+coordinator: BMWWallboxCoordinator
}
class ChargePoint {
<<ocpp.v201>>
}
DataUpdateCoordinator <|-- BMWWallboxCoordinator
BMWWallboxCoordinator *-- WallboxChargePoint
ChargePoint <|-- WallboxChargePoint
class CoordinatorEntity {
<<Home Assistant>>
}
class SensorEntity
class BinarySensorEntity
class ButtonEntity
class NumberEntity
class SwitchEntity
class BMWWallboxSensorBase
class BMWWallboxStatusSensor
class BMWWallboxPowerSensor
class BMWWallboxEnergyTotalSensor
class BMWWallboxCurrentSensor
class BMWWallboxVoltageSensor
class BMWWallboxBinarySensorBase
class BMWWallboxChargingBinarySensor
class BMWWallboxConnectedBinarySensor
class BMWWallboxButtonBase
class BMWWallboxStartButton
class BMWWallboxStopButton
class BMWWallboxCurrentLimitNumber
class BMWWallboxLEDBrightnessNumber
class BMWWallboxChargingSwitch
CoordinatorEntity <|-- SensorEntity
CoordinatorEntity <|-- BinarySensorEntity
CoordinatorEntity <|-- ButtonEntity
CoordinatorEntity <|-- NumberEntity
CoordinatorEntity <|-- SwitchEntity
SensorEntity <|-- BMWWallboxSensorBase
BMWWallboxSensorBase <|-- BMWWallboxStatusSensor
BMWWallboxSensorBase <|-- BMWWallboxPowerSensor
BMWWallboxSensorBase <|-- BMWWallboxEnergyTotalSensor
BMWWallboxSensorBase <|-- BMWWallboxCurrentSensor
BMWWallboxSensorBase <|-- BMWWallboxVoltageSensor
BinarySensorEntity <|-- BMWWallboxBinarySensorBase
BMWWallboxBinarySensorBase <|-- BMWWallboxChargingBinarySensor
BMWWallboxBinarySensorBase <|-- BMWWallboxConnectedBinarySensor
ButtonEntity <|-- BMWWallboxButtonBase
BMWWallboxButtonBase <|-- BMWWallboxStartButton
BMWWallboxButtonBase <|-- BMWWallboxStopButton
NumberEntity <|-- BMWWallboxCurrentLimitNumber
NumberEntity <|-- BMWWallboxLEDBrightnessNumber
SwitchEntity <|-- BMWWallboxChargingSwitch
Loading
Data Flow
1. Incoming Data (Wallbox → Home Assistant)
sequenceDiagram
participant Wallbox
participant WCP as WallboxChargePoint<br/>on_transaction_event
participant Data as BMWWallboxCoordinator<br/>.data dict
participant Entities as All Entities<br/>(CoordinatorEntity pattern)
Wallbox->>WCP: OCPP TransactionEvent
Note over WCP: Extract meter values
WCP->>Data: Update coordinator.data
Note over Data: power: 7200.0<br/>current: 32.0<br/>voltage: 230.0<br/>charging_state: ...
Data->>Entities: async_set_updated_data()
Note over Entities: Automatically notified<br/>sensor.power.native_value<br/>→ coordinator.data["power"]
Loading
2. Outgoing Commands (Home Assistant → Wallbox)
sequenceDiagram
participant UI as HA Frontend
participant Btn as BMWWallboxStartBtn<br/>async_press()
participant Coord as BMWWallboxCoordinator<br/>async_start_charging
participant WCP as WallboxChargePoint<br/>.call()
participant Wallbox
UI->>Btn: User presses Start Charging
Btn->>Coord: Calls coordinator method
Note over Coord: Checks state<br/>chooses action
Coord->>WCP: OCPP Command
WCP->>Wallbox: SetChargingProfile(32A)
Wallbox-->>WCP: Response
Loading
Charging State Machine
stateDiagram-v2
[*] --> Idle: Initial state
Idle: No cable connected
EVConnected: Cable ready
Charging: Power > 0W
SuspendedEVSE: Paused by us<br/>Power = 0W
SuspendedEV: Paused by car<br/>(Battery full, temp limit)
Idle --> EVConnected: Cable plugged in
EVConnected --> Charging: RequestStartTransaction<br/>or Auto-start
Charging --> SuspendedEVSE: SetChargingProfile(0A)<br/>or Car pauses
SuspendedEVSE --> Charging: SetChargingProfile(32A)
Charging --> Idle: Cable unplugged
SuspendedEVSE --> Idle: Cable unplugged
EVConnected --> Idle: Cable unplugged
SuspendedEV --> Idle: Cable unplugged
Charging --> SuspendedEV: Car decides to pause
SuspendedEV --> Charging: Car resumes
Loading
OCPP Message Flow
Normal Charging Session
sequenceDiagram
participant Wallbox
participant HA as Home Assistant
Note over Wallbox,HA: Connection Established
Wallbox->>HA: WebSocket Connect
Wallbox->>HA: BootNotification
HA-->>Wallbox: BootNotificationResp
Note right of HA: stores device_info
Wallbox->>HA: StatusNotification
HA-->>Wallbox: StatusNotificationResp
Note right of HA: connector_status = Available
Wallbox->>HA: Heartbeat
HA-->>Wallbox: HeartbeatResponse
Note right of HA: connected = True
Note over Wallbox,HA: ... Heartbeat every 10s ...
Note over Wallbox: Cable plugged in
Wallbox->>HA: StatusNotification
HA-->>Wallbox: StatusNotificationResp
Note right of HA: connector_status = Occupied
Wallbox->>HA: TransactionEvent (Started)
HA-->>Wallbox: TransactionEventResp
Note right of HA: transaction_id = "abc-123"<br/>charging_state = EVConnected
Note over Wallbox: Charging starts
Wallbox->>HA: TransactionEvent (Updated)
HA-->>Wallbox: TransactionEventResp
Note right of HA: power = 7200W<br/>current = 32A<br/>energy_total = 1.5kWh
Note over Wallbox,HA: ... TransactionEvent every 60s with meter values ...
Note over HA: User presses Stop
HA->>Wallbox: SetChargingProfile (0A)
Wallbox-->>HA: SetChargingProfileResp (Accepted)
Wallbox->>HA: TransactionEvent
HA-->>Wallbox: TransactionEventResp
Note right of HA: charging_state = SuspendedEVSE<br/>power = 0W
Note over HA: User presses Start
HA->>Wallbox: SetChargingProfile (32A)
Wallbox-->>HA: SetChargingProfileResp (Accepted)
Wallbox->>HA: TransactionEvent
HA-->>Wallbox: TransactionEventResp
Note right of HA: charging_state = Charging<br/>power = 7200W
Note over Wallbox: Cable unplugged
Wallbox->>HA: TransactionEvent (Ended)
HA-->>Wallbox: TransactionEventResp
Note right of HA: stopped_reason = EVDisconnected
Wallbox->>HA: StatusNotification
HA-->>Wallbox: StatusNotificationResp
Note right of HA: connector_status = Available
Loading
Async Model
WebSocket Server
# coordinator.py - async_start_server()# 1. Create SSL contextssl_context=ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(cert_path, key_path)
# 2. Start WebSocket server (runs in background)self.server=awaitwebsockets.serve(
on_connect, # Handler for new connections"0.0.0.0", # Listen on all interfacesself.config["port"], # Default: 9000subprotocols=["ocpp2.0.1"],
ssl=ssl_context,
)
# 3. on_connect creates WallboxChargePoint and starts message loopasyncdefon_connect(websocket):
self.charge_point=WallboxChargePoint(id, websocket, self)
awaitself.charge_point.start() # Blocks, processes messages
Entity Updates
# Entities extend CoordinatorEntity which handles automatic updatesclassBMWWallboxPowerSensor(CoordinatorEntity, SensorEntity):
@propertydefnative_value(self) ->float|None:
# Called automatically when coordinator.data updatesreturnself.coordinator.data.get("power")
# In coordinator, after processing OCPP message:self.data["power"] =new_valueself.async_set_updated_data(self.data) # Triggers all entity updates