mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Use configured names in HomeKit for child accessories (#142531)
This commit is contained in:
parent
f84f6aa713
commit
514363f1c5
@ -35,6 +35,7 @@ from homeassistant.core import State, callback
|
||||
from .accessories import TYPES, HomeAccessory
|
||||
from .const import (
|
||||
CHAR_ACTIVE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_NAME,
|
||||
CHAR_ON,
|
||||
CHAR_ROTATION_DIRECTION,
|
||||
@ -120,7 +121,9 @@ class Fan(HomeAccessory):
|
||||
continue
|
||||
|
||||
preset_serv = self.add_preload_service(
|
||||
SERV_SWITCH, CHAR_NAME, unique_id=preset_mode
|
||||
SERV_SWITCH,
|
||||
[CHAR_NAME, CHAR_CONFIGURED_NAME],
|
||||
unique_id=preset_mode,
|
||||
)
|
||||
serv_fan.add_linked_service(preset_serv)
|
||||
preset_serv.configure_char(
|
||||
@ -129,6 +132,9 @@ class Fan(HomeAccessory):
|
||||
f"{self.display_name} {preset_mode}"
|
||||
),
|
||||
)
|
||||
preset_serv.configure_char(
|
||||
CHAR_CONFIGURED_NAME, value=cleanup_name_for_homekit(preset_mode)
|
||||
)
|
||||
|
||||
def setter_callback(value: int, preset_mode: str = preset_mode) -> None:
|
||||
self.set_preset_mode(value, preset_mode)
|
||||
|
@ -41,6 +41,7 @@ from .const import (
|
||||
ATTR_KEY_NAME,
|
||||
CATEGORY_RECEIVER,
|
||||
CHAR_ACTIVE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_MUTE,
|
||||
CHAR_NAME,
|
||||
CHAR_ON,
|
||||
@ -100,41 +101,67 @@ class MediaPlayer(HomeAccessory):
|
||||
)
|
||||
|
||||
if FEATURE_ON_OFF in feature_list:
|
||||
name = self.generate_service_name(FEATURE_ON_OFF)
|
||||
serv_on_off = self.add_preload_service(
|
||||
SERV_SWITCH, CHAR_NAME, unique_id=FEATURE_ON_OFF
|
||||
SERV_SWITCH, [CHAR_CONFIGURED_NAME, CHAR_NAME], unique_id=FEATURE_ON_OFF
|
||||
)
|
||||
serv_on_off.configure_char(
|
||||
CHAR_NAME, value=self.generate_service_name(FEATURE_ON_OFF)
|
||||
)
|
||||
serv_on_off.configure_char(
|
||||
CHAR_CONFIGURED_NAME,
|
||||
value=self.generated_configured_name(FEATURE_ON_OFF),
|
||||
)
|
||||
serv_on_off.configure_char(CHAR_NAME, value=name)
|
||||
self.chars[FEATURE_ON_OFF] = serv_on_off.configure_char(
|
||||
CHAR_ON, value=False, setter_callback=self.set_on_off
|
||||
)
|
||||
|
||||
if FEATURE_PLAY_PAUSE in feature_list:
|
||||
name = self.generate_service_name(FEATURE_PLAY_PAUSE)
|
||||
serv_play_pause = self.add_preload_service(
|
||||
SERV_SWITCH, CHAR_NAME, unique_id=FEATURE_PLAY_PAUSE
|
||||
SERV_SWITCH,
|
||||
[CHAR_CONFIGURED_NAME, CHAR_NAME],
|
||||
unique_id=FEATURE_PLAY_PAUSE,
|
||||
)
|
||||
serv_play_pause.configure_char(
|
||||
CHAR_NAME, value=self.generate_service_name(FEATURE_PLAY_PAUSE)
|
||||
)
|
||||
serv_play_pause.configure_char(
|
||||
CHAR_CONFIGURED_NAME,
|
||||
value=self.generated_configured_name(FEATURE_PLAY_PAUSE),
|
||||
)
|
||||
serv_play_pause.configure_char(CHAR_NAME, value=name)
|
||||
self.chars[FEATURE_PLAY_PAUSE] = serv_play_pause.configure_char(
|
||||
CHAR_ON, value=False, setter_callback=self.set_play_pause
|
||||
)
|
||||
|
||||
if FEATURE_PLAY_STOP in feature_list:
|
||||
name = self.generate_service_name(FEATURE_PLAY_STOP)
|
||||
serv_play_stop = self.add_preload_service(
|
||||
SERV_SWITCH, CHAR_NAME, unique_id=FEATURE_PLAY_STOP
|
||||
SERV_SWITCH,
|
||||
[CHAR_CONFIGURED_NAME, CHAR_NAME],
|
||||
unique_id=FEATURE_PLAY_STOP,
|
||||
)
|
||||
serv_play_stop.configure_char(
|
||||
CHAR_NAME, value=self.generate_service_name(FEATURE_PLAY_STOP)
|
||||
)
|
||||
serv_play_stop.configure_char(
|
||||
CHAR_CONFIGURED_NAME,
|
||||
value=self.generated_configured_name(FEATURE_PLAY_STOP),
|
||||
)
|
||||
serv_play_stop.configure_char(CHAR_NAME, value=name)
|
||||
self.chars[FEATURE_PLAY_STOP] = serv_play_stop.configure_char(
|
||||
CHAR_ON, value=False, setter_callback=self.set_play_stop
|
||||
)
|
||||
|
||||
if FEATURE_TOGGLE_MUTE in feature_list:
|
||||
name = self.generate_service_name(FEATURE_TOGGLE_MUTE)
|
||||
serv_toggle_mute = self.add_preload_service(
|
||||
SERV_SWITCH, CHAR_NAME, unique_id=FEATURE_TOGGLE_MUTE
|
||||
SERV_SWITCH,
|
||||
[CHAR_CONFIGURED_NAME, CHAR_NAME],
|
||||
unique_id=FEATURE_TOGGLE_MUTE,
|
||||
)
|
||||
serv_toggle_mute.configure_char(
|
||||
CHAR_NAME, value=self.generate_service_name(FEATURE_TOGGLE_MUTE)
|
||||
)
|
||||
serv_toggle_mute.configure_char(
|
||||
CHAR_CONFIGURED_NAME,
|
||||
value=self.generated_configured_name(FEATURE_TOGGLE_MUTE),
|
||||
)
|
||||
serv_toggle_mute.configure_char(CHAR_NAME, value=name)
|
||||
self.chars[FEATURE_TOGGLE_MUTE] = serv_toggle_mute.configure_char(
|
||||
CHAR_ON, value=False, setter_callback=self.set_toggle_mute
|
||||
)
|
||||
@ -146,6 +173,10 @@ class MediaPlayer(HomeAccessory):
|
||||
f"{self.display_name} {MODE_FRIENDLY_NAME[mode]}"
|
||||
)
|
||||
|
||||
def generated_configured_name(self, mode: str) -> str:
|
||||
"""Generate name for individual service."""
|
||||
return cleanup_name_for_homekit(MODE_FRIENDLY_NAME[mode])
|
||||
|
||||
def set_on_off(self, value: bool) -> None:
|
||||
"""Move switch state to value if call came from HomeKit."""
|
||||
_LOGGER.debug('%s: Set switch state for "on_off" to %s', self.entity_id, value)
|
||||
|
@ -49,6 +49,7 @@ from homeassistant.helpers.event import async_call_later
|
||||
from .accessories import TYPES, HomeAccessory, HomeDriver
|
||||
from .const import (
|
||||
CHAR_ACTIVE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_IN_USE,
|
||||
CHAR_NAME,
|
||||
CHAR_ON,
|
||||
@ -360,11 +361,13 @@ class SelectSwitch(HomeAccessory):
|
||||
options = state.attributes[ATTR_OPTIONS]
|
||||
for option in options:
|
||||
serv_option = self.add_preload_service(
|
||||
SERV_OUTLET, [CHAR_NAME, CHAR_IN_USE], unique_id=option
|
||||
)
|
||||
serv_option.configure_char(
|
||||
CHAR_NAME, value=cleanup_name_for_homekit(option)
|
||||
SERV_OUTLET,
|
||||
[CHAR_NAME, CHAR_CONFIGURED_NAME, CHAR_IN_USE],
|
||||
unique_id=option,
|
||||
)
|
||||
name = cleanup_name_for_homekit(option)
|
||||
serv_option.configure_char(CHAR_NAME, value=name)
|
||||
serv_option.configure_char(CHAR_CONFIGURED_NAME, value=name)
|
||||
serv_option.configure_char(CHAR_IN_USE, value=False)
|
||||
self.select_chars[option] = serv_option.configure_char(
|
||||
CHAR_ON,
|
||||
|
@ -15,6 +15,7 @@ from homeassistant.helpers.trigger import async_initialize_triggers
|
||||
from .accessories import TYPES, HomeAccessory
|
||||
from .aidmanager import get_system_unique_id
|
||||
from .const import (
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_NAME,
|
||||
CHAR_PROGRAMMABLE_SWITCH_EVENT,
|
||||
CHAR_SERVICE_LABEL_INDEX,
|
||||
@ -66,7 +67,7 @@ class DeviceTriggerAccessory(HomeAccessory):
|
||||
trigger_name = cleanup_name_for_homekit(" ".join(trigger_name_parts))
|
||||
serv_stateless_switch = self.add_preload_service(
|
||||
SERV_STATELESS_PROGRAMMABLE_SWITCH,
|
||||
[CHAR_NAME, CHAR_SERVICE_LABEL_INDEX],
|
||||
[CHAR_NAME, CHAR_CONFIGURED_NAME, CHAR_SERVICE_LABEL_INDEX],
|
||||
unique_id=unique_id,
|
||||
)
|
||||
self.triggers.append(
|
||||
@ -77,6 +78,9 @@ class DeviceTriggerAccessory(HomeAccessory):
|
||||
)
|
||||
)
|
||||
serv_stateless_switch.configure_char(CHAR_NAME, value=trigger_name)
|
||||
serv_stateless_switch.configure_char(
|
||||
CHAR_CONFIGURED_NAME, value=trigger_name
|
||||
)
|
||||
serv_stateless_switch.configure_char(
|
||||
CHAR_SERVICE_LABEL_INDEX, value=idx + 1
|
||||
)
|
||||
|
@ -453,7 +453,7 @@ async def test_config_entry_with_trigger_accessory(
|
||||
"iid": 6,
|
||||
"perms": ["pr"],
|
||||
"type": "30",
|
||||
"value": ANY,
|
||||
"value": device_id,
|
||||
},
|
||||
{
|
||||
"format": "string",
|
||||
@ -484,8 +484,15 @@ async def test_config_entry_with_trigger_accessory(
|
||||
"value": "Ceiling Lights Changed States",
|
||||
},
|
||||
{
|
||||
"format": "uint8",
|
||||
"format": "string",
|
||||
"iid": 11,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "E3",
|
||||
"value": "Ceiling Lights Changed States",
|
||||
},
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 12,
|
||||
"maxValue": 255,
|
||||
"minStep": 1,
|
||||
"minValue": 1,
|
||||
@ -495,28 +502,28 @@ async def test_config_entry_with_trigger_accessory(
|
||||
},
|
||||
],
|
||||
"iid": 8,
|
||||
"linked": [12],
|
||||
"linked": [13],
|
||||
"type": "89",
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 13,
|
||||
"iid": 14,
|
||||
"perms": ["pr"],
|
||||
"type": "CD",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1,
|
||||
}
|
||||
],
|
||||
"iid": 12,
|
||||
"iid": 13,
|
||||
"type": "CC",
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 15,
|
||||
"iid": 16,
|
||||
"perms": ["pr", "ev"],
|
||||
"type": "73",
|
||||
"valid-values": [0],
|
||||
@ -524,14 +531,21 @@ async def test_config_entry_with_trigger_accessory(
|
||||
},
|
||||
{
|
||||
"format": "string",
|
||||
"iid": 16,
|
||||
"iid": 17,
|
||||
"perms": ["pr"],
|
||||
"type": "23",
|
||||
"value": "Ceiling Lights Turned Off",
|
||||
},
|
||||
{
|
||||
"format": "string",
|
||||
"iid": 18,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "E3",
|
||||
"value": "Ceiling Lights Turned Off",
|
||||
},
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 17,
|
||||
"iid": 19,
|
||||
"maxValue": 255,
|
||||
"minStep": 1,
|
||||
"minValue": 1,
|
||||
@ -540,29 +554,29 @@ async def test_config_entry_with_trigger_accessory(
|
||||
"value": 2,
|
||||
},
|
||||
],
|
||||
"iid": 14,
|
||||
"linked": [18],
|
||||
"iid": 15,
|
||||
"linked": [20],
|
||||
"type": "89",
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 19,
|
||||
"iid": 21,
|
||||
"perms": ["pr"],
|
||||
"type": "CD",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1,
|
||||
}
|
||||
],
|
||||
"iid": 18,
|
||||
"iid": 20,
|
||||
"type": "CC",
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 21,
|
||||
"iid": 23,
|
||||
"perms": ["pr", "ev"],
|
||||
"type": "73",
|
||||
"valid-values": [0],
|
||||
@ -570,14 +584,21 @@ async def test_config_entry_with_trigger_accessory(
|
||||
},
|
||||
{
|
||||
"format": "string",
|
||||
"iid": 22,
|
||||
"iid": 24,
|
||||
"perms": ["pr"],
|
||||
"type": "23",
|
||||
"value": "Ceiling Lights Turned On",
|
||||
},
|
||||
{
|
||||
"format": "string",
|
||||
"iid": 25,
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"type": "E3",
|
||||
"value": "Ceiling Lights Turned On",
|
||||
},
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 23,
|
||||
"iid": 26,
|
||||
"maxValue": 255,
|
||||
"minStep": 1,
|
||||
"minValue": 1,
|
||||
@ -586,22 +607,22 @@ async def test_config_entry_with_trigger_accessory(
|
||||
"value": 3,
|
||||
},
|
||||
],
|
||||
"iid": 20,
|
||||
"linked": [24],
|
||||
"iid": 22,
|
||||
"linked": [27],
|
||||
"type": "89",
|
||||
},
|
||||
{
|
||||
"characteristics": [
|
||||
{
|
||||
"format": "uint8",
|
||||
"iid": 25,
|
||||
"iid": 28,
|
||||
"perms": ["pr"],
|
||||
"type": "CD",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1,
|
||||
}
|
||||
],
|
||||
"iid": 24,
|
||||
"iid": 27,
|
||||
"type": "CC",
|
||||
},
|
||||
],
|
||||
@ -626,6 +647,7 @@ async def test_config_entry_with_trigger_accessory(
|
||||
"pairing_id": ANY,
|
||||
"status": 1,
|
||||
}
|
||||
|
||||
with (
|
||||
patch("pyhap.accessory_driver.AccessoryDriver.async_start"),
|
||||
patch("homeassistant.components.homekit.HomeKit.async_stop"),
|
||||
|
@ -14,7 +14,13 @@ from homeassistant.components.fan import (
|
||||
DOMAIN as FAN_DOMAIN,
|
||||
FanEntityFeature,
|
||||
)
|
||||
from homeassistant.components.homekit.const import ATTR_VALUE, PROP_MIN_STEP
|
||||
from homeassistant.components.homekit.accessories import HomeDriver
|
||||
from homeassistant.components.homekit.const import (
|
||||
ATTR_VALUE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
PROP_MIN_STEP,
|
||||
SERV_SWITCH,
|
||||
)
|
||||
from homeassistant.components.homekit.type_fans import Fan
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@ -603,7 +609,7 @@ async def test_fan_restore(
|
||||
|
||||
|
||||
async def test_fan_multiple_preset_modes(
|
||||
hass: HomeAssistant, hk_driver, events: list[Event]
|
||||
hass: HomeAssistant, hk_driver: HomeDriver, events: list[Event]
|
||||
) -> None:
|
||||
"""Test fan with multiple preset modes."""
|
||||
entity_id = "fan.demo"
|
||||
@ -623,6 +629,9 @@ async def test_fan_multiple_preset_modes(
|
||||
|
||||
assert acc.preset_mode_chars["auto"].value == 1
|
||||
assert acc.preset_mode_chars["smart"].value == 0
|
||||
switch_service = acc.get_service(SERV_SWITCH)
|
||||
configured_name_char = switch_service.get_characteristic(CHAR_CONFIGURED_NAME)
|
||||
assert configured_name_char.value == "auto"
|
||||
|
||||
acc.run()
|
||||
await hass.async_block_till_done()
|
||||
|
@ -6,6 +6,7 @@ from homeassistant.components.homekit.accessories import HomeDriver
|
||||
from homeassistant.components.homekit.const import (
|
||||
ATTR_KEY_NAME,
|
||||
ATTR_VALUE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_REMOTE_KEY,
|
||||
CONF_FEATURE_LIST,
|
||||
EVENT_HOMEKIT_TV_REMOTE_KEY_PRESSED,
|
||||
@ -14,6 +15,7 @@ from homeassistant.components.homekit.const import (
|
||||
FEATURE_PLAY_STOP,
|
||||
FEATURE_TOGGLE_MUTE,
|
||||
KEY_ARROW_RIGHT,
|
||||
SERV_SWITCH,
|
||||
)
|
||||
from homeassistant.components.homekit.type_media_players import (
|
||||
MediaPlayer,
|
||||
@ -74,6 +76,10 @@ async def test_media_player_set_state(
|
||||
assert acc.aid == 2
|
||||
assert acc.category == 8 # Switch
|
||||
|
||||
switch_service = acc.get_service(SERV_SWITCH)
|
||||
configured_name_char = switch_service.get_characteristic(CHAR_CONFIGURED_NAME)
|
||||
assert configured_name_char.value == "Power"
|
||||
|
||||
assert acc.chars[FEATURE_ON_OFF].value is False
|
||||
assert acc.chars[FEATURE_PLAY_PAUSE].value is False
|
||||
assert acc.chars[FEATURE_PLAY_STOP].value is False
|
||||
|
@ -6,6 +6,8 @@ import pytest
|
||||
|
||||
from homeassistant.components.homekit.const import (
|
||||
ATTR_VALUE,
|
||||
CHAR_CONFIGURED_NAME,
|
||||
SERV_OUTLET,
|
||||
TYPE_FAUCET,
|
||||
TYPE_SHOWER,
|
||||
TYPE_SPRINKLER,
|
||||
@ -568,6 +570,10 @@ async def test_input_select_switch(
|
||||
acc.run()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
switch_service = acc.get_service(SERV_OUTLET)
|
||||
configured_name_char = switch_service.get_characteristic(CHAR_CONFIGURED_NAME)
|
||||
assert configured_name_char.value == "option1"
|
||||
|
||||
assert acc.select_chars["option1"].value is True
|
||||
assert acc.select_chars["option2"].value is False
|
||||
assert acc.select_chars["option3"].value is False
|
||||
|
@ -3,7 +3,11 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.components.device_automation import DeviceAutomationType
|
||||
from homeassistant.components.homekit.const import CHAR_PROGRAMMABLE_SWITCH_EVENT
|
||||
from homeassistant.components.homekit.const import (
|
||||
CHAR_CONFIGURED_NAME,
|
||||
CHAR_PROGRAMMABLE_SWITCH_EVENT,
|
||||
SERV_STATELESS_PROGRAMMABLE_SWITCH,
|
||||
)
|
||||
from homeassistant.components.homekit.type_triggers import DeviceTriggerAccessory
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -55,6 +59,10 @@ async def test_programmable_switch_button_fires_on_trigger(
|
||||
assert acc.device_id is device_id
|
||||
assert acc.available is True
|
||||
|
||||
switch_service = acc.get_service(SERV_STATELESS_PROGRAMMABLE_SWITCH)
|
||||
configured_name_char = switch_service.get_characteristic(CHAR_CONFIGURED_NAME)
|
||||
assert configured_name_char.value == "ceiling lights Changed States"
|
||||
|
||||
hk_driver.publish.reset_mock()
|
||||
hass.states.async_set("light.ceiling_lights", STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
|
Loading…
x
Reference in New Issue
Block a user