Skip to content
This repository has been archived by the owner on Oct 11, 2022. It is now read-only.

Added Ambient light #105

Merged
merged 4 commits into from
Oct 17, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions custom_components/home_connect_beta/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""API for Home Connect bound to HASS OAuth."""

from asyncio import run_coroutine_threadsafe
import logging
from asyncio import run_coroutine_threadsafe

import homeconnect
from homeconnect.api import HomeConnectError
Expand All @@ -13,8 +13,10 @@

from .const import (
BSH_ACTIVE_PROGRAM,
BSH_AMBIENTLIGHTENABLED,
BSH_POWER_OFF,
BSH_POWER_STANDBY,
COOKING_LIGHTING,
SIGNAL_UPDATE_ENTITIES,
)

Expand Down Expand Up @@ -174,12 +176,21 @@ def get_door_entity(self):
class DeviceWithLight(HomeConnectDevice):
"""Device that has lighting."""

def get_light_entity(self):
def get_light_entities(self):
"""Get a dictionary with info about the lighting."""
return {
"device": self,
"desc": "Light",
}
lights = []
try:
settings = self.appliance.get_settings()
Sjack-Sch marked this conversation as resolved.
Show resolved Hide resolved
if COOKING_LIGHTING in settings:
lights.append({"device": self, "desc": "Light", "ambient": None})
if BSH_AMBIENTLIGHTENABLED in settings:
lights.append(
{"device": self, "desc": "Ambient light", "ambient": True}
)
return lights
except (HomeConnectError, ValueError):
_LOGGER.debug("Unable to fetch settings. Probably offline.")
return []


class Dryer(DeviceWithDoor, DeviceWithPrograms):
Expand Down Expand Up @@ -216,8 +227,6 @@ def get_entity_info(self):
}




class WasherDryer(DeviceWithDoor, DeviceWithPrograms):
"""Washer class."""

Expand Down Expand Up @@ -273,7 +282,7 @@ def get_entity_info(self):
}


class Dishwasher(DeviceWithDoor, DeviceWithPrograms):
class Dishwasher(DeviceWithDoor, DeviceWithLight, DeviceWithPrograms):
"""Dishwasher class."""

PROGRAMS = [
Expand Down Expand Up @@ -303,13 +312,15 @@ class Dishwasher(DeviceWithDoor, DeviceWithPrograms):

def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
light_entities = self.get_light_entities()
door_entity = self.get_door_entity()
program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches()
return {
"binary_sensor": [door_entity],
"switch": program_switches,
"sensor": program_sensors,
"light": light_entities,
}


Expand Down Expand Up @@ -441,13 +452,13 @@ class Hood(DeviceWithLight, DeviceWithPrograms):

def get_entity_info(self):
"""Get a dictionary with infos about the associated entities."""
light_entity = self.get_light_entity()
light_entities = self.get_light_entities()
program_sensors = self.get_program_sensors()
program_switches = self.get_program_switches()
return {
"switch": program_switches,
"sensor": program_sensors,
"light" : [light_entity],
"light": light_entities,
}


Expand Down
10 changes: 9 additions & 1 deletion custom_components/home_connect_beta/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@
BSH_POWER_STANDBY = "BSH.Common.EnumType.PowerState.Standby"
BSH_ACTIVE_PROGRAM = "BSH.Common.Root.ActiveProgram"
BSH_OPERATION_STATE = "BSH.Common.Status.OperationState"

COOKING_LIGHTING = "Cooking.Common.Setting.Lighting"
COOKING_LIGHTINGBRIGHTNESS = "Cooking.Common.Setting.LightingBrightness"

BSH_AMBIENTLIGHTENABLED = "BSH.Common.Setting.AmbientLightEnabled"
BSH_AMBIENTLIGHTBRIGHTNESS = "BSH.Common.Setting.AmbientLightBrightness"
BSH_AMBIENTLIGHTCOLOR = "BSH.Common.Setting.AmbientLightColor"
BSH_AMBIENTLIGHTCOLOR_CUSTOMCOLOR = "BSH.Common.EnumType.AmbientLightColor.CustomColor"
BSH_AMBIENTLIGHTCUSTOMCOLOR = "BSH.Common.Setting.AmbientLightCustomColor"

BSH_DOOR_STATE = "BSH.Common.Status.DoorState"
BSH_PAUSE = "BSH.Common.Command.PauseProgram"
BSH_RESUME = "BSH.Common.Command.ResumeProgram"
Expand All @@ -28,4 +36,4 @@

ATTR_PROGRAM = "program"
ATTR_KEY = "key"
ATTR_VALUE = "value"
ATTR_VALUE = "value"
128 changes: 107 additions & 21 deletions custom_components/home_connect_beta/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@

from homeconnect.api import HomeConnectError

import homeassistant.util.color as color_util
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
LightEntity,
ATTR_HS_COLOR,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR,
LightEntity,
)

from .const import COOKING_LIGHTING, COOKING_LIGHTINGBRIGHTNESS, DOMAIN
from .const import (
BSH_AMBIENTLIGHTBRIGHTNESS,
BSH_AMBIENTLIGHTCOLOR,
BSH_AMBIENTLIGHTCOLOR_CUSTOMCOLOR,
BSH_AMBIENTLIGHTCUSTOMCOLOR,
BSH_AMBIENTLIGHTENABLED,
COOKING_LIGHTING,
COOKING_LIGHTINGBRIGHTNESS,
DOMAIN,
)
from .entity import HomeConnectEntity

_LOGGER = logging.getLogger(__name__)
Expand All @@ -35,11 +47,23 @@ def get_entities():
class HomeConnectLight(HomeConnectEntity, LightEntity):
"""Light for Home Connect."""

def __init__(self, device, desc):
def __init__(self, device, desc, ambient):
"""Initialize the entity."""
super().__init__(device, desc)
self._state = None
self._brightness = None
self._hs_color = None
self._ambient = ambient
if self._ambient:
self._brightnesskey = BSH_AMBIENTLIGHTBRIGHTNESS
self._key = BSH_AMBIENTLIGHTENABLED
self._customcolorkey = BSH_AMBIENTLIGHTCUSTOMCOLOR
self._colorkey = BSH_AMBIENTLIGHTCOLOR
else:
self._brightnesskey = COOKING_LIGHTINGBRIGHTNESS
self._key = COOKING_LIGHTING
self._customcolorkey = None
self._colorkey = None

@property
def is_on(self):
Expand All @@ -51,22 +75,68 @@ def brightness(self):
"""Return the brightness of the light."""
return self._brightness

@property
def hs_color(self):
"""Return the color property."""
return self._hs_color

@property
def supported_features(self):
"""Flag supported features."""
if self._ambient:
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR
return SUPPORT_BRIGHTNESS

async def async_turn_on(self, **kwargs):
"""Switch the light on / change brightness."""
if ATTR_BRIGHTNESS in kwargs:
"""Switch the light on, change brightness, change color."""
if self._ambient:
if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs:
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting,
self._colorkey,
BSH_AMBIENTLIGHTCOLOR_CUSTOMCOLOR,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying selecting customcolor: %s", err)

brightness = 10 + ceil(self._brightness / 255 * 90)
if ATTR_BRIGHTNESS in kwargs:
brightness = 10 + ceil(kwargs[ATTR_BRIGHTNESS] / 255 * 90)

hs_color = self._hs_color
if ATTR_HS_COLOR in kwargs:
hs_color = kwargs[ATTR_HS_COLOR]

if hs_color != None:
rgb = color_util.color_hsv_to_RGB(*hs_color, brightness)
hex = color_util.color_rgb_to_hex(rgb[0], rgb[1], rgb[2])
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting,
self._customcolorkey,
"#" + hex,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying setting the color: %s", err)
self._state = False
else:
_LOGGER.debug("Tried to switch light on for: %s", self.name)
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting, self._key, True,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn on light: %s", err)
self._state = False

elif ATTR_BRIGHTNESS in kwargs:
_LOGGER.debug("Tried to change brightness for: %s", self.name)
"""Convert Home Assistant brightness (0-255) to Home Connect brightness (10-100)"""
""" Convert Home Assistant brightness (0-255) to Home Connect brightness (10-100)"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This space should be removed; also there is no full stop. Please run pydocstyle and make sure it is happy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, forgot to make pydocstyle happy :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi David,

Sorry to react so late, I totally forgot this PR.
Can we finish this PR?
After it has been merged I will merge it in the official HA.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

hmm strange, I also forgot about it. So is it ready to merge and all issues have been resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, al request have been resolved.
I am not sure if the 5 minute delays mentioned by @anthonyangel is still there. I will try this week to execute some tests to find out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Anthonie, thanks for sharing.
Would it be possible for you to check if the core version of home connect has a different delay?

Copy link
Contributor Author

@Sjack-Sch Sjack-Sch Oct 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK great, let me know.

Also a heads-up: we should wait with the core PR until DavidMStraub/homeconnect#3 is finally closed (I just pushed a possible fix but have to wait for others testing it.).

I just checked the core version of home connect and I noticed the same delay before entities become available after a restart as seen in the beta version.

I think we can this PR.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge, you mean? 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep merge, auto correct is not always helping 🙃

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, I just got a mini-PR merged into HA core fixing the SSE reconnection issue by simply bumping the homeconnect dependency. I wanted to separate this from the feature PR as it is an important fix. @Sjack-Sch if you want feel free to open a PR at core with the additional changes in this repo.

brightness = 10 + ceil(kwargs[ATTR_BRIGHTNESS] / 255 * 90)
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting,
COOKING_LIGHTINGBRIGHTNESS,
brightness,
self.device.appliance.set_setting, self._brightnesskey, brightness,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying set the brightness: %s", err)
Expand All @@ -76,19 +146,20 @@ async def async_turn_on(self, **kwargs):
_LOGGER.debug("Tried to switch light on for: %s", self.name)
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting, COOKING_LIGHTING, True,
self.device.appliance.set_setting, self._key, True,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn on light: %s", err)
self._state = False

self.async_entity_update()

async def async_turn_off(self, **kwargs):
"""Switch the light off."""
_LOGGER.debug("tried to switch light off for: %s", self.name)
try:
await self.hass.async_add_executor_job(
self.device.appliance.set_setting, COOKING_LIGHTING, False,
self.device.appliance.set_setting, self._key, False,
)
except HomeConnectError as err:
_LOGGER.error("Error while trying to turn off light: %s", err)
Expand All @@ -97,18 +168,33 @@ async def async_turn_off(self, **kwargs):

async def async_update(self):
"""Update the light's status."""
if self.device.appliance.status.get(COOKING_LIGHTING, {}).get("value") is True:
if self.device.appliance.status.get(self._key, {}).get("value") is True:
self._state = True
elif (
self.device.appliance.status.get(COOKING_LIGHTING, {}).get("value") is False
):
elif self.device.appliance.status.get(self._key, {}).get("value") is False:
self._state = False
else:
self._state = None
brightness = self.device.appliance.status.get(COOKING_LIGHTINGBRIGHTNESS, {})
if brightness is None:
self._brightness = None
else:
self._brightness = ceil((brightness.get("value") - 10) * 255 / 90)

_LOGGER.debug("Updated, new light state: %s", self._state)
_LOGGER.debug("Updated, new brightness: %s", self._brightness)

if self._ambient:
color = self.device.appliance.status.get(self._customcolorkey, {})

if color is None:
self._hs_color = None
self._brightness = None
else:
colorvalue = color.get("value")[1:]
rgb = color_util.rgb_hex_to_rgb_list(colorvalue)
hsv = color_util.color_RGB_to_hsv(rgb[0], rgb[1], rgb[2])
self._hs_color = [hsv[0], hsv[1]]
self._brightness = ceil((hsv[2] - 10) * 255 / 90)
_LOGGER.debug("Updated, new brightness: %s", self._brightness)

else:
brightness = self.device.appliance.status.get(self._brightnesskey, {})
if brightness is None:
self._brightness = None
else:
self._brightness = ceil((brightness.get("value") - 10) * 255 / 90)
_LOGGER.debug("Updated, new brightness: %s", self._brightness)