mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Add Locks to Xiaomi-BLE (#111156)
This commit is contained in:
parent
e631224372
commit
e91a38eede
@ -42,6 +42,10 @@ BINARY_SENSOR_DESCRIPTIONS = {
|
||||
key=XiaomiBinarySensorDeviceClass.LIGHT,
|
||||
device_class=BinarySensorDeviceClass.LIGHT,
|
||||
),
|
||||
XiaomiBinarySensorDeviceClass.LOCK: BinarySensorEntityDescription(
|
||||
key=XiaomiBinarySensorDeviceClass.LOCK,
|
||||
device_class=BinarySensorDeviceClass.LOCK,
|
||||
),
|
||||
XiaomiBinarySensorDeviceClass.MOISTURE: BinarySensorEntityDescription(
|
||||
key=XiaomiBinarySensorDeviceClass.MOISTURE,
|
||||
device_class=BinarySensorDeviceClass.MOISTURE,
|
||||
@ -62,6 +66,16 @@ BINARY_SENSOR_DESCRIPTIONS = {
|
||||
key=XiaomiBinarySensorDeviceClass.SMOKE,
|
||||
device_class=BinarySensorDeviceClass.SMOKE,
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.ANTILOCK: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.ANTILOCK,
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.ARMED: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.ARMED,
|
||||
icon="mdi:shield-check",
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.CHILDLOCK: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.CHILDLOCK,
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.DEVICE_FORCIBLY_REMOVED: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.DEVICE_FORCIBLY_REMOVED,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
@ -74,6 +88,10 @@ BINARY_SENSOR_DESCRIPTIONS = {
|
||||
key=ExtendedBinarySensorDeviceClass.DOOR_STUCK,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.FINGERPRINT: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.FINGERPRINT,
|
||||
icon="mdi:fingerprint",
|
||||
),
|
||||
ExtendedBinarySensorDeviceClass.KNOCK_ON_THE_DOOR: BinarySensorEntityDescription(
|
||||
key=ExtendedBinarySensorDeviceClass.KNOCK_ON_THE_DOOR,
|
||||
),
|
||||
|
@ -20,13 +20,21 @@ EVENT_PROPERTIES: Final = "event_properties"
|
||||
XIAOMI_BLE_EVENT: Final = "xiaomi_ble_event"
|
||||
|
||||
EVENT_CLASS_BUTTON: Final = "button"
|
||||
EVENT_CLASS_DIMMER: Final = "dimmer"
|
||||
EVENT_CLASS_MOTION: Final = "motion"
|
||||
EVENT_CLASS_CUBE: Final = "cube"
|
||||
EVENT_CLASS_DIMMER: Final = "dimmer"
|
||||
EVENT_CLASS_ERROR: Final = "error"
|
||||
EVENT_CLASS_FINGERPRINT: Final = "fingerprint"
|
||||
EVENT_CLASS_LOCK: Final = "lock"
|
||||
EVENT_CLASS_MOTION: Final = "motion"
|
||||
|
||||
BUTTON: Final = "button"
|
||||
CUBE: Final = "cube"
|
||||
DIMMER: Final = "dimmer"
|
||||
ERROR: Final = "error"
|
||||
FINGERPRINT: Final = "fingerprint"
|
||||
LOCK: Final = "lock"
|
||||
LOCK_FINGERPRINT = "lock_fingerprint"
|
||||
MOTION_DEVICE: Final = "motion_device"
|
||||
DOUBLE_BUTTON: Final = "double_button"
|
||||
TRIPPLE_BUTTON: Final = "tripple_button"
|
||||
REMOTE: Final = "remote"
|
||||
@ -40,7 +48,6 @@ BUTTON_PRESS_LONG: Final = "button_press_long"
|
||||
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"
|
||||
|
||||
|
||||
class XiaomiBleEvent(TypedDict):
|
||||
|
@ -32,12 +32,19 @@ from .const import (
|
||||
DOMAIN,
|
||||
DOUBLE_BUTTON,
|
||||
DOUBLE_BUTTON_PRESS_DOUBLE_LONG,
|
||||
ERROR,
|
||||
EVENT_CLASS,
|
||||
EVENT_CLASS_BUTTON,
|
||||
EVENT_CLASS_CUBE,
|
||||
EVENT_CLASS_DIMMER,
|
||||
EVENT_CLASS_ERROR,
|
||||
EVENT_CLASS_FINGERPRINT,
|
||||
EVENT_CLASS_LOCK,
|
||||
EVENT_CLASS_MOTION,
|
||||
EVENT_TYPE,
|
||||
FINGERPRINT,
|
||||
LOCK,
|
||||
LOCK_FINGERPRINT,
|
||||
MOTION,
|
||||
MOTION_DEVICE,
|
||||
REMOTE,
|
||||
@ -62,6 +69,51 @@ TRIGGERS_BY_TYPE = {
|
||||
"rotate_left_pressed",
|
||||
"rotate_right_pressed",
|
||||
],
|
||||
ERROR: [
|
||||
"frequent_unlocking_with_incorrect_password",
|
||||
"frequent_unlocking_with_wrong_fingerprints",
|
||||
"operation_timeout_password_input_timeout",
|
||||
"lock_picking",
|
||||
"reset_button_is_pressed",
|
||||
"the_wrong_key_is_frequently_unlocked",
|
||||
"foreign_body_in_the_keyhole",
|
||||
"the_key_has_not_been_taken_out",
|
||||
"error_nfc_frequently_unlocks",
|
||||
"timeout_is_not_locked_as_required",
|
||||
"failure_to_unlock_frequently_in_multiple_ways",
|
||||
"unlocking_the_face_frequently_fails",
|
||||
"failure_to_unlock_the_vein_frequently",
|
||||
"hijacking_alarm",
|
||||
"unlock_inside_the_door_after_arming",
|
||||
"palmprints_frequently_fail_to_unlock",
|
||||
"the_safe_was_moved",
|
||||
"the_battery_level_is_less_than_10_percent",
|
||||
"the_battery_level_is_less_than_5_percent",
|
||||
"the_fingerprint_sensor_is_abnormal",
|
||||
"the_accessory_battery_is_low",
|
||||
"mechanical_failure",
|
||||
"the_lock_sensor_is_faulty",
|
||||
],
|
||||
FINGERPRINT: [
|
||||
"match_successful",
|
||||
"match_failed",
|
||||
"low_quality_too_light_fuzzy",
|
||||
"insufficient_area",
|
||||
"skin_is_too_dry",
|
||||
"skin_is_too_wet",
|
||||
],
|
||||
LOCK: [
|
||||
"lock_outside_the_door",
|
||||
"unlock_outside_the_door",
|
||||
"lock_inside_the_door",
|
||||
"unlock_inside_the_door",
|
||||
"locked",
|
||||
"turn_on_antilock",
|
||||
"release_the_antilock",
|
||||
"turn_on_child_lock",
|
||||
"turn_off_child_lock",
|
||||
"abnormal",
|
||||
],
|
||||
MOTION_DEVICE: ["motion_detected"],
|
||||
}
|
||||
|
||||
@ -71,6 +123,10 @@ EVENT_TYPES = {
|
||||
DIMMER: ["dimmer"],
|
||||
DOUBLE_BUTTON: ["button_left", "button_right"],
|
||||
TRIPPLE_BUTTON: ["button_left", "button_middle", "button_right"],
|
||||
ERROR: ["error"],
|
||||
FINGERPRINT: ["fingerprint"],
|
||||
LOCK: ["lock"],
|
||||
MOTION: ["motion"],
|
||||
REMOTE: [
|
||||
"button_on",
|
||||
"button_off",
|
||||
@ -106,7 +162,6 @@ EVENT_TYPES = {
|
||||
"button_increase_wind_speed",
|
||||
"button_decrease_wind_speed",
|
||||
],
|
||||
MOTION: ["motion"],
|
||||
}
|
||||
|
||||
|
||||
@ -150,6 +205,26 @@ TRIGGER_MODEL_DATA = {
|
||||
event_types=EVENT_TYPES[TRIPPLE_BUTTON],
|
||||
triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS_DOUBLE_LONG],
|
||||
),
|
||||
ERROR: TriggerModelData(
|
||||
event_class=EVENT_CLASS_ERROR,
|
||||
event_types=EVENT_TYPES[ERROR],
|
||||
triggers=TRIGGERS_BY_TYPE[ERROR],
|
||||
),
|
||||
LOCK_FINGERPRINT: TriggerModelData(
|
||||
event_class=EVENT_CLASS_FINGERPRINT,
|
||||
event_types=EVENT_TYPES[LOCK] + EVENT_TYPES[FINGERPRINT],
|
||||
triggers=TRIGGERS_BY_TYPE[LOCK] + TRIGGERS_BY_TYPE[FINGERPRINT],
|
||||
),
|
||||
LOCK: TriggerModelData(
|
||||
event_class=EVENT_CLASS_LOCK,
|
||||
event_types=EVENT_TYPES[LOCK],
|
||||
triggers=TRIGGERS_BY_TYPE[LOCK],
|
||||
),
|
||||
MOTION_DEVICE: TriggerModelData(
|
||||
event_class=EVENT_CLASS_MOTION,
|
||||
event_types=EVENT_TYPES[MOTION],
|
||||
triggers=TRIGGERS_BY_TYPE[MOTION_DEVICE],
|
||||
),
|
||||
REMOTE: TriggerModelData(
|
||||
event_class=EVENT_CLASS_BUTTON,
|
||||
event_types=EVENT_TYPES[REMOTE],
|
||||
@ -170,11 +245,6 @@ TRIGGER_MODEL_DATA = {
|
||||
event_types=EVENT_TYPES[REMOTE_VENFAN],
|
||||
triggers=TRIGGERS_BY_TYPE[BUTTON_PRESS_LONG],
|
||||
),
|
||||
MOTION_DEVICE: TriggerModelData(
|
||||
event_class=EVENT_CLASS_MOTION,
|
||||
event_types=EVENT_TYPES[MOTION],
|
||||
triggers=TRIGGERS_BY_TYPE[MOTION_DEVICE],
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@ -197,6 +267,13 @@ MODEL_DATA = {
|
||||
"MUE4094RT": TRIGGER_MODEL_DATA[MOTION_DEVICE],
|
||||
"XMMF01JQD": TRIGGER_MODEL_DATA[CUBE],
|
||||
"YLKG07YL/YLKG08YL": TRIGGER_MODEL_DATA[DIMMER],
|
||||
"DSL-C08": TRIGGER_MODEL_DATA[LOCK],
|
||||
"XMZNMS08LM": TRIGGER_MODEL_DATA[LOCK],
|
||||
"Lockin-SV40": TRIGGER_MODEL_DATA[LOCK_FINGERPRINT],
|
||||
"MJZNMSQ01YD": TRIGGER_MODEL_DATA[LOCK_FINGERPRINT],
|
||||
"XMZNMS04LM": TRIGGER_MODEL_DATA[LOCK_FINGERPRINT],
|
||||
"ZNMS16LM": TRIGGER_MODEL_DATA[LOCK_FINGERPRINT],
|
||||
"ZNMS17LM": TRIGGER_MODEL_DATA[LOCK_FINGERPRINT],
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,9 @@ from .const import (
|
||||
EVENT_CLASS_BUTTON,
|
||||
EVENT_CLASS_CUBE,
|
||||
EVENT_CLASS_DIMMER,
|
||||
EVENT_CLASS_ERROR,
|
||||
EVENT_CLASS_FINGERPRINT,
|
||||
EVENT_CLASS_LOCK,
|
||||
EVENT_CLASS_MOTION,
|
||||
EVENT_PROPERTIES,
|
||||
EVENT_TYPE,
|
||||
@ -59,6 +62,63 @@ DESCRIPTIONS_BY_EVENT_CLASS = {
|
||||
"rotate_right_pressed",
|
||||
],
|
||||
),
|
||||
EVENT_CLASS_ERROR: EventEntityDescription(
|
||||
key=EVENT_CLASS_ERROR,
|
||||
translation_key="error",
|
||||
event_types=[
|
||||
"frequent_unlocking_with_incorrect_password",
|
||||
"frequent_unlocking_with_wrong_fingerprints",
|
||||
"operation_timeout_password_input_timeout",
|
||||
"lock_picking",
|
||||
"reset_button_is_pressed",
|
||||
"the_wrong_key_is_frequently_unlocked",
|
||||
"foreign_body_in_the_keyhole",
|
||||
"the_key_has_not_been_taken_out",
|
||||
"error_nfc_frequently_unlocks",
|
||||
"timeout_is_not_locked_as_required",
|
||||
"failure_to_unlock_frequently_in_multiple_ways",
|
||||
"unlocking_the_face_frequently_fails",
|
||||
"failure_to_unlock_the_vein_frequently",
|
||||
"hijacking_alarm",
|
||||
"unlock_inside_the_door_after_arming",
|
||||
"palmprints_frequently_fail_to_unlock",
|
||||
"the_safe_was_moved",
|
||||
"the_battery_level_is_less_than_10_percent",
|
||||
"the_battery_is_less_than_5_percent",
|
||||
"the_fingerprint_sensor_is_abnormal",
|
||||
"the_accessory_battery_is_low",
|
||||
"mechanical_failure",
|
||||
"the_lock_sensor_is_faulty",
|
||||
],
|
||||
),
|
||||
EVENT_CLASS_FINGERPRINT: EventEntityDescription(
|
||||
key=EVENT_CLASS_FINGERPRINT,
|
||||
translation_key="fingerprint",
|
||||
event_types=[
|
||||
"match_successful",
|
||||
"match_failed",
|
||||
"low_quality_too_light_fuzzy",
|
||||
"insufficient_area",
|
||||
"skin_is_too_dry",
|
||||
"skin_is_too_wet",
|
||||
],
|
||||
),
|
||||
EVENT_CLASS_LOCK: EventEntityDescription(
|
||||
key=EVENT_CLASS_LOCK,
|
||||
translation_key="lock",
|
||||
event_types=[
|
||||
"lock_outside_the_door",
|
||||
"unlock_outside_the_door",
|
||||
"lock_inside_the_door",
|
||||
"unlock_inside_the_door",
|
||||
"locked",
|
||||
"turn_on_antilock",
|
||||
"release_the_antilock",
|
||||
"turn_on_child_lock",
|
||||
"turn_off_child_lock",
|
||||
"abnormal",
|
||||
],
|
||||
),
|
||||
EVENT_CLASS_MOTION: EventEntityDescription(
|
||||
key=EVENT_CLASS_MOTION,
|
||||
translation_key="motion",
|
||||
|
@ -24,5 +24,5 @@
|
||||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/xiaomi_ble",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["xiaomi-ble==0.25.2"]
|
||||
"requirements": ["xiaomi-ble==0.26.1"]
|
||||
}
|
||||
|
@ -132,23 +132,31 @@ SENSOR_DESCRIPTIONS = {
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# Used for e.g. consumable sensor on WX08ZM and M1S-T500
|
||||
# E.g. consumable sensor on WX08ZM and M1S-T500
|
||||
(ExtendedSensorDeviceClass.CONSUMABLE, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=str(ExtendedSensorDeviceClass.CONSUMABLE),
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for score after brushing with a toothbrush
|
||||
# Score after brushing with a toothbrush
|
||||
(ExtendedSensorDeviceClass.SCORE, None): SensorEntityDescription(
|
||||
key=str(ExtendedSensorDeviceClass.SCORE),
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Used for counting during brushing
|
||||
# Counting during brushing
|
||||
(ExtendedSensorDeviceClass.COUNTER, Units.TIME_SECONDS): SensorEntityDescription(
|
||||
key=str(ExtendedSensorDeviceClass.COUNTER),
|
||||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Key id for locks and fingerprint readers
|
||||
(ExtendedSensorDeviceClass.KEY_ID, None): SensorEntityDescription(
|
||||
key=str(ExtendedSensorDeviceClass.KEY_ID), icon="mdi:identifier"
|
||||
),
|
||||
# Lock method for locks
|
||||
(ExtendedSensorDeviceClass.LOCK_METHOD, None): SensorEntityDescription(
|
||||
key=str(ExtendedSensorDeviceClass.LOCK_METHOD), icon="mdi:key-variant"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,7 +48,23 @@
|
||||
"rotate_left": "Rotate Left",
|
||||
"rotate_right": "Rotate Right",
|
||||
"rotate_left_pressed": "Rotate Left (Pressed)",
|
||||
"rotate_right_pressed": "Rotate Right (Pressed)"
|
||||
"rotate_right_pressed": "Rotate Right (Pressed)",
|
||||
"match_successful": "Match successful",
|
||||
"match_failed": "Match failed",
|
||||
"low_quality_too_light_fuzzy": "Low quality (too light, fuzzy)",
|
||||
"insufficient_area": "Insufficient area",
|
||||
"skin_is_too_dry": "Skin is too dry",
|
||||
"skin_is_too_wet": "Skin is too wet",
|
||||
"lock_outside_the_door": "Lock outside the door",
|
||||
"unlock_outside_the_door": "Unlock outside the door",
|
||||
"lock_inside_the_door": "Lock inside the door",
|
||||
"unlock_inside_the_door": "Unlock outside the door",
|
||||
"locked": "Locked",
|
||||
"turn_on_antilock": "Turn on antilock",
|
||||
"release_the_antilock": "Release antilock",
|
||||
"turn_on_child_lock": "Turn on child lock",
|
||||
"turn_off_child_lock": "Turn off child lock",
|
||||
"abnormal": "Abnormal"
|
||||
},
|
||||
"trigger_type": {
|
||||
"button": "Button \"{subtype}\"",
|
||||
@ -79,6 +95,8 @@
|
||||
"button_increase_wind_speed": "Button Increase Wind Speed \"{subtype}\"",
|
||||
"button_decrease_wind_speed": "Button Decrease Wind Speed \"{subtype}\"",
|
||||
"dimmer": "{subtype}",
|
||||
"fingerprint": "{subtype}",
|
||||
"lock": "{subtype}",
|
||||
"motion": "{subtype}",
|
||||
"cube": "{subtype}"
|
||||
}
|
||||
@ -120,6 +138,69 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
"state": {
|
||||
"frequent_unlocking_with_incorrect_password": "Frequent unlocking with incorrect password",
|
||||
"frequent_unlocking_with_wrong_fingerprints": "Frequent unlocking with wrong fingerprints",
|
||||
"operation_timeout_password_input_timeout": "Operation timeout password input timeout",
|
||||
"lock_picking": "Lock picking",
|
||||
"reset_button_is_pressed": "Reset button is pressed",
|
||||
"the_wrong_key_is_frequently_unlocked": "The wrong key is frequently unlocked",
|
||||
"foreign_body_in_the_keyhole": "Foreign body in the keyhole",
|
||||
"the_key_has_not_been_taken_out": "The key has not been taken out",
|
||||
"error_nfc_frequently_unlocks": "Error NFC frequently unlocks",
|
||||
"timeout_is_not_locked_as_required": "Timeout is not locked as required",
|
||||
"failure_to_unlock_frequently_in_multiple_ways": "Failure to unlock frequently in multiple ways",
|
||||
"unlocking_the_face_frequently_fails": "Unlocking the face frequently fails",
|
||||
"failure_to_unlock_the_vein_frequently": "Failure to unlock the vein frequently",
|
||||
"hijacking_alarm": "Hijacking alarm",
|
||||
"unlock_inside_the_door_after_arming": "Unlock inside the door after arming",
|
||||
"palmprints_frequently_fail_to_unlock": "Palmprints frequently fail to unlock",
|
||||
"the_safe_was_moved": "The safe was moved",
|
||||
"the_battery_level_is_less_than_10_percent": "The battery level is less than 10%",
|
||||
"the_battery_level_is_less_than_5_percent": "The battery level is less than 5%",
|
||||
"the_fingerprint_sensor_is_abnormal": "The fingerprint sensor is abnormal",
|
||||
"the_accessory_battery_is_low": "The accessory battery is low",
|
||||
"mechanical_failure": "Mechanical failure",
|
||||
"the_lock_sensor_is_faulty": "The lock sensor is faulty"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fingerprint": {
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
"state": {
|
||||
"match_successful": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::match_successful%]",
|
||||
"match_failed": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::match_failed%]",
|
||||
"low_quality_too_light_fuzzy": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::low_quality_too_light_fuzzy%]",
|
||||
"insufficient_area": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::insufficient_area%]",
|
||||
"skin_is_too_dry": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::skin_is_too_dry%]",
|
||||
"skin_is_too_wet": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::skin_is_too_wet%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lock": {
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
"state": {
|
||||
"lock_outside_the_door": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::lock_outside_the_door%]",
|
||||
"unlock_outside_the_door": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::unlock_outside_the_door%]",
|
||||
"lock_inside_the_door": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::lock_inside_the_door%]",
|
||||
"unlock_inside_the_door": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::unlock_inside_the_door%]",
|
||||
"locked": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::locked%]",
|
||||
"turn_on_antilock": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::turn_on_antilock%]",
|
||||
"release_the_antilock": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::release_the_antilock%]",
|
||||
"turn_on_child_lock": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::turn_on_child_lock%]",
|
||||
"turn_off_child_lock": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::turn_off_child_lock%]",
|
||||
"abnormal": "[%key:component::xiaomi_ble::device_automation::trigger_subtype::abnormal%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"state_attributes": {
|
||||
"event_type": {
|
||||
|
@ -2866,7 +2866,7 @@ wyoming==1.5.3
|
||||
xbox-webapi==2.0.11
|
||||
|
||||
# homeassistant.components.xiaomi_ble
|
||||
xiaomi-ble==0.25.2
|
||||
xiaomi-ble==0.26.1
|
||||
|
||||
# homeassistant.components.knx
|
||||
xknx==2.12.2
|
||||
|
@ -2204,7 +2204,7 @@ wyoming==1.5.3
|
||||
xbox-webapi==2.0.11
|
||||
|
||||
# homeassistant.components.xiaomi_ble
|
||||
xiaomi-ble==0.25.2
|
||||
xiaomi-ble==0.26.1
|
||||
|
||||
# homeassistant.components.knx
|
||||
xknx==2.12.2
|
||||
|
@ -75,6 +75,58 @@ async def test_event_button_press(hass: HomeAssistant) -> None:
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_event_unlock_outside_the_door(hass: HomeAssistant) -> None:
|
||||
"""Make sure that a unlock outside the door event is fired."""
|
||||
mac = "D7:1F:44:EB:8A:91"
|
||||
entry = await _async_setup_xiaomi_device(hass, mac)
|
||||
events = async_capture_events(hass, "xiaomi_ble_event")
|
||||
|
||||
# Emit button press event
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
mac,
|
||||
b"PD\x9e\x06C\x91\x8a\xebD\x1f\xd7\x0b\x00\t" b" \x02\x00\x01\x80|D/a",
|
||||
),
|
||||
)
|
||||
|
||||
# wait for the event
|
||||
await hass.async_block_till_done()
|
||||
assert len(events) == 1
|
||||
assert events[0].data["address"] == "D7:1F:44:EB:8A:91"
|
||||
assert events[0].data["event_type"] == "unlock_outside_the_door"
|
||||
assert events[0].data["event_properties"] is None
|
||||
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_event_successful_fingerprint_match_the_door(hass: HomeAssistant) -> None:
|
||||
"""Make sure that a successful fingerprint match event is fired."""
|
||||
mac = "D7:1F:44:EB:8A:91"
|
||||
entry = await _async_setup_xiaomi_device(hass, mac)
|
||||
events = async_capture_events(hass, "xiaomi_ble_event")
|
||||
|
||||
# Emit button press event
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
mac,
|
||||
b"PD\x9e\x06B\x91\x8a\xebD\x1f\xd7" b"\x06\x00\x05\xff\xff\xff\xff\x00",
|
||||
),
|
||||
)
|
||||
|
||||
# wait for the event
|
||||
await hass.async_block_till_done()
|
||||
assert len(events) == 1
|
||||
assert events[0].data["address"] == "D7:1F:44:EB:8A:91"
|
||||
assert events[0].data["event_type"] == "match_successful"
|
||||
assert events[0].data["event_properties"] is None
|
||||
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_event_motion_detected(hass: HomeAssistant) -> None:
|
||||
"""Make sure that a motion detected event is fired."""
|
||||
mac = "DE:70:E8:B2:39:0C"
|
||||
@ -204,6 +256,47 @@ async def test_get_triggers_double_button(hass: HomeAssistant) -> None:
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_get_triggers_lock(hass: HomeAssistant) -> None:
|
||||
"""Test that we get the expected triggers from a Xiaomi BLE lock with fingerprint scanner."""
|
||||
mac = "98:0C:33:A3:04:3D"
|
||||
data = {"bindkey": "54d84797cb77f9538b224b305c877d1e"}
|
||||
entry = await _async_setup_xiaomi_device(hass, mac, data)
|
||||
events = async_capture_events(hass, "xiaomi_ble_event")
|
||||
|
||||
# Emit unlock inside the door event so it creates the device in the registry
|
||||
inject_bluetooth_service_info_bleak(
|
||||
hass,
|
||||
make_advertisement(
|
||||
mac,
|
||||
b"\x48\x55\xc2\x11\x16\x50\x68\xb6\xfe\x3c\x87"
|
||||
b"\x80\x95\xc8\xa5\x83\x4f\x00\x00\x00\x46\x32\x21\xc6",
|
||||
),
|
||||
)
|
||||
|
||||
# wait for the event
|
||||
await hass.async_block_till_done()
|
||||
assert len(events) == 1
|
||||
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = dev_reg.async_get_device(identifiers={get_device_id(mac)})
|
||||
assert device
|
||||
expected_trigger = {
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_DEVICE_ID: device.id,
|
||||
CONF_TYPE: "fingerprint",
|
||||
CONF_SUBTYPE: "skin_is_too_dry",
|
||||
"metadata": {},
|
||||
}
|
||||
triggers = await async_get_device_automations(
|
||||
hass, DeviceAutomationType.TRIGGER, device.id
|
||||
)
|
||||
assert expected_trigger in triggers
|
||||
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_get_triggers_motion(hass: HomeAssistant) -> None:
|
||||
"""Test that we get the expected triggers from a Xiaomi BLE motion sensor."""
|
||||
mac = "DE:70:E8:B2:39:0C"
|
||||
|
@ -4,7 +4,7 @@ import pytest
|
||||
|
||||
from homeassistant.components.event import ATTR_EVENT_TYPE
|
||||
from homeassistant.components.xiaomi_ble.const import DOMAIN
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, STATE_UNAVAILABLE
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, STATE_ON, STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import make_advertisement
|
||||
@ -202,3 +202,94 @@ async def test_events(
|
||||
assert attributes[ATTR_EVENT_TYPE] == meas[ATTR_EVENT_TYPE]
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_xiaomi_fingerprint(hass: HomeAssistant) -> None:
|
||||
"""Make sure that fingerprint reader events are correctly mapped."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="D7:1F:44:EB:8A:91",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
inject_bluetooth_service_info(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"D7:1F:44:EB:8A:91",
|
||||
b"PD\x9e\x06B\x91\x8a\xebD\x1f\xd7" b"\x06\x00\x05\xff\xff\xff\xff\x00",
|
||||
),
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 3
|
||||
|
||||
sensor = hass.states.get("sensor.door_lock_8a91_key_id")
|
||||
sensor_attr = sensor.attributes
|
||||
assert sensor.state == "unknown operator"
|
||||
assert sensor_attr[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Key id"
|
||||
|
||||
binary_sensor = hass.states.get("binary_sensor.door_lock_8a91_fingerprint")
|
||||
binary_sensor_attribtes = binary_sensor.attributes
|
||||
assert binary_sensor.state == STATE_ON
|
||||
assert binary_sensor_attribtes[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Fingerprint"
|
||||
|
||||
event = hass.states.get("event.door_lock_8a91_fingerprint")
|
||||
event_attr = event.attributes
|
||||
assert event_attr[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Fingerprint"
|
||||
assert event_attr[ATTR_EVENT_TYPE] == "match_successful"
|
||||
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_xiaomi_lock(hass: HomeAssistant) -> None:
|
||||
"""Make sure that lock events are correctly mapped."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="D7:1F:44:EB:8A:91",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
|
||||
inject_bluetooth_service_info(
|
||||
hass,
|
||||
make_advertisement(
|
||||
"D7:1F:44:EB:8A:91",
|
||||
b"PD\x9e\x06C\x91\x8a\xebD\x1f\xd7\x0b\x00\t" b" \x02\x00\x01\x80|D/a",
|
||||
),
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 4
|
||||
|
||||
event = hass.states.get("event.door_lock_8a91_lock")
|
||||
event_attr = event.attributes
|
||||
assert event_attr[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Lock"
|
||||
assert event_attr[ATTR_EVENT_TYPE] == "unlock_outside_the_door"
|
||||
|
||||
sensor = hass.states.get("sensor.door_lock_8a91_lock_method")
|
||||
sensor_attr = sensor.attributes
|
||||
assert sensor.state == "biometrics"
|
||||
assert sensor_attr[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Lock method"
|
||||
|
||||
sensor = hass.states.get("sensor.door_lock_8a91_key_id")
|
||||
sensor_attr = sensor.attributes
|
||||
assert sensor.state == "Fingerprint key id 2"
|
||||
assert sensor_attr[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Key id"
|
||||
|
||||
binary_sensor = hass.states.get("binary_sensor.door_lock_8a91_lock")
|
||||
binary_sensor_attribtes = binary_sensor.attributes
|
||||
assert binary_sensor.state == STATE_ON
|
||||
assert binary_sensor_attribtes[ATTR_FRIENDLY_NAME] == "Door Lock 8A91 Lock"
|
||||
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
Loading…
x
Reference in New Issue
Block a user