Homeconnect remote states (#45610)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
badguy99 2021-02-03 16:05:20 +00:00 committed by GitHub
parent 0875f654c8
commit 6458ff774f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 157 additions and 37 deletions

View File

@ -13,6 +13,7 @@ from homeassistant.helpers.dispatcher import dispatcher_send
from .const import ( from .const import (
BSH_ACTIVE_PROGRAM, BSH_ACTIVE_PROGRAM,
BSH_OPERATION_STATE,
BSH_POWER_OFF, BSH_POWER_OFF,
BSH_POWER_STANDBY, BSH_POWER_STANDBY,
SIGNAL_UPDATE_ENTITIES, SIGNAL_UPDATE_ENTITIES,
@ -156,6 +157,25 @@ class DeviceWithPrograms(HomeConnectDevice):
] ]
class DeviceWithOpState(HomeConnectDevice):
"""Device that has an operation state sensor."""
def get_opstate_sensor(self):
"""Get a list with info about operation state sensors."""
return [
{
"device": self,
"desc": "Operation State",
"unit": None,
"key": BSH_OPERATION_STATE,
"icon": "mdi:state-machine",
"device_class": None,
"sign": 1,
}
]
class DeviceWithDoor(HomeConnectDevice): class DeviceWithDoor(HomeConnectDevice):
"""Device that has a door sensor.""" """Device that has a door sensor."""
@ -164,6 +184,7 @@ class DeviceWithDoor(HomeConnectDevice):
return { return {
"device": self, "device": self,
"desc": "Door", "desc": "Door",
"sensor_type": "door",
"device_class": "door", "device_class": "door",
} }
@ -173,11 +194,7 @@ class DeviceWithLight(HomeConnectDevice):
def get_light_entity(self): def get_light_entity(self):
"""Get a dictionary with info about the lighting.""" """Get a dictionary with info about the lighting."""
return { return {"device": self, "desc": "Light", "ambient": None}
"device": self,
"desc": "Light",
"ambient": None,
}
class DeviceWithAmbientLight(HomeConnectDevice): class DeviceWithAmbientLight(HomeConnectDevice):
@ -185,14 +202,36 @@ class DeviceWithAmbientLight(HomeConnectDevice):
def get_ambientlight_entity(self): def get_ambientlight_entity(self):
"""Get a dictionary with info about the ambient lighting.""" """Get a dictionary with info about the ambient lighting."""
return {"device": self, "desc": "AmbientLight", "ambient": True}
class DeviceWithRemoteControl(HomeConnectDevice):
"""Device that has Remote Control binary sensor."""
def get_remote_control(self):
"""Get a dictionary with info about the remote control sensor."""
return { return {
"device": self, "device": self,
"desc": "AmbientLight", "desc": "Remote Control",
"ambient": True, "sensor_type": "remote_control",
} }
class Dryer(DeviceWithDoor, DeviceWithPrograms): class DeviceWithRemoteStart(HomeConnectDevice):
"""Device that has a Remote Start binary sensor."""
def get_remote_start(self):
"""Get a dictionary with info about the remote start sensor."""
return {"device": self, "desc": "Remote Start", "sensor_type": "remote_start"}
class Dryer(
DeviceWithDoor,
DeviceWithOpState,
DeviceWithPrograms,
DeviceWithRemoteControl,
DeviceWithRemoteStart,
):
"""Dryer class.""" """Dryer class."""
PROGRAMS = [ PROGRAMS = [
@ -217,16 +256,26 @@ class Dryer(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
door_entity = self.get_door_entity() door_entity = self.get_door_entity()
remote_control = self.get_remote_control()
remote_start = self.get_remote_start()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return { return {
"binary_sensor": [door_entity], "binary_sensor": [door_entity, remote_control, remote_start],
"switch": program_switches, "switch": program_switches,
"sensor": program_sensors, "sensor": program_sensors + op_state_sensor,
} }
class Dishwasher(DeviceWithDoor, DeviceWithAmbientLight, DeviceWithPrograms): class Dishwasher(
DeviceWithDoor,
DeviceWithAmbientLight,
DeviceWithOpState,
DeviceWithPrograms,
DeviceWithRemoteControl,
DeviceWithRemoteStart,
):
"""Dishwasher class.""" """Dishwasher class."""
PROGRAMS = [ PROGRAMS = [
@ -257,16 +306,25 @@ class Dishwasher(DeviceWithDoor, DeviceWithAmbientLight, DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
door_entity = self.get_door_entity() door_entity = self.get_door_entity()
remote_control = self.get_remote_control()
remote_start = self.get_remote_start()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return { return {
"binary_sensor": [door_entity], "binary_sensor": [door_entity, remote_control, remote_start],
"switch": program_switches, "switch": program_switches,
"sensor": program_sensors, "sensor": program_sensors + op_state_sensor,
} }
class Oven(DeviceWithDoor, DeviceWithPrograms): class Oven(
DeviceWithDoor,
DeviceWithOpState,
DeviceWithPrograms,
DeviceWithRemoteControl,
DeviceWithRemoteStart,
):
"""Oven class.""" """Oven class."""
PROGRAMS = [ PROGRAMS = [
@ -282,16 +340,25 @@ class Oven(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
door_entity = self.get_door_entity() door_entity = self.get_door_entity()
remote_control = self.get_remote_control()
remote_start = self.get_remote_start()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return { return {
"binary_sensor": [door_entity], "binary_sensor": [door_entity, remote_control, remote_start],
"switch": program_switches, "switch": program_switches,
"sensor": program_sensors, "sensor": program_sensors + op_state_sensor,
} }
class Washer(DeviceWithDoor, DeviceWithPrograms): class Washer(
DeviceWithDoor,
DeviceWithOpState,
DeviceWithPrograms,
DeviceWithRemoteControl,
DeviceWithRemoteStart,
):
"""Washer class.""" """Washer class."""
PROGRAMS = [ PROGRAMS = [
@ -321,16 +388,19 @@ class Washer(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
door_entity = self.get_door_entity() door_entity = self.get_door_entity()
remote_control = self.get_remote_control()
remote_start = self.get_remote_start()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return { return {
"binary_sensor": [door_entity], "binary_sensor": [door_entity, remote_control, remote_start],
"switch": program_switches, "switch": program_switches,
"sensor": program_sensors, "sensor": program_sensors + op_state_sensor,
} }
class CoffeeMaker(DeviceWithPrograms): class CoffeeMaker(DeviceWithOpState, DeviceWithPrograms, DeviceWithRemoteStart):
"""Coffee maker class.""" """Coffee maker class."""
PROGRAMS = [ PROGRAMS = [
@ -354,12 +424,25 @@ class CoffeeMaker(DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
remote_start = self.get_remote_start()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return {"switch": program_switches, "sensor": program_sensors} return {
"binary_sensor": [remote_start],
"switch": program_switches,
"sensor": program_sensors + op_state_sensor,
}
class Hood(DeviceWithLight, DeviceWithAmbientLight, DeviceWithPrograms): class Hood(
DeviceWithLight,
DeviceWithAmbientLight,
DeviceWithOpState,
DeviceWithPrograms,
DeviceWithRemoteControl,
DeviceWithRemoteStart,
):
"""Hood class.""" """Hood class."""
PROGRAMS = [ PROGRAMS = [
@ -370,13 +453,17 @@ class Hood(DeviceWithLight, DeviceWithAmbientLight, DeviceWithPrograms):
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
remote_control = self.get_remote_control()
remote_start = self.get_remote_start()
light_entity = self.get_light_entity() light_entity = self.get_light_entity()
ambientlight_entity = self.get_ambientlight_entity() ambientlight_entity = self.get_ambientlight_entity()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return { return {
"binary_sensor": [remote_control, remote_start],
"switch": program_switches, "switch": program_switches,
"sensor": program_sensors, "sensor": program_sensors + op_state_sensor,
"light": [light_entity, ambientlight_entity], "light": [light_entity, ambientlight_entity],
} }
@ -390,13 +477,19 @@ class FridgeFreezer(DeviceWithDoor):
return {"binary_sensor": [door_entity]} return {"binary_sensor": [door_entity]}
class Hob(DeviceWithPrograms): class Hob(DeviceWithOpState, DeviceWithPrograms, DeviceWithRemoteControl):
"""Hob class.""" """Hob class."""
PROGRAMS = [{"name": "Cooking.Hob.Program.PowerLevelMode"}] PROGRAMS = [{"name": "Cooking.Hob.Program.PowerLevelMode"}]
def get_entity_info(self): def get_entity_info(self):
"""Get a dictionary with infos about the associated entities.""" """Get a dictionary with infos about the associated entities."""
remote_control = self.get_remote_control()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors() program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches() program_switches = self.get_program_switches()
return {"switch": program_switches, "sensor": program_sensors} return {
"binary_sensor": [remote_control],
"switch": program_switches,
"sensor": program_sensors + op_state_sensor,
}

View File

@ -3,7 +3,12 @@ import logging
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from .const import BSH_DOOR_STATE, DOMAIN from .const import (
BSH_DOOR_STATE,
BSH_REMOTE_CONTROL_ACTIVATION_STATE,
BSH_REMOTE_START_ALLOWANCE_STATE,
DOMAIN,
)
from .entity import HomeConnectEntity from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -26,11 +31,27 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity): class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity):
"""Binary sensor for Home Connect.""" """Binary sensor for Home Connect."""
def __init__(self, device, desc, device_class): def __init__(self, device, desc, sensor_type, device_class=None):
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(device, desc) super().__init__(device, desc)
self._device_class = device_class
self._state = None self._state = None
self._device_class = device_class
self._type = sensor_type
if self._type == "door":
self._update_key = BSH_DOOR_STATE
self._false_value_list = (
"BSH.Common.EnumType.DoorState.Closed",
"BSH.Common.EnumType.DoorState.Locked",
)
self._true_value_list = ["BSH.Common.EnumType.DoorState.Open"]
elif self._type == "remote_control":
self._update_key = BSH_REMOTE_CONTROL_ACTIVATION_STATE
self._false_value_list = [False]
self._true_value_list = [True]
elif self._type == "remote_start":
self._update_key = BSH_REMOTE_START_ALLOWANCE_STATE
self._false_value_list = [False]
self._true_value_list = [True]
@property @property
def is_on(self): def is_on(self):
@ -44,18 +65,17 @@ class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity):
async def async_update(self): async def async_update(self):
"""Update the binary sensor's status.""" """Update the binary sensor's status."""
state = self.device.appliance.status.get(BSH_DOOR_STATE, {}) state = self.device.appliance.status.get(self._update_key, {})
if not state: if not state:
self._state = None self._state = None
elif state.get("value") in [ elif state.get("value") in self._false_value_list:
"BSH.Common.EnumType.DoorState.Closed",
"BSH.Common.EnumType.DoorState.Locked",
]:
self._state = False self._state = False
elif state.get("value") == "BSH.Common.EnumType.DoorState.Open": elif state.get("value") in self._true_value_list:
self._state = True self._state = True
else: else:
_LOGGER.warning("Unexpected value for HomeConnect door state: %s", state) _LOGGER.warning(
"Unexpected value for HomeConnect %s state: %s", self._type, state
)
self._state = None self._state = None
_LOGGER.debug("Updated, new state: %s", self._state) _LOGGER.debug("Updated, new state: %s", self._state)

View File

@ -11,6 +11,8 @@ BSH_POWER_OFF = "BSH.Common.EnumType.PowerState.Off"
BSH_POWER_STANDBY = "BSH.Common.EnumType.PowerState.Standby" BSH_POWER_STANDBY = "BSH.Common.EnumType.PowerState.Standby"
BSH_ACTIVE_PROGRAM = "BSH.Common.Root.ActiveProgram" BSH_ACTIVE_PROGRAM = "BSH.Common.Root.ActiveProgram"
BSH_OPERATION_STATE = "BSH.Common.Status.OperationState" BSH_OPERATION_STATE = "BSH.Common.Status.OperationState"
BSH_REMOTE_CONTROL_ACTIVATION_STATE = "BSH.Common.Status.RemoteControlActive"
BSH_REMOTE_START_ALLOWANCE_STATE = "BSH.Common.Status.RemoteControlStartAllowed"
COOKING_LIGHTING = "Cooking.Common.Setting.Lighting" COOKING_LIGHTING = "Cooking.Common.Setting.Lighting"
COOKING_LIGHTING_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness" COOKING_LIGHTING_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness"

View File

@ -6,7 +6,7 @@ import logging
from homeassistant.const import DEVICE_CLASS_TIMESTAMP from homeassistant.const import DEVICE_CLASS_TIMESTAMP
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .const import DOMAIN from .const import BSH_OPERATION_STATE, DOMAIN
from .entity import HomeConnectEntity from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -51,7 +51,7 @@ class HomeConnectSensor(HomeConnectEntity):
return self._state is not None return self._state is not None
async def async_update(self): async def async_update(self):
"""Update the sensos status.""" """Update the sensor's status."""
status = self.device.appliance.status status = self.device.appliance.status
if self._key not in status: if self._key not in status:
self._state = None self._state = None
@ -74,6 +74,11 @@ class HomeConnectSensor(HomeConnectEntity):
).isoformat() ).isoformat()
else: else:
self._state = status[self._key].get("value") self._state = status[self._key].get("value")
if self._key == BSH_OPERATION_STATE:
# Value comes back as an enum, we only really care about the
# last part, so split it off
# https://developer.home-connect.com/docs/status/operation_state
self._state = self._state.split(".")[-1]
_LOGGER.debug("Updated, new state: %s", self._state) _LOGGER.debug("Updated, new state: %s", self._state)
@property @property