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 (
BSH_ACTIVE_PROGRAM,
BSH_OPERATION_STATE,
BSH_POWER_OFF,
BSH_POWER_STANDBY,
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):
"""Device that has a door sensor."""
@ -164,6 +184,7 @@ class DeviceWithDoor(HomeConnectDevice):
return {
"device": self,
"desc": "Door",
"sensor_type": "door",
"device_class": "door",
}
@ -173,11 +194,7 @@ class DeviceWithLight(HomeConnectDevice):
def get_light_entity(self):
"""Get a dictionary with info about the lighting."""
return {
"device": self,
"desc": "Light",
"ambient": None,
}
return {"device": self, "desc": "Light", "ambient": None}
class DeviceWithAmbientLight(HomeConnectDevice):
@ -185,14 +202,36 @@ class DeviceWithAmbientLight(HomeConnectDevice):
def get_ambientlight_entity(self):
"""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 {
"device": self,
"desc": "AmbientLight",
"ambient": True,
"desc": "Remote Control",
"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."""
PROGRAMS = [
@ -217,16 +256,26 @@ class Dryer(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
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_switches = self.get_program_switches()
return {
"binary_sensor": [door_entity],
"binary_sensor": [door_entity, remote_control, remote_start],
"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."""
PROGRAMS = [
@ -257,16 +306,25 @@ class Dishwasher(DeviceWithDoor, DeviceWithAmbientLight, DeviceWithPrograms):
def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
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_switches = self.get_program_switches()
return {
"binary_sensor": [door_entity],
"binary_sensor": [door_entity, remote_control, remote_start],
"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."""
PROGRAMS = [
@ -282,16 +340,25 @@ class Oven(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
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_switches = self.get_program_switches()
return {
"binary_sensor": [door_entity],
"binary_sensor": [door_entity, remote_control, remote_start],
"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."""
PROGRAMS = [
@ -321,16 +388,19 @@ class Washer(DeviceWithDoor, DeviceWithPrograms):
def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
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_switches = self.get_program_switches()
return {
"binary_sensor": [door_entity],
"binary_sensor": [door_entity, remote_control, remote_start],
"switch": program_switches,
"sensor": program_sensors,
"sensor": program_sensors + op_state_sensor,
}
class CoffeeMaker(DeviceWithPrograms):
class CoffeeMaker(DeviceWithOpState, DeviceWithPrograms, DeviceWithRemoteStart):
"""Coffee maker class."""
PROGRAMS = [
@ -354,12 +424,25 @@ class CoffeeMaker(DeviceWithPrograms):
def get_entity_info(self):
"""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_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."""
PROGRAMS = [
@ -370,13 +453,17 @@ class Hood(DeviceWithLight, DeviceWithAmbientLight, DeviceWithPrograms):
def get_entity_info(self):
"""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()
ambientlight_entity = self.get_ambientlight_entity()
op_state_sensor = self.get_opstate_sensor()
program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches()
return {
"binary_sensor": [remote_control, remote_start],
"switch": program_switches,
"sensor": program_sensors,
"sensor": program_sensors + op_state_sensor,
"light": [light_entity, ambientlight_entity],
}
@ -390,13 +477,19 @@ class FridgeFreezer(DeviceWithDoor):
return {"binary_sensor": [door_entity]}
class Hob(DeviceWithPrograms):
class Hob(DeviceWithOpState, DeviceWithPrograms, DeviceWithRemoteControl):
"""Hob class."""
PROGRAMS = [{"name": "Cooking.Hob.Program.PowerLevelMode"}]
def get_entity_info(self):
"""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_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 .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
_LOGGER = logging.getLogger(__name__)
@ -26,11 +31,27 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity):
"""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."""
super().__init__(device, desc)
self._device_class = device_class
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
def is_on(self):
@ -44,18 +65,17 @@ class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity):
async def async_update(self):
"""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:
self._state = None
elif state.get("value") in [
"BSH.Common.EnumType.DoorState.Closed",
"BSH.Common.EnumType.DoorState.Locked",
]:
elif state.get("value") in self._false_value_list:
self._state = False
elif state.get("value") == "BSH.Common.EnumType.DoorState.Open":
elif state.get("value") in self._true_value_list:
self._state = True
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
_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_ACTIVE_PROGRAM = "BSH.Common.Root.ActiveProgram"
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_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness"

View File

@ -6,7 +6,7 @@ import logging
from homeassistant.const import DEVICE_CLASS_TIMESTAMP
import homeassistant.util.dt as dt_util
from .const import DOMAIN
from .const import BSH_OPERATION_STATE, DOMAIN
from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__)
@ -51,7 +51,7 @@ class HomeConnectSensor(HomeConnectEntity):
return self._state is not None
async def async_update(self):
"""Update the sensos status."""
"""Update the sensor's status."""
status = self.device.appliance.status
if self._key not in status:
self._state = None
@ -74,6 +74,11 @@ class HomeConnectSensor(HomeConnectEntity):
).isoformat()
else:
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)
@property