Use EntityDescription - starline (#54431)

This commit is contained in:
Marc Mueller 2021-08-21 20:47:29 +02:00 committed by GitHub
parent 05de7a78d1
commit f9ebb29541
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 206 additions and 83 deletions

View file

@ -1,57 +1,92 @@
"""Reads vehicle status from StarLine API.""" """Reads vehicle status from StarLine API."""
from __future__ import annotations
from dataclasses import dataclass
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASS_DOOR, DEVICE_CLASS_DOOR,
DEVICE_CLASS_LOCK, DEVICE_CLASS_LOCK,
DEVICE_CLASS_POWER, DEVICE_CLASS_POWER,
DEVICE_CLASS_PROBLEM, DEVICE_CLASS_PROBLEM,
BinarySensorEntity, BinarySensorEntity,
BinarySensorEntityDescription,
) )
from .account import StarlineAccount, StarlineDevice from .account import StarlineAccount, StarlineDevice
from .const import DOMAIN from .const import DOMAIN
from .entity import StarlineEntity from .entity import StarlineEntity
SENSOR_TYPES = {
"hbrake": ["Hand Brake", DEVICE_CLASS_POWER], @dataclass
"hood": ["Hood", DEVICE_CLASS_DOOR], class StarlineRequiredKeysMixin:
"trunk": ["Trunk", DEVICE_CLASS_DOOR], """Mixin for required keys."""
"alarm": ["Alarm", DEVICE_CLASS_PROBLEM],
"door": ["Doors", DEVICE_CLASS_LOCK], name_: str
}
@dataclass
class StarlineBinarySensorEntityDescription(
BinarySensorEntityDescription, StarlineRequiredKeysMixin
):
"""Describes Starline binary_sensor entity."""
BINARY_SENSOR_TYPES: tuple[StarlineBinarySensorEntityDescription, ...] = (
StarlineBinarySensorEntityDescription(
key="hbrake",
name_="Hand Brake",
device_class=DEVICE_CLASS_POWER,
),
StarlineBinarySensorEntityDescription(
key="hood",
name_="Hood",
device_class=DEVICE_CLASS_DOOR,
),
StarlineBinarySensorEntityDescription(
key="trunk",
name_="Trunk",
device_class=DEVICE_CLASS_DOOR,
),
StarlineBinarySensorEntityDescription(
key="alarm",
name_="Alarm",
device_class=DEVICE_CLASS_PROBLEM,
),
StarlineBinarySensorEntityDescription(
key="door",
name_="Doors",
device_class=DEVICE_CLASS_LOCK,
),
)
async def async_setup_entry(hass, entry, async_add_entities): async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the StarLine sensors.""" """Set up the StarLine sensors."""
account: StarlineAccount = hass.data[DOMAIN][entry.entry_id] account: StarlineAccount = hass.data[DOMAIN][entry.entry_id]
entities = [] entities = [
for device in account.api.devices.values(): sensor
for key, value in SENSOR_TYPES.items(): for device in account.api.devices.values()
if key in device.car_state: for description in BINARY_SENSOR_TYPES
sensor = StarlineSensor(account, device, key, *value) if description.key in device.car_state
if sensor.is_on is not None: if (sensor := StarlineSensor(account, device, description)).is_on is not None
entities.append(sensor) ]
async_add_entities(entities) async_add_entities(entities)
class StarlineSensor(StarlineEntity, BinarySensorEntity): class StarlineSensor(StarlineEntity, BinarySensorEntity):
"""Representation of a StarLine binary sensor.""" """Representation of a StarLine binary sensor."""
entity_description: StarlineBinarySensorEntityDescription
def __init__( def __init__(
self, self,
account: StarlineAccount, account: StarlineAccount,
device: StarlineDevice, device: StarlineDevice,
key: str, description: StarlineBinarySensorEntityDescription,
name: str,
device_class: str,
) -> None: ) -> None:
"""Initialize sensor.""" """Initialize sensor."""
super().__init__(account, device, key, name) super().__init__(account, device, description.key, description.name_)
self._device_class = device_class self.entity_description = description
@property
def device_class(self):
"""Return the class of the binary sensor."""
return self._device_class
@property @property
def is_on(self): def is_on(self):

View file

@ -1,5 +1,13 @@
"""Reads vehicle status from StarLine API.""" """Reads vehicle status from StarLine API."""
from homeassistant.components.sensor import DEVICE_CLASS_TEMPERATURE, SensorEntity from __future__ import annotations
from dataclasses import dataclass
from homeassistant.components.sensor import (
DEVICE_CLASS_TEMPERATURE,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import ( from homeassistant.const import (
ELECTRIC_POTENTIAL_VOLT, ELECTRIC_POTENTIAL_VOLT,
LENGTH_KILOMETERS, LENGTH_KILOMETERS,
@ -13,48 +21,94 @@ from .account import StarlineAccount, StarlineDevice
from .const import DOMAIN from .const import DOMAIN
from .entity import StarlineEntity from .entity import StarlineEntity
SENSOR_TYPES = {
"battery": ["Battery", None, ELECTRIC_POTENTIAL_VOLT, None], @dataclass
"balance": ["Balance", None, None, "mdi:cash-multiple"], class StarlineRequiredKeysMixin:
"ctemp": ["Interior Temperature", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None], """Mixin for required keys."""
"etemp": ["Engine Temperature", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None],
"gsm_lvl": ["GSM Signal", None, PERCENTAGE, None], name_: str
"fuel": ["Fuel Volume", None, None, "mdi:fuel"],
"errors": ["OBD Errors", None, None, "mdi:alert-octagon"],
"mileage": ["Mileage", None, LENGTH_KILOMETERS, "mdi:counter"], @dataclass
} class StarlineSensorEntityDescription(
SensorEntityDescription, StarlineRequiredKeysMixin
):
"""Describes Starline binary_sensor entity."""
SENSOR_TYPES: tuple[StarlineSensorEntityDescription, ...] = (
StarlineSensorEntityDescription(
key="battery",
name_="Battery",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
),
StarlineSensorEntityDescription(
key="balance",
name_="Balance",
icon="mdi:cash-multiple",
),
StarlineSensorEntityDescription(
key="ctemp",
name_="Interior Temperature",
device_class=DEVICE_CLASS_TEMPERATURE,
native_unit_of_measurement=TEMP_CELSIUS,
),
StarlineSensorEntityDescription(
key="etemp",
name_="Engine Temperature",
device_class=DEVICE_CLASS_TEMPERATURE,
native_unit_of_measurement=TEMP_CELSIUS,
),
StarlineSensorEntityDescription(
key="gsm_lvl",
name_="GSM Signal",
native_unit_of_measurement=PERCENTAGE,
),
StarlineSensorEntityDescription(
key="fuel",
name_="Fuel Volume",
icon="mdi:fuel",
),
StarlineSensorEntityDescription(
key="errors",
name_="OBD Errors",
icon="mdi:alert-octagon",
),
StarlineSensorEntityDescription(
key="mileage",
name_="Mileage",
native_unit_of_measurement=LENGTH_KILOMETERS,
icon="mdi:counter",
),
)
async def async_setup_entry(hass, entry, async_add_entities): async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the StarLine sensors.""" """Set up the StarLine sensors."""
account: StarlineAccount = hass.data[DOMAIN][entry.entry_id] account: StarlineAccount = hass.data[DOMAIN][entry.entry_id]
entities = [] entities = [
for device in account.api.devices.values(): sensor
for key, value in SENSOR_TYPES.items(): for device in account.api.devices.values()
sensor = StarlineSensor(account, device, key, *value) for description in SENSOR_TYPES
if sensor.state is not None: if (sensor := StarlineSensor(account, device, description)).state is not None
entities.append(sensor) ]
async_add_entities(entities) async_add_entities(entities)
class StarlineSensor(StarlineEntity, SensorEntity): class StarlineSensor(StarlineEntity, SensorEntity):
"""Representation of a StarLine sensor.""" """Representation of a StarLine sensor."""
entity_description: StarlineSensorEntityDescription
def __init__( def __init__(
self, self,
account: StarlineAccount, account: StarlineAccount,
device: StarlineDevice, device: StarlineDevice,
key: str, description: StarlineSensorEntityDescription,
name: str,
device_class: str,
unit: str,
icon: str,
) -> None: ) -> None:
"""Initialize StarLine sensor.""" """Initialize StarLine sensor."""
super().__init__(account, device, key, name) super().__init__(account, device, description.key, description.name_)
self._device_class = device_class self.entity_description = description
self._unit = unit
self._icon = icon
@property @property
def icon(self): def icon(self):
@ -66,7 +120,7 @@ class StarlineSensor(StarlineEntity, SensorEntity):
) )
if self._key == "gsm_lvl": if self._key == "gsm_lvl":
return icon_for_signal_level(signal_level=self._device.gsm_level_percent) return icon_for_signal_level(signal_level=self._device.gsm_level_percent)
return self._icon return self.entity_description.icon
@property @property
def native_value(self): def native_value(self):
@ -100,12 +154,7 @@ class StarlineSensor(StarlineEntity, SensorEntity):
return PERCENTAGE return PERCENTAGE
if type_value == "litres": if type_value == "litres":
return VOLUME_LITERS return VOLUME_LITERS
return self._unit return self.entity_description.native_unit_of_measurement
@property
def device_class(self):
"""Return the class of the sensor."""
return self._device_class
@property @property
def extra_state_attributes(self): def extra_state_attributes(self):

View file

@ -1,51 +1,86 @@
"""Support for StarLine switch.""" """Support for StarLine switch."""
from homeassistant.components.switch import SwitchEntity from __future__ import annotations
from dataclasses import dataclass
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from .account import StarlineAccount, StarlineDevice from .account import StarlineAccount, StarlineDevice
from .const import DOMAIN from .const import DOMAIN
from .entity import StarlineEntity from .entity import StarlineEntity
SWITCH_TYPES = {
"ign": ["Engine", "mdi:engine-outline", "mdi:engine-off-outline"], @dataclass
"webasto": ["Webasto", "mdi:radiator", "mdi:radiator-off"], class StarlineRequiredKeysMixin:
"out": [ """Mixin for required keys."""
"Additional Channel",
"mdi:access-point-network", name_: str
"mdi:access-point-network-off", icon_on: str
], icon_off: str
"poke": ["Horn", "mdi:bullhorn-outline", "mdi:bullhorn-outline"],
}
@dataclass
class StarlineSwitchEntityDescription(
SwitchEntityDescription, StarlineRequiredKeysMixin
):
"""Describes Starline switch entity."""
SWITCH_TYPES: tuple[StarlineSwitchEntityDescription, ...] = (
StarlineSwitchEntityDescription(
key="ign",
name_="Engine",
icon_on="mdi:engine-outline",
icon_off="mdi:engine-off-outline",
),
StarlineSwitchEntityDescription(
key="webasto",
name_="Webasto",
icon_on="mdi:radiator",
icon_off="mdi:radiator-off",
),
StarlineSwitchEntityDescription(
key="out",
name_="Additional Channel",
icon_on="mdi:access-point-network",
icon_off="mdi:access-point-network-off",
),
StarlineSwitchEntityDescription(
key="poke",
name_="Horn",
icon_on="mdi:bullhorn-outline",
icon_off="mdi:bullhorn-outline",
),
)
async def async_setup_entry(hass, entry, async_add_entities): async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the StarLine switch.""" """Set up the StarLine switch."""
account: StarlineAccount = hass.data[DOMAIN][entry.entry_id] account: StarlineAccount = hass.data[DOMAIN][entry.entry_id]
entities = [] entities = [
for device in account.api.devices.values(): switch
if device.support_state: for device in account.api.devices.values()
for key, value in SWITCH_TYPES.items(): if device.support_state
switch = StarlineSwitch(account, device, key, *value) for description in SWITCH_TYPES
if switch.is_on is not None: if (switch := StarlineSwitch(account, device, description)).is_on is not None
entities.append(switch) ]
async_add_entities(entities) async_add_entities(entities)
class StarlineSwitch(StarlineEntity, SwitchEntity): class StarlineSwitch(StarlineEntity, SwitchEntity):
"""Representation of a StarLine switch.""" """Representation of a StarLine switch."""
entity_description: StarlineSwitchEntityDescription
def __init__( def __init__(
self, self,
account: StarlineAccount, account: StarlineAccount,
device: StarlineDevice, device: StarlineDevice,
key: str, description: StarlineSwitchEntityDescription,
name: str,
icon_on: str,
icon_off: str,
) -> None: ) -> None:
"""Initialize the switch.""" """Initialize the switch."""
super().__init__(account, device, key, name) super().__init__(account, device, description.key, description.name_)
self._icon_on = icon_on self.entity_description = description
self._icon_off = icon_off
@property @property
def available(self): def available(self):
@ -62,7 +97,11 @@ class StarlineSwitch(StarlineEntity, SwitchEntity):
@property @property
def icon(self): def icon(self):
"""Icon to use in the frontend, if any.""" """Icon to use in the frontend, if any."""
return self._icon_on if self.is_on else self._icon_off return (
self.entity_description.icon_on
if self.is_on
else self.entity_description.icon_off
)
@property @property
def assumed_state(self): def assumed_state(self):