Enforce maximum length for HomeKit characteristics (#53913)

This commit is contained in:
J. Nick Koston 2021-08-03 12:09:10 -05:00 committed by GitHub
parent fa9ac71c3a
commit df03cce471
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 20 deletions

View File

@ -64,6 +64,11 @@ from .const import (
HK_NOT_CHARGABLE, HK_NOT_CHARGABLE,
HK_NOT_CHARGING, HK_NOT_CHARGING,
MANUFACTURER, MANUFACTURER,
MAX_MANUFACTURER_LENGTH,
MAX_MODEL_LENGTH,
MAX_NAME_LENGTH,
MAX_SERIAL_LENGTH,
MAX_VERSION_LENGTH,
SERV_BATTERY_SERVICE, SERV_BATTERY_SERVICE,
SERVICE_HOMEKIT_RESET_ACCESSORY, SERVICE_HOMEKIT_RESET_ACCESSORY,
TYPE_FAUCET, TYPE_FAUCET,
@ -217,7 +222,9 @@ class HomeAccessory(Accessory):
**kwargs, **kwargs,
): ):
"""Initialize a Accessory object.""" """Initialize a Accessory object."""
super().__init__(driver=driver, display_name=name, aid=aid, *args, **kwargs) super().__init__(
driver=driver, display_name=name[:MAX_NAME_LENGTH], aid=aid, *args, **kwargs
)
self.config = config or {} self.config = config or {}
domain = split_entity_id(entity_id)[0].replace("_", " ") domain = split_entity_id(entity_id)[0].replace("_", " ")
@ -237,10 +244,10 @@ class HomeAccessory(Accessory):
sw_version = __version__ sw_version = __version__
self.set_info_service( self.set_info_service(
manufacturer=manufacturer, manufacturer=manufacturer[:MAX_MANUFACTURER_LENGTH],
model=model, model=model[:MAX_MODEL_LENGTH],
serial_number=entity_id, serial_number=entity_id[:MAX_SERIAL_LENGTH],
firmware_revision=sw_version, firmware_revision=sw_version[:MAX_VERSION_LENGTH],
) )
self.category = category self.category = category

View File

@ -293,3 +293,10 @@ CONFIG_OPTIONS = [
CONF_ENTITY_CONFIG, CONF_ENTITY_CONFIG,
CONF_HOMEKIT_MODE, CONF_HOMEKIT_MODE,
] ]
# ### Maximum Lengths ###
MAX_NAME_LENGTH = 64
MAX_SERIAL_LENGTH = 64
MAX_MODEL_LENGTH = 64
MAX_VERSION_LENGTH = 64
MAX_MANUFACTURER_LENGTH = 64

View File

@ -39,6 +39,7 @@ from .const import (
CHAR_ROTATION_DIRECTION, CHAR_ROTATION_DIRECTION,
CHAR_ROTATION_SPEED, CHAR_ROTATION_SPEED,
CHAR_SWING_MODE, CHAR_SWING_MODE,
MAX_NAME_LENGTH,
PROP_MIN_STEP, PROP_MIN_STEP,
SERV_FANV2, SERV_FANV2,
SERV_SWITCH, SERV_SWITCH,
@ -100,7 +101,8 @@ class Fan(HomeAccessory):
preset_serv = self.add_preload_service(SERV_SWITCH, CHAR_NAME) preset_serv = self.add_preload_service(SERV_SWITCH, CHAR_NAME)
serv_fan.add_linked_service(preset_serv) serv_fan.add_linked_service(preset_serv)
preset_serv.configure_char( preset_serv.configure_char(
CHAR_NAME, value=f"{self.display_name} {preset_mode}" CHAR_NAME,
value=f"{self.display_name} {preset_mode}"[:MAX_NAME_LENGTH],
) )
self.preset_mode_chars[preset_mode] = preset_serv.configure_char( self.preset_mode_chars[preset_mode] = preset_serv.configure_char(

View File

@ -55,6 +55,7 @@ from .const import (
FEATURE_PLAY_STOP, FEATURE_PLAY_STOP,
FEATURE_TOGGLE_MUTE, FEATURE_TOGGLE_MUTE,
KEY_PLAY_PAUSE, KEY_PLAY_PAUSE,
MAX_NAME_LENGTH,
SERV_SWITCH, SERV_SWITCH,
SERV_TELEVISION_SPEAKER, SERV_TELEVISION_SPEAKER,
) )
@ -134,7 +135,7 @@ class MediaPlayer(HomeAccessory):
def generate_service_name(self, mode): def generate_service_name(self, mode):
"""Generate name for individual service.""" """Generate name for individual service."""
return f"{self.display_name} {MODE_FRIENDLY_NAME[mode]}" return f"{self.display_name} {MODE_FRIENDLY_NAME[mode]}"[:MAX_NAME_LENGTH]
def set_on_off(self, value): def set_on_off(self, value):
"""Move switch state to value if call came from HomeKit.""" """Move switch state to value if call came from HomeKit."""

View File

@ -47,6 +47,7 @@ from .const import (
KEY_PREVIOUS_TRACK, KEY_PREVIOUS_TRACK,
KEY_REWIND, KEY_REWIND,
KEY_SELECT, KEY_SELECT,
MAX_NAME_LENGTH,
SERV_INPUT_SOURCE, SERV_INPUT_SOURCE,
SERV_TELEVISION, SERV_TELEVISION,
) )
@ -120,8 +121,10 @@ class RemoteInputSelectAccessory(HomeAccessory):
SERV_INPUT_SOURCE, [CHAR_IDENTIFIER, CHAR_NAME] SERV_INPUT_SOURCE, [CHAR_IDENTIFIER, CHAR_NAME]
) )
serv_tv.add_linked_service(serv_input) serv_tv.add_linked_service(serv_input)
serv_input.configure_char(CHAR_CONFIGURED_NAME, value=source) serv_input.configure_char(
serv_input.configure_char(CHAR_NAME, value=source) CHAR_CONFIGURED_NAME, value=source[:MAX_NAME_LENGTH]
)
serv_input.configure_char(CHAR_NAME, value=source[:MAX_NAME_LENGTH])
serv_input.configure_char(CHAR_IDENTIFIER, value=index) serv_input.configure_char(CHAR_IDENTIFIER, value=index)
serv_input.configure_char(CHAR_IS_CONFIGURED, value=True) serv_input.configure_char(CHAR_IS_CONFIGURED, value=True)
input_type = 3 if "hdmi" in source.lower() else 0 input_type = 3 if "hdmi" in source.lower() else 0

View File

@ -66,7 +66,7 @@ async def test_accessory_cancels_track_state_change_on_stop(hass, hk_driver):
async def test_home_accessory(hass, hk_driver): async def test_home_accessory(hass, hk_driver):
"""Test HomeAccessory class.""" """Test HomeAccessory class."""
entity_id = "sensor.accessory" entity_id = "sensor.accessory"
entity_id2 = "light.accessory" entity_id2 = "light.accessory_that_exceeds_the_maximum_maximum_maximum_maximum_maximum_maximum_maximum_allowed_length"
hass.states.async_set(entity_id, None) hass.states.async_set(entity_id, None)
hass.states.async_set(entity_id2, STATE_UNAVAILABLE) hass.states.async_set(entity_id2, STATE_UNAVAILABLE)
@ -94,27 +94,42 @@ async def test_home_accessory(hass, hk_driver):
assert serv.get_characteristic(CHAR_NAME).value == "Home Accessory" assert serv.get_characteristic(CHAR_NAME).value == "Home Accessory"
assert serv.get_characteristic(CHAR_MANUFACTURER).value == f"{MANUFACTURER} Light" assert serv.get_characteristic(CHAR_MANUFACTURER).value == f"{MANUFACTURER} Light"
assert serv.get_characteristic(CHAR_MODEL).value == "Light" assert serv.get_characteristic(CHAR_MODEL).value == "Light"
assert serv.get_characteristic(CHAR_SERIAL_NUMBER).value == "light.accessory" assert (
serv.get_characteristic(CHAR_SERIAL_NUMBER).value
== "light.accessory_that_exceeds_the_maximum_maximum_maximum_maximum"
)
acc3 = HomeAccessory( acc3 = HomeAccessory(
hass, hass,
hk_driver, hk_driver,
"Home Accessory", "Home Accessory that exceeds the maximum maximum maximum maximum maximum maximum length",
entity_id2, entity_id2,
3, 3,
{ {
ATTR_MODEL: "Awesome", ATTR_MODEL: "Awesome Model that exceeds the maximum maximum maximum maximum maximum maximum length",
ATTR_MANUFACTURER: "Lux Brands", ATTR_MANUFACTURER: "Lux Brands that exceeds the maximum maximum maximum maximum maximum maximum length",
ATTR_SW_VERSION: "0.4.3", ATTR_SW_VERSION: "0.4.3 that exceeds the maximum maximum maximum maximum maximum maximum length",
ATTR_INTEGRATION: "luxe", ATTR_INTEGRATION: "luxe that exceeds the maximum maximum maximum maximum maximum maximum length",
}, },
) )
assert acc3.available is False assert acc3.available is False
serv = acc3.services[0] # SERV_ACCESSORY_INFO serv = acc3.services[0] # SERV_ACCESSORY_INFO
assert serv.get_characteristic(CHAR_NAME).value == "Home Accessory" assert (
assert serv.get_characteristic(CHAR_MANUFACTURER).value == "Lux Brands" serv.get_characteristic(CHAR_NAME).value
assert serv.get_characteristic(CHAR_MODEL).value == "Awesome" == "Home Accessory that exceeds the maximum maximum maximum maximum "
assert serv.get_characteristic(CHAR_SERIAL_NUMBER).value == "light.accessory" )
assert (
serv.get_characteristic(CHAR_MANUFACTURER).value
== "Lux Brands that exceeds the maximum maximum maximum maximum maxi"
)
assert (
serv.get_characteristic(CHAR_MODEL).value
== "Awesome Model that exceeds the maximum maximum maximum maximum m"
)
assert (
serv.get_characteristic(CHAR_SERIAL_NUMBER).value
== "light.accessory_that_exceeds_the_maximum_maximum_maximum_maximum"
)
hass.states.async_set(entity_id, "on") hass.states.async_set(entity_id, "on")
await hass.async_block_till_done() await hass.async_block_till_done()