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

View file

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

View file

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