"""Models the state of a vehicle."""
import logging
from dataclasses import dataclass, field
from typing import Any, Dict, List
from bimmer_connected.const import ATTR_STATE
from bimmer_connected.models import StrEnum, VehicleDataBase
from bimmer_connected.utils import to_camel_case
_LOGGER = logging.getLogger(__name__)
[docs]class LidState(StrEnum):
"""Possible states of the hatch, trunk, doors, windows, sun roof."""
CLOSED = "CLOSED"
OPEN = "OPEN"
OPEN_TILT = "OPEN_TILT"
INTERMEDIATE = "INTERMEDIATE"
INVALID = "INVALID"
UNKNOWN = "UNKNOWN"
[docs]class LockState(StrEnum):
"""Possible states of the door locks."""
LOCKED = "LOCKED"
SECURED = "SECURED"
SELECTIVE_LOCKED = "SELECTIVE_LOCKED"
PARTIALLY_LOCKED = "PARTIALLY_LOCKED"
UNLOCKED = "UNLOCKED"
UNKNOWN = "UNKNOWN"
[docs]class Lid:
"""A lid of the vehicle.
Lids are: Doors + Trunk + Hatch
"""
def __init__(self, name: str, state: str):
#: name of the lid
self.name = name
self.state = LidState(state)
@property
def is_closed(self) -> bool:
"""Check if the lid is closed."""
return self.state == LidState.CLOSED
[docs]class Window(Lid):
"""A window of the vehicle.
A window can be a normal window of the car or the sun roof.
"""
[docs]@dataclass
class DoorsAndWindows(VehicleDataBase):
"""Provides an accessible version of `properties.doorsAndWindows`."""
door_lock_state: LockState = LockState.UNKNOWN
"""Get state of the door locks."""
lids: List[Lid] = field(default_factory=list)
"""All lids (doors+hood+trunk) of the car."""
windows: List[Window] = field(default_factory=list)
"""All windows (doors+sunroof) of the car."""
@classmethod
def _parse_vehicle_data(cls, vehicle_data: Dict) -> Dict:
"""Parse doors and windows."""
retval: Dict[str, Any] = {}
if ATTR_STATE in vehicle_data:
if "doorsState" in vehicle_data[ATTR_STATE]:
retval["lids"] = [
Lid(k, v)
for k, v in vehicle_data[ATTR_STATE]["doorsState"].items()
if k not in ["combinedState", "combinedSecurityState"] and v != LidState.INVALID
]
retval["door_lock_state"] = LockState(
vehicle_data[ATTR_STATE]["doorsState"].get("combinedSecurityState", "UNKNOWN")
)
if "windowsState" in vehicle_data[ATTR_STATE]:
retval["windows"] = [
Window(k, v)
for k, v in vehicle_data[ATTR_STATE]["windowsState"].items()
if k not in ["combinedState"] and v != LidState.INVALID
]
if "roofState" in vehicle_data[ATTR_STATE]:
retval["lids"].append(
Lid(
to_camel_case(vehicle_data[ATTR_STATE]["roofState"]["roofStateType"]),
vehicle_data[ATTR_STATE]["roofState"]["roofState"],
)
)
return retval
@property
def open_lids(self) -> List[Lid]:
"""Get all open lids of the car."""
return [lid for lid in self.lids if not lid.is_closed]
@property
def all_lids_closed(self) -> bool:
"""Check if all lids are closed."""
return len(self.open_lids) == 0
@property
def open_windows(self) -> List[Window]:
"""Get all open windows of the car."""
return [lid for lid in self.windows if not lid.is_closed]
@property
def all_windows_closed(self) -> bool:
"""Check if all windows are closed."""
return len(self.open_windows) == 0