Fix HomeKit with entity registry restoration where supported_features is a non-None falsey (#30657)

* Fix homekit with #30094

* Fix test
This commit is contained in:
Jc2k 2020-01-11 00:33:48 +00:00 committed by Paulus Schoutsen
parent d6512c8a9f
commit 669c89e8c0
7 changed files with 300 additions and 4 deletions

View file

@ -502,13 +502,13 @@ def async_setup_entity_restore(
attrs: Dict[str, Any] = {ATTR_RESTORED: True}
if entry.capabilities:
if entry.capabilities is not None:
attrs.update(entry.capabilities)
if entry.supported_features:
if entry.supported_features is not None:
attrs[ATTR_SUPPORTED_FEATURES] = entry.supported_features
if entry.device_class:
if entry.device_class is not None:
attrs[ATTR_DEVICE_CLASS] = entry.device_class
states.async_set(entry.entity_id, STATE_UNAVAILABLE, attrs)

View file

@ -13,6 +13,7 @@ from homeassistant.components.homekit.const import ATTR_VALUE
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
EVENT_HOMEASSISTANT_START,
STATE_CLOSED,
STATE_CLOSING,
STATE_OPEN,
@ -20,6 +21,8 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import CoreState
from homeassistant.helpers import entity_registry
from tests.common import async_mock_service
from tests.components.homekit.common import patch_debounce
@ -308,3 +311,73 @@ async def test_window_open_close_stop(hass, hk_driver, cls, events):
assert acc.char_position_state.value == 2
assert len(events) == 3
assert events[-1].data[ATTR_VALUE] is None
async def test_window_basic_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"cover", "generic", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"cover",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={},
supported_features=SUPPORT_STOP,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.window_basic(hass, hk_driver, "Cover", "cover.simple", 2, None)
assert acc.category == 14
assert acc.char_current_position is not None
assert acc.char_target_position is not None
assert acc.char_position_state is not None
acc = cls.window_basic(hass, hk_driver, "Cover", "cover.all_info_set", 2, None)
assert acc.category == 14
assert acc.char_current_position is not None
assert acc.char_target_position is not None
assert acc.char_position_state is not None
async def test_window_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"cover", "generic", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"cover",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={},
supported_features=SUPPORT_STOP,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.window(hass, hk_driver, "Cover", "cover.simple", 2, None)
assert acc.category == 14
assert acc.char_current_position is not None
assert acc.char_target_position is not None
assert acc.char_position_state is not None
acc = cls.window(hass, hk_driver, "Cover", "cover.all_info_set", 2, None)
assert acc.category == 14
assert acc.char_current_position is not None
assert acc.char_target_position is not None
assert acc.char_position_state is not None

View file

@ -24,10 +24,13 @@ from homeassistant.components.homekit.util import HomeKitSpeedMapping
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
EVENT_HOMEASSISTANT_START,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
)
from homeassistant.core import CoreState
from homeassistant.helpers import entity_registry
from tests.common import async_mock_service
from tests.components.homekit.common import patch_debounce
@ -226,3 +229,40 @@ async def test_fan_speed(hass, hk_driver, cls, events):
assert call_set_speed[0].data[ATTR_SPEED] == "ludicrous"
assert len(events) == 1
assert events[-1].data[ATTR_VALUE] == "ludicrous"
async def test_fan_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"fan", "generic", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"fan",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={"speed_list": ["off", "low", "medium", "high"]},
supported_features=SUPPORT_SET_SPEED | SUPPORT_OSCILLATE | SUPPORT_DIRECTION,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.fan(hass, hk_driver, "Fan", "fan.simple", 2, None)
assert acc.category == 3
assert acc.char_active is not None
assert acc.char_direction is None
assert acc.char_speed is None
assert acc.char_swing is None
acc = cls.fan(hass, hk_driver, "Fan", "fan.all_info_set", 2, None)
assert acc.category == 3
assert acc.char_active is not None
assert acc.char_direction is not None
assert acc.char_speed is not None
assert acc.char_swing is not None

View file

@ -17,10 +17,13 @@ from homeassistant.components.light import (
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
EVENT_HOMEASSISTANT_START,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
)
from homeassistant.core import CoreState
from homeassistant.helpers import entity_registry
from tests.common import async_mock_service
from tests.components.homekit.common import patch_debounce
@ -205,3 +208,36 @@ async def test_light_rgb_color(hass, hk_driver, cls, events):
assert call_turn_on[0].data[ATTR_HS_COLOR] == (145, 75)
assert len(events) == 1
assert events[-1].data[ATTR_VALUE] == "set color at (145, 75)"
async def test_light_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"light", "hue", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"light",
"hue",
"9012",
suggested_object_id="all_info_set",
capabilities={"max": 100},
supported_features=5,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.light(hass, hk_driver, "Light", "light.simple", 2, None)
assert acc.category == 5 # Lightbulb
assert acc.chars == []
assert acc.char_on.value == 0
acc = cls.light(hass, hk_driver, "Light", "light.all_info_set", 2, None)
assert acc.category == 5 # Lightbulb
assert acc.chars == ["Brightness"]
assert acc.char_on.value == 0

View file

@ -24,12 +24,15 @@ from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
EVENT_HOMEASSISTANT_START,
STATE_IDLE,
STATE_OFF,
STATE_ON,
STATE_PAUSED,
STATE_PLAYING,
)
from homeassistant.core import CoreState
from homeassistant.helpers import entity_registry
from tests.common import async_mock_service
@ -336,3 +339,56 @@ async def test_media_player_television_basic(hass, hk_driver, events, caplog):
assert acc.char_active.value == 1
assert not caplog.messages or "Error" not in caplog.messages[-1]
async def test_tv_restore(hass, hk_driver, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"media_player",
"generic",
"1234",
suggested_object_id="simple",
device_class=DEVICE_CLASS_TV,
)
registry.async_get_or_create(
"media_player",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={
ATTR_INPUT_SOURCE_LIST: ["HDMI 1", "HDMI 2", "HDMI 3", "HDMI 4"],
},
supported_features=3469,
device_class=DEVICE_CLASS_TV,
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = TelevisionMediaPlayer(
hass, hk_driver, "MediaPlayer", "media_player.simple", 2, None
)
assert acc.category == 31
assert acc.chars_tv == []
assert acc.chars_speaker == []
assert acc.support_select_source is False
assert not hasattr(acc, "char_input_source")
acc = TelevisionMediaPlayer(
hass, hk_driver, "MediaPlayer", "media_player.all_info_set", 2, None
)
assert acc.category == 31
assert acc.chars_tv == ["RemoteKey"]
assert acc.chars_speaker == [
"Name",
"Active",
"VolumeControlType",
"VolumeSelector",
"Volume",
]
assert acc.support_select_source is True
assert acc.char_input_source is not None

View file

@ -41,8 +41,11 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
CONF_TEMPERATURE_UNIT,
EVENT_HOMEASSISTANT_START,
TEMP_FAHRENHEIT,
)
from homeassistant.core import CoreState
from homeassistant.helpers import entity_registry
from tests.common import async_mock_service
from tests.components.homekit.common import patch_debounce
@ -517,6 +520,51 @@ async def test_thermostat_temperature_step_whole(hass, hk_driver, cls):
assert acc.char_target_temp.properties[PROP_MIN_STEP] == 1.0
async def test_thermostat_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"climate", "generic", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"climate",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={
ATTR_MIN_TEMP: 60,
ATTR_MAX_TEMP: 70,
ATTR_HVAC_MODES: [HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF],
},
supported_features=0,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.thermostat(hass, hk_driver, "Climate", "climate.simple", 2, None)
assert acc.category == 9
assert acc.get_temperature_range() == (7, 35)
assert set(acc.char_target_heat_cool.properties["ValidValues"].keys()) == {
"cool",
"heat",
"heat_cool",
"off",
}
acc = cls.thermostat(hass, hk_driver, "Climate", "climate.all_info_set", 2, None)
assert acc.category == 9
assert acc.get_temperature_range() == (60.0, 70.0)
assert set(acc.char_target_heat_cool.properties["ValidValues"].keys()) == {
"heat_cool",
"off",
}
async def test_thermostat_hvac_modes(hass, hk_driver, cls):
"""Test if unsupported HVAC modes are deactivated in HomeKit."""
entity_id = "climate.test"
@ -671,3 +719,46 @@ async def test_water_heater_get_temperature_range(hass, hk_driver, cls):
)
await hass.async_block_till_done()
assert acc.get_temperature_range() == (15.5, 21.0)
async def test_water_heater_restore(hass, hk_driver, cls, events):
"""Test setting up an entity from state in the event registry."""
hass.state = CoreState.not_running
registry = await entity_registry.async_get_registry(hass)
registry.async_get_or_create(
"water_heater", "generic", "1234", suggested_object_id="simple",
)
registry.async_get_or_create(
"water_heater",
"generic",
"9012",
suggested_object_id="all_info_set",
capabilities={ATTR_MIN_TEMP: 60, ATTR_MAX_TEMP: 70},
supported_features=0,
device_class="mock-device-class",
)
hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {})
await hass.async_block_till_done()
acc = cls.thermostat(hass, hk_driver, "WaterHeater", "water_heater.simple", 2, None)
assert acc.category == 9
assert acc.get_temperature_range() == (7, 35)
assert set(acc.char_current_heat_cool.properties["ValidValues"].keys()) == {
"Cool",
"Heat",
"Off",
}
acc = cls.thermostat(
hass, hk_driver, "WaterHeater", "water_heater.all_info_set", 2, None
)
assert acc.category == 9
assert acc.get_temperature_range() == (60.0, 70.0)
assert set(acc.char_current_heat_cool.properties["ValidValues"].keys()) == {
"Cool",
"Heat",
"Off",
}

View file

@ -511,7 +511,7 @@ async def test_restore_states(hass):
simple = hass.states.get("light.simple")
assert simple is not None
assert simple.state == STATE_UNAVAILABLE
assert simple.attributes == {"restored": True}
assert simple.attributes == {"restored": True, "supported_features": 0}
disabled = hass.states.get("light.disabled")
assert disabled is None