Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
47 changes: 34 additions & 13 deletions homeassistant/components/homekit_controller/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR,
SUPPORT_COLOR_TEMP,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_HS,
COLOR_MODE_ONOFF,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
Expand Down Expand Up @@ -79,23 +80,43 @@ def color_temp(self) -> int:
return self.service.value(CharacteristicsTypes.COLOR_TEMPERATURE)

@property
def supported_features(self) -> int:
"""Flag supported features."""
features = 0
def color_mode(self) -> str:
"""Return the color mode of the light."""
# aiohomekit does not keep track of the light's color mode, report
# hs for light supporting both hs and ct
if self.service.has(CharacteristicsTypes.HUE) or self.service.has(
CharacteristicsTypes.SATURATION
):
return COLOR_MODE_HS

if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
return COLOR_MODE_COLOR_TEMP

if self.service.has(CharacteristicsTypes.BRIGHTNESS):
features |= SUPPORT_BRIGHTNESS
return COLOR_MODE_BRIGHTNESS

return COLOR_MODE_ONOFF

@property
def supported_color_modes(self) -> set[str] | None:
"""Flag supported color modes."""
color_modes = set()

if self.service.has(CharacteristicsTypes.HUE) or self.service.has(
CharacteristicsTypes.SATURATION
):
color_modes.add(COLOR_MODE_HS)

if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
features |= SUPPORT_COLOR_TEMP
color_modes.add(COLOR_MODE_COLOR_TEMP)

if self.service.has(CharacteristicsTypes.HUE):
features |= SUPPORT_COLOR
if not color_modes and self.service.has(CharacteristicsTypes.BRIGHTNESS):
color_modes.add(COLOR_MODE_BRIGHTNESS)

if self.service.has(CharacteristicsTypes.SATURATION):
features |= SUPPORT_COLOR
if not color_modes:
color_modes.add(COLOR_MODE_ONOFF)

return features
return color_modes

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the specified light on."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
SUPPORT_ALARM_ARM_HOME,
SUPPORT_ALARM_ARM_NIGHT,
)
from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
from homeassistant.components.number import NumberMode
from homeassistant.helpers.entity import EntityCategory

Expand Down Expand Up @@ -52,7 +51,7 @@ async def test_aqara_gateway_setup(hass):
"light.aqara_hub_1563",
friendly_name="Aqara Hub-1563",
unique_id="homekit-0000000123456789-65792",
supported_features=SUPPORT_BRIGHTNESS | SUPPORT_COLOR,
supported_features=0,
capabilities={"supported_color_modes": ["hs"]},
state="off",
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Make sure that an Arlo Baby can be setup."""

from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
from homeassistant.components.sensor import SensorStateClass
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS

Expand Down Expand Up @@ -75,7 +74,7 @@ async def test_arlo_baby_setup(hass):
entity_id="light.arlobabya0",
unique_id="homekit-00A0000000000-1100",
friendly_name="ArloBabyA0",
supported_features=SUPPORT_BRIGHTNESS | SUPPORT_COLOR,
supported_features=0,
capabilities={"supported_color_modes": ["hs"]},
state="off",
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from aiohomekit.testing import FakePairing
import pytest

from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
from homeassistant.helpers.entity import EntityCategory
import homeassistant.util.dt as dt_util

Expand Down Expand Up @@ -47,7 +46,7 @@ async def test_koogeek_ls1_setup(hass):
entity_id="light.koogeek_ls1_20833f",
friendly_name="Koogeek-LS1-20833F",
unique_id="homekit-AAAA011111111111-7",
supported_features=SUPPORT_BRIGHTNESS | SUPPORT_COLOR,
supported_features=0,
capabilities={"supported_color_modes": ["hs"]},
state="off",
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Make sure that Mysa Living is enumerated properly."""

from homeassistant.components.climate import SUPPORT_TARGET_TEMPERATURE
from homeassistant.components.light import SUPPORT_BRIGHTNESS
from homeassistant.components.sensor import SensorStateClass
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS

Expand Down Expand Up @@ -64,7 +63,7 @@ async def test_mysa_living_setup(hass):
entity_id="light.mysa_85dda9",
friendly_name="Mysa-85dda9",
unique_id="homekit-AAAAAAA000-40",
supported_features=SUPPORT_BRIGHTNESS,
supported_features=0,
capabilities={"supported_color_modes": ["brightness"]},
state="off",
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Make sure that Vocolinc Flowerbud is enumerated properly."""

from homeassistant.components.humidifier.const import SUPPORT_MODES
from homeassistant.components.light import SUPPORT_BRIGHTNESS, SUPPORT_COLOR
from homeassistant.components.number import NumberMode
from homeassistant.components.sensor import SensorStateClass
from homeassistant.const import PERCENTAGE
Expand Down Expand Up @@ -50,7 +49,7 @@ async def test_vocolinc_flowerbud_setup(hass):
entity_id="light.vocolinc_flowerbud_0d324b",
friendly_name="VOCOlinc-Flowerbud-0d324b",
unique_id="homekit-AM01121849000327-9",
supported_features=SUPPORT_BRIGHTNESS | SUPPORT_COLOR,
supported_features=0,
capabilities={"supported_color_modes": ["hs"]},
state="on",
),
Expand Down
4 changes: 2 additions & 2 deletions tests/components/homekit_controller/test_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ async def test_config_entry(hass: HomeAssistant, hass_client: ClientSession, utc
"attributes": {
"supported_color_modes": ["hs"],
"friendly_name": "Koogeek-LS1-20833F",
"supported_features": 17,
"supported_features": 0,
},
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
Expand Down Expand Up @@ -520,7 +520,7 @@ async def test_device(hass: HomeAssistant, hass_client: ClientSession, utcnow):
"attributes": {
"supported_color_modes": ["hs"],
"friendly_name": "Koogeek-LS1-20833F",
"supported_features": 17,
"supported_features": 0,
},
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
Expand Down
88 changes: 85 additions & 3 deletions tests/components/homekit_controller/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
from aiohomekit.model.services import ServicesTypes

from homeassistant.components.homekit_controller.const import KNOWN_DEVICES
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.components.light import (
ATTR_COLOR_MODE,
ATTR_SUPPORTED_COLOR_MODES,
COLOR_MODE_BRIGHTNESS,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_HS,
)
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_UNAVAILABLE

from tests.components.homekit_controller.common import setup_test_component

Expand Down Expand Up @@ -98,13 +105,79 @@ async def test_switch_change_light_state_color_temp(hass, utcnow):
)


async def test_switch_read_light_state(hass, utcnow):
async def test_switch_read_light_state_dimmer(hass, utcnow):
"""Test that we can read the state of a HomeKit light accessory."""
helper = await setup_test_component(hass, create_lightbulb_service)

# Initial state is that the light is off
state = await helper.poll_and_get_state()
assert state.state == "off"
assert ATTR_COLOR_MODE not in state.attributes
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_BRIGHTNESS]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0

# Simulate that someone switched on the device in the real world not via HA
state = await helper.async_update(
ServicesTypes.LIGHTBULB,
{
CharacteristicsTypes.ON: True,
CharacteristicsTypes.BRIGHTNESS: 100,
},
)
assert state.state == "on"
assert state.attributes["brightness"] == 255
assert state.attributes[ATTR_COLOR_MODE] == COLOR_MODE_BRIGHTNESS
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_BRIGHTNESS]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0

# Simulate that device switched off in the real world not via HA
state = await helper.async_update(
ServicesTypes.LIGHTBULB,
{
CharacteristicsTypes.ON: False,
},
)
assert state.state == "off"


async def test_switch_push_light_state_dimmer(hass, utcnow):
"""Test that we can read the state of a HomeKit light accessory."""
helper = await setup_test_component(hass, create_lightbulb_service)

# Initial state is that the light is off
state = hass.states.get(LIGHT_BULB_ENTITY_ID)
assert state.state == "off"

state = await helper.async_update(
ServicesTypes.LIGHTBULB,
{
CharacteristicsTypes.ON: True,
CharacteristicsTypes.BRIGHTNESS: 100,
},
)
assert state.state == "on"
assert state.attributes["brightness"] == 255

# Simulate that device switched off in the real world not via HA
state = await helper.async_update(
ServicesTypes.LIGHTBULB,
{
CharacteristicsTypes.ON: False,
},
)
assert state.state == "off"


async def test_switch_read_light_state_hs(hass, utcnow):
"""Test that we can read the state of a HomeKit light accessory."""
helper = await setup_test_component(hass, create_lightbulb_service_with_hs)

# Initial state is that the light is off
state = await helper.poll_and_get_state()
assert state.state == "off"
assert ATTR_COLOR_MODE not in state.attributes
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_HS]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0

# Simulate that someone switched on the device in the real world not via HA
state = await helper.async_update(
Expand All @@ -119,6 +192,9 @@ async def test_switch_read_light_state(hass, utcnow):
assert state.state == "on"
assert state.attributes["brightness"] == 255
assert state.attributes["hs_color"] == (4, 5)
assert state.attributes[ATTR_COLOR_MODE] == COLOR_MODE_HS
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_HS]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0

# Simulate that device switched off in the real world not via HA
state = await helper.async_update(
Expand All @@ -130,7 +206,7 @@ async def test_switch_read_light_state(hass, utcnow):
assert state.state == "off"


async def test_switch_push_light_state(hass, utcnow):
async def test_switch_push_light_state_hs(hass, utcnow):
"""Test that we can read the state of a HomeKit light accessory."""
helper = await setup_test_component(hass, create_lightbulb_service_with_hs)

Expand Down Expand Up @@ -168,6 +244,9 @@ async def test_switch_read_light_state_color_temp(hass, utcnow):
# Initial state is that the light is off
state = await helper.poll_and_get_state()
assert state.state == "off"
assert ATTR_COLOR_MODE not in state.attributes
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_COLOR_TEMP]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0

# Simulate that someone switched on the device in the real world not via HA
state = await helper.async_update(
Expand All @@ -181,6 +260,9 @@ async def test_switch_read_light_state_color_temp(hass, utcnow):
assert state.state == "on"
assert state.attributes["brightness"] == 255
assert state.attributes["color_temp"] == 400
assert state.attributes[ATTR_COLOR_MODE] == COLOR_MODE_COLOR_TEMP
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [COLOR_MODE_COLOR_TEMP]
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0


async def test_switch_push_light_state_color_temp(hass, utcnow):
Expand Down