diff --git a/homeassistant/components/xiaomi_ble/const.py b/homeassistant/components/xiaomi_ble/const.py index b6a6369e258..1accfd9dc55 100644 --- a/homeassistant/components/xiaomi_ble/const.py +++ b/homeassistant/components/xiaomi_ble/const.py @@ -21,8 +21,15 @@ XIAOMI_BLE_EVENT: Final = "xiaomi_ble_event" EVENT_CLASS_BUTTON: Final = "button" EVENT_CLASS_MOTION: Final = "motion" +BUTTON: Final = "button" +DOUBLE_BUTTON: Final = "double_button" +TRIPPLE_BUTTON: Final = "tripple_button" +MOTION: Final = "motion" + BUTTON_PRESS: Final = "button_press" BUTTON_PRESS_DOUBLE_LONG: Final = "button_press_double_long" +DOUBLE_BUTTON_PRESS_DOUBLE_LONG: Final = "double_button_press_double_long" +TRIPPLE_BUTTON_PRESS_DOUBLE_LONG: Final = "tripple_button_press_double_long" MOTION_DEVICE: Final = "motion_device" diff --git a/homeassistant/components/xiaomi_ble/device_trigger.py b/homeassistant/components/xiaomi_ble/device_trigger.py index a2373da89b4..6d29af9ac11 100644 --- a/homeassistant/components/xiaomi_ble/device_trigger.py +++ b/homeassistant/components/xiaomi_ble/device_trigger.py @@ -21,15 +21,21 @@ from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo from homeassistant.helpers.typing import ConfigType from .const import ( + BUTTON, BUTTON_PRESS, BUTTON_PRESS_DOUBLE_LONG, CONF_SUBTYPE, DOMAIN, + DOUBLE_BUTTON, + DOUBLE_BUTTON_PRESS_DOUBLE_LONG, EVENT_CLASS, EVENT_CLASS_BUTTON, EVENT_CLASS_MOTION, EVENT_TYPE, + MOTION, MOTION_DEVICE, + TRIPPLE_BUTTON, + TRIPPLE_BUTTON_PRESS_DOUBLE_LONG, XIAOMI_BLE_EVENT, ) @@ -39,47 +45,47 @@ TRIGGERS_BY_TYPE = { MOTION_DEVICE: ["motion_detected"], } +EVENT_TYPES = { + BUTTON: ["button"], + DOUBLE_BUTTON: ["button_left", "button_right"], + TRIPPLE_BUTTON: ["button_left", "button_middle", "button_right"], + MOTION: ["motion"], +} + @dataclass class TriggerModelData: """Data class for trigger model data.""" - schema: vol.Schema event_class: str + event_types: list[str] triggers: list[str] TRIGGER_MODEL_DATA = { BUTTON_PRESS: TriggerModelData( - schema=DEVICE_TRIGGER_BASE_SCHEMA.extend( - { - vol.Required(CONF_TYPE): vol.In([EVENT_CLASS_BUTTON]), - vol.Required(CONF_SUBTYPE): vol.In(TRIGGERS_BY_TYPE[BUTTON_PRESS]), - } - ), event_class=EVENT_CLASS_BUTTON, + event_types=EVENT_TYPES[BUTTON], triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS], ), BUTTON_PRESS_DOUBLE_LONG: TriggerModelData( - schema=DEVICE_TRIGGER_BASE_SCHEMA.extend( - { - vol.Required(CONF_TYPE): vol.In([EVENT_CLASS_BUTTON]), - vol.Required(CONF_SUBTYPE): vol.In( - TRIGGERS_BY_TYPE[BUTTON_PRESS_DOUBLE_LONG] - ), - } - ), event_class=EVENT_CLASS_BUTTON, + event_types=EVENT_TYPES[BUTTON], + triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS_DOUBLE_LONG], + ), + DOUBLE_BUTTON_PRESS_DOUBLE_LONG: TriggerModelData( + event_class=EVENT_CLASS_BUTTON, + event_types=EVENT_TYPES[DOUBLE_BUTTON], + triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS_DOUBLE_LONG], + ), + TRIPPLE_BUTTON_PRESS_DOUBLE_LONG: TriggerModelData( + event_class=EVENT_CLASS_BUTTON, + event_types=EVENT_TYPES[TRIPPLE_BUTTON], triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS_DOUBLE_LONG], ), MOTION_DEVICE: TriggerModelData( - schema=DEVICE_TRIGGER_BASE_SCHEMA.extend( - { - vol.Required(CONF_TYPE): vol.In([EVENT_CLASS_MOTION]), - vol.Required(CONF_SUBTYPE): vol.In(TRIGGERS_BY_TYPE[MOTION_DEVICE]), - } - ), event_class=EVENT_CLASS_MOTION, + event_types=EVENT_TYPES[MOTION], triggers=TRIGGERS_BY_TYPE[MOTION_DEVICE], ), } @@ -90,13 +96,13 @@ MODEL_DATA = { "MS1BB(MI)": TRIGGER_MODEL_DATA[BUTTON_PRESS], "RTCGQ02LM": TRIGGER_MODEL_DATA[BUTTON_PRESS], "SJWS01LM": TRIGGER_MODEL_DATA[BUTTON_PRESS], - "K9B-1BTN": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], - "K9B-2BTN": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], - "K9B-3BTN": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], "K9BB-1BTN": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], "YLAI003": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], "XMWXKG01LM": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], - "XMWXKG01YL": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], + "K9B-1BTN": TRIGGER_MODEL_DATA[BUTTON_PRESS_DOUBLE_LONG], + "XMWXKG01YL": TRIGGER_MODEL_DATA[DOUBLE_BUTTON_PRESS_DOUBLE_LONG], + "K9B-2BTN": TRIGGER_MODEL_DATA[DOUBLE_BUTTON_PRESS_DOUBLE_LONG], + "K9B-3BTN": TRIGGER_MODEL_DATA[TRIPPLE_BUTTON_PRESS_DOUBLE_LONG], "MUE4094RT": TRIGGER_MODEL_DATA[MOTION_DEVICE], } @@ -107,7 +113,13 @@ async def async_validate_trigger_config( """Validate trigger config.""" device_id = config[CONF_DEVICE_ID] if model_data := _async_trigger_model_data(hass, device_id): - return model_data.schema(config) # type: ignore[no-any-return] + schema = DEVICE_TRIGGER_BASE_SCHEMA.extend( + { + vol.Required(CONF_TYPE): vol.In(model_data.event_types), + vol.Required(CONF_SUBTYPE): vol.In(model_data.triggers), + } + ) + return schema(config) # type: ignore[no-any-return] return config @@ -120,7 +132,7 @@ async def async_get_triggers( if not (model_data := _async_trigger_model_data(hass, device_id)): return [] - event_type = model_data.event_class + event_types = model_data.event_types event_subtypes = model_data.triggers return [ { @@ -132,6 +144,7 @@ async def async_get_triggers( CONF_TYPE: event_type, CONF_SUBTYPE: event_subtype, } + for event_type in event_types for event_subtype in event_subtypes ] diff --git a/homeassistant/components/xiaomi_ble/strings.json b/homeassistant/components/xiaomi_ble/strings.json index 2017ee674bb..c7cbe43bd94 100644 --- a/homeassistant/components/xiaomi_ble/strings.json +++ b/homeassistant/components/xiaomi_ble/strings.json @@ -48,6 +48,9 @@ }, "trigger_type": { "button": "Button \"{subtype}\"", + "button_left": "Button Left \"{subtype}\"", + "button_middle": "Button Middle \"{subtype}\"", + "button_right": "Button Right \"{subtype}\"", "motion": "{subtype}" } }, diff --git a/tests/components/xiaomi_ble/test_device_trigger.py b/tests/components/xiaomi_ble/test_device_trigger.py index 5c86173ca01..31f896680bf 100644 --- a/tests/components/xiaomi_ble/test_device_trigger.py +++ b/tests/components/xiaomi_ble/test_device_trigger.py @@ -164,8 +164,8 @@ async def test_get_triggers_double_button(hass: HomeAssistant) -> None: CONF_PLATFORM: "device", CONF_DOMAIN: DOMAIN, CONF_DEVICE_ID: device.id, - CONF_TYPE: "button", - CONF_SUBTYPE: "press", + CONF_TYPE: "button_right", + CONF_SUBTYPE: "long_press", "metadata": {}, } triggers = await async_get_device_automations( @@ -334,6 +334,66 @@ async def test_if_fires_on_button_press(hass: HomeAssistant, calls) -> None: await hass.async_block_till_done() +async def test_if_fires_on_double_button_long_press(hass: HomeAssistant, calls) -> None: + """Test for button press event trigger firing.""" + mac = "DC:ED:83:87:12:73" + data = {"bindkey": "b93eb3787eabda352edd94b667f5d5a9"} + entry = await _async_setup_xiaomi_device(hass, mac, data) + + # Emit left button press event so it creates the device in the registry + inject_bluetooth_service_info_bleak( + hass, + make_advertisement( + mac, + b"XYI\x19Ks\x12\x87\x83\xed\xdc!\xad\xb4\xcd\x02\x00\x00,\xf3\xd9\x83", + ), + ) + + # wait for the device being created + await hass.async_block_till_done() + + dev_reg = async_get_dev_reg(hass) + device = dev_reg.async_get_device(identifiers={get_device_id(mac)}) + device_id = device.id + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + CONF_PLATFORM: "device", + CONF_DOMAIN: DOMAIN, + CONF_DEVICE_ID: device_id, + CONF_TYPE: "button_right", + CONF_SUBTYPE: "press", + }, + "action": { + "service": "test.automation", + "data_template": {"some": "test_trigger_right_button_press"}, + }, + }, + ] + }, + ) + # Emit right button press event + inject_bluetooth_service_info_bleak( + hass, + make_advertisement( + mac, + b"XYI\x19Ps\x12\x87\x83\xed\xdc\x13~~\xbe\x02\x00\x00\xf0\\;4", + ), + ) + await hass.async_block_till_done() + + assert len(calls) == 1 + assert calls[0].data["some"] == "test_trigger_right_button_press" + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() + + async def test_if_fires_on_motion_detected(hass: HomeAssistant, calls) -> None: """Test for motion event trigger firing.""" mac = "DE:70:E8:B2:39:0C"