Only compute homekit_controller accessory_info when entity is added or config changes (#102145)
This commit is contained in:
parent
e6895b5738
commit
d8e541a284
6 changed files with 642 additions and 33 deletions
|
@ -8,6 +8,7 @@ import os
|
|||
from typing import Any, Final
|
||||
from unittest import mock
|
||||
|
||||
from aiohomekit.controller.abstract import AbstractPairing
|
||||
from aiohomekit.hkjson import loads as hkloads
|
||||
from aiohomekit.model import (
|
||||
Accessories,
|
||||
|
@ -180,7 +181,7 @@ async def time_changed(hass, seconds):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def setup_accessories_from_file(hass, path):
|
||||
async def setup_accessories_from_file(hass: HomeAssistant, path: str) -> Accessories:
|
||||
"""Load an collection of accessory defs from JSON data."""
|
||||
accessories_fixture = await hass.async_add_executor_job(
|
||||
load_fixture, os.path.join("homekit_controller", path)
|
||||
|
@ -242,11 +243,11 @@ async def setup_test_accessories_with_controller(
|
|||
return config_entry, pairing
|
||||
|
||||
|
||||
async def device_config_changed(hass, accessories):
|
||||
async def device_config_changed(hass: HomeAssistant, accessories: Accessories):
|
||||
"""Discover new devices added to Home Assistant at runtime."""
|
||||
# Update the accessories our FakePairing knows about
|
||||
controller = hass.data[CONTROLLER]
|
||||
pairing = controller.pairings["00:00:00:00:00:00"]
|
||||
pairing: AbstractPairing = controller.pairings["00:00:00:00:00:00"]
|
||||
|
||||
accessories_obj = Accessories()
|
||||
for accessory in accessories:
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"description": "Identify",
|
||||
"format": "bool",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"type": "00000014-0000-1000-8000-0026BB765291"
|
||||
},
|
||||
{
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"iid": 3,
|
||||
"perms": ["pr"],
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"iid": 4,
|
||||
"perms": ["pr"],
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"iid": 5,
|
||||
"perms": ["pr"],
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"value": "Home Assistant Bridge"
|
||||
},
|
||||
{
|
||||
"description": "SerialNumber",
|
||||
"format": "string",
|
||||
"iid": 6,
|
||||
"perms": ["pr"],
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"description": "FirmwareRevision",
|
||||
"format": "string",
|
||||
"iid": 7,
|
||||
"perms": ["pr"],
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"value": "0.104.0.dev0"
|
||||
}
|
||||
],
|
||||
"iid": 1,
|
||||
"stype": "accessory-information",
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 1256851357,
|
||||
"services": [
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"description": "Identify",
|
||||
"format": "bool",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"type": "00000014-0000-1000-8000-0026BB765291"
|
||||
},
|
||||
{
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"iid": 3,
|
||||
"perms": ["pr"],
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"iid": 4,
|
||||
"perms": ["pr"],
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"value": "Fan"
|
||||
},
|
||||
{
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"iid": 5,
|
||||
"perms": ["pr"],
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"value": "Living Room Fan"
|
||||
},
|
||||
{
|
||||
"description": "SerialNumber",
|
||||
"format": "string",
|
||||
"iid": 6,
|
||||
"perms": ["pr"],
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"value": "fan.living_room_fan"
|
||||
},
|
||||
{
|
||||
"description": "FirmwareRevision",
|
||||
"format": "string",
|
||||
"iid": 7,
|
||||
"perms": ["pr"],
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"value": "0.104.0.dev0"
|
||||
}
|
||||
],
|
||||
"iid": 1,
|
||||
"stype": "accessory-information",
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291"
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"description": "Active",
|
||||
"format": "uint8",
|
||||
"iid": 9,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "000000B0-0000-1000-8000-0026BB765291",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"description": "RotationDirection",
|
||||
"format": "int",
|
||||
"iid": 10,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "00000028-0000-1000-8000-0026BB765291",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"description": "RotationSpeed",
|
||||
"format": "float",
|
||||
"iid": 12,
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "00000029-0000-1000-8000-0026BB765291",
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
}
|
||||
],
|
||||
"iid": 8,
|
||||
"stype": "fanv2",
|
||||
"type": "000000B7-0000-1000-8000-0026BB765291"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 766313939,
|
||||
"services": [
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"description": "Identify",
|
||||
"format": "bool",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"type": "00000014-0000-1000-8000-0026BB765291"
|
||||
},
|
||||
{
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"iid": 3,
|
||||
"perms": ["pr"],
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"iid": 4,
|
||||
"perms": ["pr"],
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"value": "Fan"
|
||||
},
|
||||
{
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"iid": 5,
|
||||
"perms": ["pr"],
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"value": "Ceiling Fan"
|
||||
},
|
||||
{
|
||||
"description": "SerialNumber",
|
||||
"format": "string",
|
||||
"iid": 6,
|
||||
"perms": ["pr"],
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"value": "fan.ceiling_fan"
|
||||
},
|
||||
{
|
||||
"description": "FirmwareRevision",
|
||||
"format": "string",
|
||||
"iid": 7,
|
||||
"perms": ["pr"],
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"value": "0.104.0.dev0"
|
||||
}
|
||||
],
|
||||
"iid": 1,
|
||||
"stype": "accessory-information",
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291"
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"description": "Active",
|
||||
"format": "uint8",
|
||||
"iid": 9,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "000000B0-0000-1000-8000-0026BB765291",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"description": "RotationSpeed",
|
||||
"format": "float",
|
||||
"iid": 10,
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "00000029-0000-1000-8000-0026BB765291",
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
}
|
||||
],
|
||||
"iid": 8,
|
||||
"stype": "fanv2",
|
||||
"type": "000000B7-0000-1000-8000-0026BB765291"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -5544,6 +5544,292 @@
|
|||
}),
|
||||
])
|
||||
# ---
|
||||
# name: test_snapshots[home_assistant_bridge_basic_fan]
|
||||
list([
|
||||
dict({
|
||||
'device': dict({
|
||||
'area_id': None,
|
||||
'config_entries': list([
|
||||
'TestData',
|
||||
]),
|
||||
'configuration_url': None,
|
||||
'connections': list([
|
||||
]),
|
||||
'disabled_by': None,
|
||||
'entry_type': None,
|
||||
'hw_version': '',
|
||||
'identifiers': list([
|
||||
list([
|
||||
'homekit_controller:accessory-id',
|
||||
'00:00:00:00:00:00:aid:766313939',
|
||||
]),
|
||||
]),
|
||||
'is_new': False,
|
||||
'manufacturer': 'Home Assistant',
|
||||
'model': 'Fan',
|
||||
'name': 'Ceiling Fan',
|
||||
'name_by_user': None,
|
||||
'suggested_area': None,
|
||||
'sw_version': '0.104.0.dev0',
|
||||
}),
|
||||
'entities': list([
|
||||
dict({
|
||||
'entry': dict({
|
||||
'aliases': list([
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': 'TestData',
|
||||
'device_class': None,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'button.ceiling_fan_identify',
|
||||
'has_entity_name': False,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Ceiling Fan Identify',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_766313939_1_2',
|
||||
'unit_of_measurement': None,
|
||||
}),
|
||||
'state': dict({
|
||||
'attributes': dict({
|
||||
'friendly_name': 'Ceiling Fan Identify',
|
||||
}),
|
||||
'entity_id': 'button.ceiling_fan_identify',
|
||||
'state': 'unknown',
|
||||
}),
|
||||
}),
|
||||
dict({
|
||||
'entry': dict({
|
||||
'aliases': list([
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'preset_modes': None,
|
||||
}),
|
||||
'config_entry_id': 'TestData',
|
||||
'device_class': None,
|
||||
'disabled_by': None,
|
||||
'domain': 'fan',
|
||||
'entity_category': None,
|
||||
'entity_id': 'fan.ceiling_fan',
|
||||
'has_entity_name': False,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Ceiling Fan',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <FanEntityFeature: 1>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_766313939_8',
|
||||
'unit_of_measurement': None,
|
||||
}),
|
||||
'state': dict({
|
||||
'attributes': dict({
|
||||
'friendly_name': 'Ceiling Fan',
|
||||
'percentage': 0,
|
||||
'percentage_step': 1.0,
|
||||
'preset_mode': None,
|
||||
'preset_modes': None,
|
||||
'supported_features': <FanEntityFeature: 1>,
|
||||
}),
|
||||
'entity_id': 'fan.ceiling_fan',
|
||||
'state': 'off',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
dict({
|
||||
'device': dict({
|
||||
'area_id': None,
|
||||
'config_entries': list([
|
||||
'TestData',
|
||||
]),
|
||||
'configuration_url': None,
|
||||
'connections': list([
|
||||
]),
|
||||
'disabled_by': None,
|
||||
'entry_type': None,
|
||||
'hw_version': '',
|
||||
'identifiers': list([
|
||||
list([
|
||||
'homekit_controller:accessory-id',
|
||||
'00:00:00:00:00:00:aid:1',
|
||||
]),
|
||||
]),
|
||||
'is_new': False,
|
||||
'manufacturer': 'Home Assistant',
|
||||
'model': 'Bridge',
|
||||
'name': 'Home Assistant Bridge',
|
||||
'name_by_user': None,
|
||||
'suggested_area': None,
|
||||
'sw_version': '0.104.0.dev0',
|
||||
}),
|
||||
'entities': list([
|
||||
dict({
|
||||
'entry': dict({
|
||||
'aliases': list([
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': 'TestData',
|
||||
'device_class': None,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'button.home_assistant_bridge_identify',
|
||||
'has_entity_name': False,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Home Assistant Bridge Identify',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1_1_2',
|
||||
'unit_of_measurement': None,
|
||||
}),
|
||||
'state': dict({
|
||||
'attributes': dict({
|
||||
'friendly_name': 'Home Assistant Bridge Identify',
|
||||
}),
|
||||
'entity_id': 'button.home_assistant_bridge_identify',
|
||||
'state': 'unknown',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
dict({
|
||||
'device': dict({
|
||||
'area_id': None,
|
||||
'config_entries': list([
|
||||
'TestData',
|
||||
]),
|
||||
'configuration_url': None,
|
||||
'connections': list([
|
||||
]),
|
||||
'disabled_by': None,
|
||||
'entry_type': None,
|
||||
'hw_version': '',
|
||||
'identifiers': list([
|
||||
list([
|
||||
'homekit_controller:accessory-id',
|
||||
'00:00:00:00:00:00:aid:1256851357',
|
||||
]),
|
||||
]),
|
||||
'is_new': False,
|
||||
'manufacturer': 'Home Assistant',
|
||||
'model': 'Fan',
|
||||
'name': 'Living Room Fan',
|
||||
'name_by_user': None,
|
||||
'suggested_area': None,
|
||||
'sw_version': '0.104.0.dev0',
|
||||
}),
|
||||
'entities': list([
|
||||
dict({
|
||||
'entry': dict({
|
||||
'aliases': list([
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': 'TestData',
|
||||
'device_class': None,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'button.living_room_fan_identify',
|
||||
'has_entity_name': False,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Living Room Fan Identify',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1256851357_1_2',
|
||||
'unit_of_measurement': None,
|
||||
}),
|
||||
'state': dict({
|
||||
'attributes': dict({
|
||||
'friendly_name': 'Living Room Fan Identify',
|
||||
}),
|
||||
'entity_id': 'button.living_room_fan_identify',
|
||||
'state': 'unknown',
|
||||
}),
|
||||
}),
|
||||
dict({
|
||||
'entry': dict({
|
||||
'aliases': list([
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'preset_modes': None,
|
||||
}),
|
||||
'config_entry_id': 'TestData',
|
||||
'device_class': None,
|
||||
'disabled_by': None,
|
||||
'domain': 'fan',
|
||||
'entity_category': None,
|
||||
'entity_id': 'fan.living_room_fan',
|
||||
'has_entity_name': False,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Living Room Fan',
|
||||
'platform': 'homekit_controller',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <FanEntityFeature: 5>,
|
||||
'translation_key': None,
|
||||
'unique_id': '00:00:00:00:00:00_1256851357_8',
|
||||
'unit_of_measurement': None,
|
||||
}),
|
||||
'state': dict({
|
||||
'attributes': dict({
|
||||
'direction': 'forward',
|
||||
'friendly_name': 'Living Room Fan',
|
||||
'percentage': 0,
|
||||
'percentage_step': 1.0,
|
||||
'preset_mode': None,
|
||||
'preset_modes': None,
|
||||
'supported_features': <FanEntityFeature: 5>,
|
||||
}),
|
||||
'entity_id': 'fan.living_room_fan',
|
||||
'state': 'off',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
# ---
|
||||
# name: test_snapshots[home_assistant_bridge_fan]
|
||||
list([
|
||||
dict({
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
"""Test for a Home Assistant bridge that changes fan features at runtime."""
|
||||
|
||||
|
||||
from homeassistant.components.fan import FanEntityFeature
|
||||
from homeassistant.const import ATTR_SUPPORTED_FEATURES
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..common import (
|
||||
device_config_changed,
|
||||
setup_accessories_from_file,
|
||||
setup_test_accessories,
|
||||
)
|
||||
|
||||
|
||||
async def test_fan_add_feature_at_runtime(hass: HomeAssistant) -> None:
|
||||
"""Test that new features can be added at runtime."""
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
# Set up a basic fan that does not support oscillation
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_basic_fan.json"
|
||||
)
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
fan = entity_registry.async_get("fan.living_room_fan")
|
||||
assert fan.unique_id == "00:00:00:00:00:00_1256851357_8"
|
||||
|
||||
fan_state = hass.states.get("fan.living_room_fan")
|
||||
assert (
|
||||
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is FanEntityFeature.SET_SPEED | FanEntityFeature.DIRECTION
|
||||
)
|
||||
|
||||
fan = entity_registry.async_get("fan.ceiling_fan")
|
||||
assert fan.unique_id == "00:00:00:00:00:00_766313939_8"
|
||||
|
||||
fan_state = hass.states.get("fan.ceiling_fan")
|
||||
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
|
||||
|
||||
# Now change the config to add oscillation
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_fan.json"
|
||||
)
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
fan_state = hass.states.get("fan.living_room_fan")
|
||||
assert (
|
||||
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is FanEntityFeature.SET_SPEED
|
||||
| FanEntityFeature.DIRECTION
|
||||
| FanEntityFeature.OSCILLATE
|
||||
)
|
||||
fan_state = hass.states.get("fan.ceiling_fan")
|
||||
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
|
Loading…
Add table
Add a link
Reference in a new issue