Use entity class attributes for Bmw connected drive (#53054)
* Use entity class attributes for bmw_connected_driv * forgot the icon
This commit is contained in:
parent
7fef87691a
commit
668437741a
5 changed files with 99 additions and 221 deletions
|
@ -21,7 +21,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry, discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import track_utc_time_change
|
||||
from homeassistant.util import slugify
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
@ -317,6 +317,8 @@ class BMWConnectedDriveAccount:
|
|||
class BMWConnectedDriveBaseEntity(Entity):
|
||||
"""Common base for BMW entities."""
|
||||
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, account, vehicle):
|
||||
"""Initialize sensor."""
|
||||
self._account = account
|
||||
|
@ -326,15 +328,11 @@ class BMWConnectedDriveBaseEntity(Entity):
|
|||
"vin": self._vehicle.vin,
|
||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||
}
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return info for device registry."""
|
||||
return {
|
||||
"identifiers": {(DOMAIN, self._vehicle.vin)},
|
||||
"name": f'{self._vehicle.attributes.get("brand")} {self._vehicle.name}',
|
||||
"model": self._vehicle.name,
|
||||
"manufacturer": self._vehicle.attributes.get("brand"),
|
||||
self._attr_device_info = {
|
||||
"identifiers": {(DOMAIN, vehicle.vin)},
|
||||
"name": f'{vehicle.attributes.get("brand")} {vehicle.name}',
|
||||
"model": vehicle.name,
|
||||
"manufacturer": vehicle.attributes.get("brand"),
|
||||
}
|
||||
|
||||
@property
|
||||
|
@ -342,14 +340,6 @@ class BMWConnectedDriveBaseEntity(Entity):
|
|||
"""Return the state attributes of the sensor."""
|
||||
return self._attrs
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Do not poll this class.
|
||||
|
||||
Updates are triggered from BMWConnectedDriveAccount.
|
||||
"""
|
||||
return False
|
||||
|
||||
def update_callback(self):
|
||||
"""Schedule a state update."""
|
||||
self.schedule_update_ha_state(True)
|
||||
|
|
|
@ -76,41 +76,45 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, BinarySensorEntity):
|
|||
super().__init__(account, vehicle)
|
||||
|
||||
self._attribute = attribute
|
||||
self._name = f"{self._vehicle.name} {self._attribute}"
|
||||
self._unique_id = f"{self._vehicle.vin}-{self._attribute}"
|
||||
self._attr_name = f"{vehicle.name} {attribute}"
|
||||
self._attr_unique_id = f"{vehicle.vin}-{attribute}"
|
||||
self._sensor_name = sensor_name
|
||||
self._device_class = device_class
|
||||
self._icon = icon
|
||||
self._state = None
|
||||
self._attr_device_class = device_class
|
||||
self._attr_icon = icon
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID of the binary sensor."""
|
||||
return self._unique_id
|
||||
def update(self):
|
||||
"""Read new state data from the library."""
|
||||
vehicle_state = self._vehicle.state
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the binary sensor."""
|
||||
return self._name
|
||||
# device class opening: On means open, Off means closed
|
||||
if self._attribute == "lids":
|
||||
_LOGGER.debug("Status of lid: %s", vehicle_state.all_lids_closed)
|
||||
self._attr_state = not vehicle_state.all_lids_closed
|
||||
if self._attribute == "windows":
|
||||
self._attr_state = not vehicle_state.all_windows_closed
|
||||
# device class lock: On means unlocked, Off means locked
|
||||
if self._attribute == "door_lock_state":
|
||||
# Possible values: LOCKED, SECURED, SELECTIVE_LOCKED, UNLOCKED
|
||||
self._attr_state = vehicle_state.door_lock_state not in [
|
||||
LockState.LOCKED,
|
||||
LockState.SECURED,
|
||||
]
|
||||
# device class light: On means light detected, Off means no light
|
||||
if self._attribute == "lights_parking":
|
||||
self._attr_state = vehicle_state.are_parking_lights_on
|
||||
# device class problem: On means problem detected, Off means no problem
|
||||
if self._attribute == "condition_based_services":
|
||||
self._attr_state = not vehicle_state.are_all_cbs_ok
|
||||
if self._attribute == "check_control_messages":
|
||||
self._attr_state = vehicle_state.has_check_control_messages
|
||||
# device class power: On means power detected, Off means no power
|
||||
if self._attribute == "charging_status":
|
||||
self._attr_state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
||||
# device class plug: On means device is plugged in,
|
||||
# Off means device is unplugged
|
||||
if self._attribute == "connection_status":
|
||||
self._attr_state = vehicle_state.connection_status == "CONNECTED"
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend, if any."""
|
||||
return self._icon
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of the binary sensor."""
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return the state of the binary sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes of the binary sensor."""
|
||||
vehicle_state = self._vehicle.state
|
||||
result = self._attrs.copy()
|
||||
|
||||
|
@ -144,40 +148,7 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, BinarySensorEntity):
|
|||
elif self._attribute == "connection_status":
|
||||
result["connection_status"] = vehicle_state.connection_status
|
||||
|
||||
return sorted(result.items())
|
||||
|
||||
def update(self):
|
||||
"""Read new state data from the library."""
|
||||
vehicle_state = self._vehicle.state
|
||||
|
||||
# device class opening: On means open, Off means closed
|
||||
if self._attribute == "lids":
|
||||
_LOGGER.debug("Status of lid: %s", vehicle_state.all_lids_closed)
|
||||
self._state = not vehicle_state.all_lids_closed
|
||||
if self._attribute == "windows":
|
||||
self._state = not vehicle_state.all_windows_closed
|
||||
# device class lock: On means unlocked, Off means locked
|
||||
if self._attribute == "door_lock_state":
|
||||
# Possible values: LOCKED, SECURED, SELECTIVE_LOCKED, UNLOCKED
|
||||
self._state = vehicle_state.door_lock_state not in [
|
||||
LockState.LOCKED,
|
||||
LockState.SECURED,
|
||||
]
|
||||
# device class light: On means light detected, Off means no light
|
||||
if self._attribute == "lights_parking":
|
||||
self._state = vehicle_state.are_parking_lights_on
|
||||
# device class problem: On means problem detected, Off means no problem
|
||||
if self._attribute == "condition_based_services":
|
||||
self._state = not vehicle_state.are_all_cbs_ok
|
||||
if self._attribute == "check_control_messages":
|
||||
self._state = vehicle_state.has_check_control_messages
|
||||
# device class power: On means power detected, Off means no power
|
||||
if self._attribute == "charging_status":
|
||||
self._state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
||||
# device class plug: On means device is plugged in,
|
||||
# Off means device is unplugged
|
||||
if self._attribute == "connection_status":
|
||||
self._state = vehicle_state.connection_status == "CONNECTED"
|
||||
self._attr_extra_state_attributes = sorted(result.items())
|
||||
|
||||
def _format_cbs_report(self, report):
|
||||
result = {}
|
||||
|
|
|
@ -29,15 +29,18 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class BMWDeviceTracker(BMWConnectedDriveBaseEntity, TrackerEntity):
|
||||
"""BMW Connected Drive device tracker."""
|
||||
|
||||
_attr_force_update = False
|
||||
_attr_icon = "mdi:car"
|
||||
|
||||
def __init__(self, account, vehicle):
|
||||
"""Initialize the Tracker."""
|
||||
super().__init__(account, vehicle)
|
||||
|
||||
self._unique_id = vehicle.vin
|
||||
self._attr_unique_id = vehicle.vin
|
||||
self._location = (
|
||||
vehicle.state.gps_position if vehicle.state.gps_position else (None, None)
|
||||
)
|
||||
self._name = vehicle.name
|
||||
self._attr_name = vehicle.name
|
||||
|
||||
@property
|
||||
def latitude(self):
|
||||
|
@ -49,31 +52,11 @@ class BMWDeviceTracker(BMWConnectedDriveBaseEntity, TrackerEntity):
|
|||
"""Return longitude value of the device."""
|
||||
return self._location[1] if self._location else None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def source_type(self):
|
||||
"""Return the source type, eg gps or router, of the device."""
|
||||
return SOURCE_TYPE_GPS
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:car"
|
||||
|
||||
@property
|
||||
def force_update(self):
|
||||
"""All updates do not need to be written to the state machine."""
|
||||
return False
|
||||
|
||||
def update(self):
|
||||
"""Update state of the decvice tracker."""
|
||||
self._location = (
|
||||
|
|
|
@ -4,7 +4,6 @@ import logging
|
|||
from bimmer_connected.state import LockState
|
||||
|
||||
from homeassistant.components.lock import LockEntity
|
||||
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
|
||||
|
||||
from . import DOMAIN as BMW_DOMAIN, BMWConnectedDriveBaseEntity
|
||||
from .const import CONF_ACCOUNT, DATA_ENTRIES
|
||||
|
@ -33,50 +32,17 @@ class BMWLock(BMWConnectedDriveBaseEntity, LockEntity):
|
|||
super().__init__(account, vehicle)
|
||||
|
||||
self._attribute = attribute
|
||||
self._name = f"{self._vehicle.name} {self._attribute}"
|
||||
self._unique_id = f"{self._vehicle.vin}-{self._attribute}"
|
||||
self._attr_name = f"{vehicle.name} {attribute}"
|
||||
self._attr_unique_id = f"{vehicle.vin}-{attribute}"
|
||||
self._sensor_name = sensor_name
|
||||
self._state = None
|
||||
self.door_lock_state_available = (
|
||||
DOOR_LOCK_STATE in self._vehicle.available_attributes
|
||||
)
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID of the lock."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the lock."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes of the lock."""
|
||||
vehicle_state = self._vehicle.state
|
||||
result = self._attrs.copy()
|
||||
|
||||
if self.door_lock_state_available:
|
||||
result["door_lock_state"] = vehicle_state.door_lock_state.value
|
||||
result["last_update_reason"] = vehicle_state.last_update_reason
|
||||
return result
|
||||
|
||||
@property
|
||||
def is_locked(self):
|
||||
"""Return true if lock is locked."""
|
||||
if self.door_lock_state_available:
|
||||
result = self._state == STATE_LOCKED
|
||||
else:
|
||||
result = None
|
||||
return result
|
||||
self.door_lock_state_available = DOOR_LOCK_STATE in vehicle.available_attributes
|
||||
|
||||
def lock(self, **kwargs):
|
||||
"""Lock the car."""
|
||||
_LOGGER.debug("%s: locking doors", self._vehicle.name)
|
||||
# Optimistic state set here because it takes some time before the
|
||||
# update callback response
|
||||
self._state = STATE_LOCKED
|
||||
self._attr_is_locked = True
|
||||
self.schedule_update_ha_state()
|
||||
self._vehicle.remote_services.trigger_remote_door_lock()
|
||||
|
||||
|
@ -85,18 +51,23 @@ class BMWLock(BMWConnectedDriveBaseEntity, LockEntity):
|
|||
_LOGGER.debug("%s: unlocking doors", self._vehicle.name)
|
||||
# Optimistic state set here because it takes some time before the
|
||||
# update callback response
|
||||
self._state = STATE_UNLOCKED
|
||||
self._attr_is_locked = False
|
||||
self.schedule_update_ha_state()
|
||||
self._vehicle.remote_services.trigger_remote_door_unlock()
|
||||
|
||||
def update(self):
|
||||
"""Update state of the lock."""
|
||||
_LOGGER.debug("%s: updating data for %s", self._vehicle.name, self._attribute)
|
||||
vehicle_state = self._vehicle.state
|
||||
if self._vehicle.state.door_lock_state in [LockState.LOCKED, LockState.SECURED]:
|
||||
self._attr_is_locked = True
|
||||
else:
|
||||
self._attr_is_locked = False
|
||||
if not self.door_lock_state_available:
|
||||
self._attr_is_locked = None
|
||||
|
||||
# Possible values: LOCKED, SECURED, SELECTIVE_LOCKED, UNLOCKED
|
||||
self._state = (
|
||||
STATE_LOCKED
|
||||
if vehicle_state.door_lock_state in [LockState.LOCKED, LockState.SECURED]
|
||||
else STATE_UNLOCKED
|
||||
)
|
||||
vehicle_state = self._vehicle.state
|
||||
result = self._attrs.copy()
|
||||
if self.door_lock_state_available:
|
||||
result["door_lock_state"] = vehicle_state.door_lock_state.value
|
||||
result["last_update_reason"] = vehicle_state.last_update_reason
|
||||
self._attr_extra_state_attributes = result
|
||||
|
|
|
@ -503,94 +503,46 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
|||
|
||||
self._attribute = attribute
|
||||
self._service = service
|
||||
self._state = None
|
||||
if self._service:
|
||||
self._name = (
|
||||
f"{self._vehicle.name} {self._service.lower()}_{self._attribute}"
|
||||
)
|
||||
self._unique_id = (
|
||||
f"{self._vehicle.vin}-{self._service.lower()}-{self._attribute}"
|
||||
)
|
||||
if service:
|
||||
self._attr_name = f"{vehicle.name} {service.lower()}_{attribute}"
|
||||
self._attr_unique_id = f"{vehicle.vin}-{service.lower()}-{attribute}"
|
||||
else:
|
||||
self._name = f"{self._vehicle.name} {self._attribute}"
|
||||
self._unique_id = f"{self._vehicle.vin}-{self._attribute}"
|
||||
self._attr_name = f"{vehicle.name} {attribute}"
|
||||
self._attr_unique_id = f"{vehicle.vin}-{attribute}"
|
||||
self._attribute_info = attribute_info
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID of the sensor."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend, if any."""
|
||||
vehicle_state = self._vehicle.state
|
||||
charging_state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
||||
|
||||
if self._attribute == "charging_level_hv":
|
||||
return icon_for_battery_level(
|
||||
battery_level=vehicle_state.charging_level_hv, charging=charging_state
|
||||
)
|
||||
icon = self._attribute_info.get(self._attribute, [None, None, None, None])[0]
|
||||
return icon
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
enabled_default = self._attribute_info.get(
|
||||
self._attribute, [None, None, None, True]
|
||||
self._attr_entity_registry_enabled_default = attribute_info.get(
|
||||
attribute, [None, None, None, True]
|
||||
)[3]
|
||||
return enabled_default
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor.
|
||||
|
||||
The return type of this call depends on the attribute that
|
||||
is configured.
|
||||
"""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Get the device class."""
|
||||
clss = self._attribute_info.get(self._attribute, [None, None, None, None])[1]
|
||||
return clss
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Get the unit of measurement."""
|
||||
unit = self._attribute_info.get(self._attribute, [None, None, None, None])[2]
|
||||
return unit
|
||||
self._attr_device_class = attribute_info.get(
|
||||
attribute, [None, None, None, None]
|
||||
)[1]
|
||||
self._attr_unit_of_measurement = attribute_info.get(
|
||||
attribute, [None, None, None, None]
|
||||
)[2]
|
||||
|
||||
def update(self) -> None:
|
||||
"""Read new state data from the library."""
|
||||
_LOGGER.debug("Updating %s", self._vehicle.name)
|
||||
vehicle_state = self._vehicle.state
|
||||
if self._attribute == "charging_status":
|
||||
self._state = getattr(vehicle_state, self._attribute).value
|
||||
self._attr_state = getattr(vehicle_state, self._attribute).value
|
||||
elif self.unit_of_measurement == VOLUME_GALLONS:
|
||||
value = getattr(vehicle_state, self._attribute)
|
||||
value_converted = self.hass.config.units.volume(value, VOLUME_LITERS)
|
||||
self._state = round(value_converted)
|
||||
self._attr_state = round(value_converted)
|
||||
elif self.unit_of_measurement == LENGTH_MILES:
|
||||
value = getattr(vehicle_state, self._attribute)
|
||||
value_converted = self.hass.config.units.length(value, LENGTH_KILOMETERS)
|
||||
self._state = round(value_converted)
|
||||
self._attr_state = round(value_converted)
|
||||
elif self._service is None:
|
||||
self._state = getattr(vehicle_state, self._attribute)
|
||||
self._attr_state = getattr(vehicle_state, self._attribute)
|
||||
elif self._service == SERVICE_LAST_TRIP:
|
||||
vehicle_last_trip = self._vehicle.state.last_trip
|
||||
if self._attribute == "date_utc":
|
||||
date_str = getattr(vehicle_last_trip, "date")
|
||||
self._state = dt_util.parse_datetime(date_str).isoformat()
|
||||
self._attr_state = dt_util.parse_datetime(date_str).isoformat()
|
||||
else:
|
||||
self._state = getattr(vehicle_last_trip, self._attribute)
|
||||
self._attr_state = getattr(vehicle_last_trip, self._attribute)
|
||||
elif self._service == SERVICE_ALL_TRIPS:
|
||||
vehicle_all_trips = self._vehicle.state.all_trips
|
||||
for attribute in (
|
||||
|
@ -603,10 +555,21 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
|||
if self._attribute.startswith(f"{attribute}_"):
|
||||
attr = getattr(vehicle_all_trips, attribute)
|
||||
sub_attr = self._attribute.replace(f"{attribute}_", "")
|
||||
self._state = getattr(attr, sub_attr)
|
||||
self._attr_state = getattr(attr, sub_attr)
|
||||
return
|
||||
if self._attribute == "reset_date_utc":
|
||||
date_str = getattr(vehicle_all_trips, "reset_date")
|
||||
self._state = dt_util.parse_datetime(date_str).isoformat()
|
||||
self._attr_state = dt_util.parse_datetime(date_str).isoformat()
|
||||
else:
|
||||
self._state = getattr(vehicle_all_trips, self._attribute)
|
||||
self._attr_state = getattr(vehicle_all_trips, self._attribute)
|
||||
|
||||
vehicle_state = self._vehicle.state
|
||||
charging_state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
||||
|
||||
if self._attribute == "charging_level_hv":
|
||||
self._attr_icon = icon_for_battery_level(
|
||||
battery_level=vehicle_state.charging_level_hv, charging=charging_state
|
||||
)
|
||||
self._attr_icon = self._attribute_info.get(
|
||||
self._attribute, [None, None, None, None]
|
||||
)[0]
|
||||
|
|
Loading…
Add table
Reference in a new issue