mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add color temp support for older HomeKit devices (#107206)
This commit is contained in:
parent
f0ec1235b1
commit
2641e4014a
@ -17,6 +17,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
import homeassistant.util.color as color_util
|
||||||
|
|
||||||
from . import KNOWN_DEVICES
|
from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
@ -94,12 +95,16 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def min_mireds(self) -> int:
|
def min_mireds(self) -> int:
|
||||||
"""Return minimum supported color temperature."""
|
"""Return minimum supported color temperature."""
|
||||||
|
if not self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
|
||||||
|
return super().min_mireds
|
||||||
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
|
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
|
||||||
return int(min_value) if min_value else super().min_mireds
|
return int(min_value) if min_value else super().min_mireds
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def max_mireds(self) -> int:
|
def max_mireds(self) -> int:
|
||||||
"""Return the maximum color temperature."""
|
"""Return the maximum color temperature."""
|
||||||
|
if not self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
|
||||||
|
return super().max_mireds
|
||||||
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
|
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
|
||||||
return int(max_value) if max_value else super().max_mireds
|
return int(max_value) if max_value else super().max_mireds
|
||||||
|
|
||||||
@ -135,8 +140,9 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
|||||||
CharacteristicsTypes.SATURATION
|
CharacteristicsTypes.SATURATION
|
||||||
):
|
):
|
||||||
color_modes.add(ColorMode.HS)
|
color_modes.add(ColorMode.HS)
|
||||||
|
color_modes.add(ColorMode.COLOR_TEMP)
|
||||||
|
|
||||||
if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
|
elif self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
|
||||||
color_modes.add(ColorMode.COLOR_TEMP)
|
color_modes.add(ColorMode.COLOR_TEMP)
|
||||||
|
|
||||||
if not color_modes and self.service.has(CharacteristicsTypes.BRIGHTNESS):
|
if not color_modes and self.service.has(CharacteristicsTypes.BRIGHTNESS):
|
||||||
@ -153,23 +159,36 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
|||||||
temperature = kwargs.get(ATTR_COLOR_TEMP)
|
temperature = kwargs.get(ATTR_COLOR_TEMP)
|
||||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||||
|
|
||||||
characteristics = {}
|
characteristics: dict[str, Any] = {}
|
||||||
|
|
||||||
if hs_color is not None:
|
|
||||||
characteristics.update(
|
|
||||||
{
|
|
||||||
CharacteristicsTypes.HUE: hs_color[0],
|
|
||||||
CharacteristicsTypes.SATURATION: hs_color[1],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if brightness is not None:
|
if brightness is not None:
|
||||||
characteristics[CharacteristicsTypes.BRIGHTNESS] = int(
|
characteristics[CharacteristicsTypes.BRIGHTNESS] = int(
|
||||||
brightness * 100 / 255
|
brightness * 100 / 255
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# If they send both temperature and hs_color, and the device
|
||||||
|
# does not support both, temperature will win. This is not
|
||||||
|
# expected to happen in the UI, but it is possible via a manual
|
||||||
|
# service call.
|
||||||
if temperature is not None:
|
if temperature is not None:
|
||||||
characteristics[CharacteristicsTypes.COLOR_TEMPERATURE] = int(temperature)
|
if self.service.has(CharacteristicsTypes.COLOR_TEMPERATURE):
|
||||||
|
characteristics[CharacteristicsTypes.COLOR_TEMPERATURE] = int(
|
||||||
|
temperature
|
||||||
|
)
|
||||||
|
elif hs_color is None:
|
||||||
|
# Some HomeKit devices implement color temperature with HS
|
||||||
|
# since the spec "technically" does not permit the COLOR_TEMPERATURE
|
||||||
|
# characteristic and the HUE and SATURATION characteristics to be
|
||||||
|
# present at the same time.
|
||||||
|
hue_sat = color_util.color_temperature_to_hs(
|
||||||
|
color_util.color_temperature_mired_to_kelvin(temperature)
|
||||||
|
)
|
||||||
|
characteristics[CharacteristicsTypes.HUE] = hue_sat[0]
|
||||||
|
characteristics[CharacteristicsTypes.SATURATION] = hue_sat[1]
|
||||||
|
|
||||||
|
if hs_color is not None:
|
||||||
|
characteristics[CharacteristicsTypes.HUE] = hs_color[0]
|
||||||
|
characteristics[CharacteristicsTypes.SATURATION] = hs_color[1]
|
||||||
|
|
||||||
characteristics[CharacteristicsTypes.ON] = True
|
characteristics[CharacteristicsTypes.ON] = True
|
||||||
|
|
||||||
|
@ -43,10 +43,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
'color_temp',
|
||||||
'hs',
|
'hs',
|
||||||
]),
|
]),
|
||||||
'supported_features': 0,
|
'supported_features': 0,
|
||||||
@ -360,10 +367,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
'color_temp',
|
||||||
'hs',
|
'hs',
|
||||||
]),
|
]),
|
||||||
'supported_features': 0,
|
'supported_features': 0,
|
||||||
|
@ -1626,7 +1626,12 @@
|
|||||||
]),
|
]),
|
||||||
'area_id': None,
|
'area_id': None,
|
||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -1656,10 +1661,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'Aqara Hub-1563 Lightbulb-1563',
|
'friendly_name': 'Aqara Hub-1563 Lightbulb-1563',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
@ -2014,7 +2026,12 @@
|
|||||||
]),
|
]),
|
||||||
'area_id': None,
|
'area_id': None,
|
||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -2044,10 +2061,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'ArloBabyA0 Nightlight',
|
'friendly_name': 'ArloBabyA0 Nightlight',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
@ -9279,7 +9303,12 @@
|
|||||||
]),
|
]),
|
||||||
'area_id': None,
|
'area_id': None,
|
||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -9309,10 +9338,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'Laundry Smoke ED78',
|
'friendly_name': 'Laundry Smoke ED78',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
@ -11535,7 +11571,12 @@
|
|||||||
]),
|
]),
|
||||||
'area_id': None,
|
'area_id': None,
|
||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -11565,10 +11606,17 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': None,
|
'brightness': None,
|
||||||
'color_mode': None,
|
'color_mode': None,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
'friendly_name': 'Koogeek-LS1-20833F Light Strip',
|
||||||
'hs_color': None,
|
'hs_color': None,
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': None,
|
'rgb_color': None,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
@ -16318,7 +16366,12 @@
|
|||||||
]),
|
]),
|
||||||
'area_id': None,
|
'area_id': None,
|
||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -16348,17 +16401,24 @@
|
|||||||
'attributes': dict({
|
'attributes': dict({
|
||||||
'brightness': 127.5,
|
'brightness': 127.5,
|
||||||
'color_mode': <ColorMode.HS: 'hs'>,
|
'color_mode': <ColorMode.HS: 'hs'>,
|
||||||
|
'color_temp': None,
|
||||||
|
'color_temp_kelvin': None,
|
||||||
'friendly_name': 'VOCOlinc-Flowerbud-0d324b Mood Light',
|
'friendly_name': 'VOCOlinc-Flowerbud-0d324b Mood Light',
|
||||||
'hs_color': tuple(
|
'hs_color': tuple(
|
||||||
120.0,
|
120.0,
|
||||||
100.0,
|
100.0,
|
||||||
),
|
),
|
||||||
|
'max_color_temp_kelvin': 6535,
|
||||||
|
'max_mireds': 500,
|
||||||
|
'min_color_temp_kelvin': 2000,
|
||||||
|
'min_mireds': 153,
|
||||||
'rgb_color': tuple(
|
'rgb_color': tuple(
|
||||||
0,
|
0,
|
||||||
255,
|
255,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
|
<ColorMode.COLOR_TEMP: 'color_temp'>,
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
|
@ -39,4 +39,7 @@ async def test_light_add_feature_at_runtime(
|
|||||||
await device_config_changed(hass, accessories)
|
await device_config_changed(hass, accessories)
|
||||||
|
|
||||||
light_state = hass.states.get("light.laundry_smoke_ed78")
|
light_state = hass.states.get("light.laundry_smoke_ed78")
|
||||||
assert light_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.HS]
|
assert light_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [
|
||||||
|
ColorMode.COLOR_TEMP,
|
||||||
|
ColorMode.HS,
|
||||||
|
]
|
||||||
|
@ -74,6 +74,22 @@ async def test_switch_change_light_state(hass: HomeAssistant) -> None:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"light",
|
||||||
|
"turn_on",
|
||||||
|
{"entity_id": "light.testdevice", "brightness": 255, "color_temp": 300},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
helper.async_assert_service_values(
|
||||||
|
ServicesTypes.LIGHTBULB,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.ON: True,
|
||||||
|
CharacteristicsTypes.BRIGHTNESS: 100,
|
||||||
|
CharacteristicsTypes.HUE: 27,
|
||||||
|
CharacteristicsTypes.SATURATION: 49,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"light", "turn_off", {"entity_id": "light.testdevice"}, blocking=True
|
"light", "turn_off", {"entity_id": "light.testdevice"}, blocking=True
|
||||||
)
|
)
|
||||||
@ -176,7 +192,10 @@ async def test_switch_read_light_state_hs(hass: HomeAssistant) -> None:
|
|||||||
state = await helper.poll_and_get_state()
|
state = await helper.poll_and_get_state()
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
assert state.attributes[ATTR_COLOR_MODE] is None
|
assert state.attributes[ATTR_COLOR_MODE] is None
|
||||||
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.HS]
|
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [
|
||||||
|
ColorMode.COLOR_TEMP,
|
||||||
|
ColorMode.HS,
|
||||||
|
]
|
||||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||||
|
|
||||||
# Simulate that someone switched on the device in the real world not via HA
|
# Simulate that someone switched on the device in the real world not via HA
|
||||||
@ -193,7 +212,10 @@ async def test_switch_read_light_state_hs(hass: HomeAssistant) -> None:
|
|||||||
assert state.attributes["brightness"] == 255
|
assert state.attributes["brightness"] == 255
|
||||||
assert state.attributes["hs_color"] == (4, 5)
|
assert state.attributes["hs_color"] == (4, 5)
|
||||||
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.HS
|
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.HS
|
||||||
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.HS]
|
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [
|
||||||
|
ColorMode.COLOR_TEMP,
|
||||||
|
ColorMode.HS,
|
||||||
|
]
|
||||||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||||
|
|
||||||
# Simulate that device switched off in the real world not via HA
|
# Simulate that device switched off in the real world not via HA
|
||||||
@ -205,6 +227,25 @@ async def test_switch_read_light_state_hs(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
|
# Simulate that device switched on in the real world not via HA
|
||||||
|
state = await helper.async_update(
|
||||||
|
ServicesTypes.LIGHTBULB,
|
||||||
|
{
|
||||||
|
CharacteristicsTypes.ON: True,
|
||||||
|
CharacteristicsTypes.HUE: 6,
|
||||||
|
CharacteristicsTypes.SATURATION: 7,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert state.state == "on"
|
||||||
|
assert state.attributes["brightness"] == 255
|
||||||
|
assert state.attributes["hs_color"] == (6, 7)
|
||||||
|
assert state.attributes[ATTR_COLOR_MODE] == ColorMode.HS
|
||||||
|
assert state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [
|
||||||
|
ColorMode.COLOR_TEMP,
|
||||||
|
ColorMode.HS,
|
||||||
|
]
|
||||||
|
assert state.attributes[ATTR_SUPPORTED_FEATURES] == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_switch_push_light_state_hs(hass: HomeAssistant) -> None:
|
async def test_switch_push_light_state_hs(hass: HomeAssistant) -> None:
|
||||||
"""Test that we can read the state of a HomeKit light accessory."""
|
"""Test that we can read the state of a HomeKit light accessory."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user