Resolve homekit not updating motion sensors (#34282)

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>
pull/34319/head
J. Nick Koston 2020-04-16 18:15:37 -05:00 committed by GitHub
parent 97609576cb
commit b87b618c94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 13 deletions

View File

@ -60,16 +60,16 @@ from .util import convert_to_float, density_to_air_quality, temperature_to_homek
_LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_SERVICE_MAP = {
DEVICE_CLASS_CO2: (SERV_CARBON_DIOXIDE_SENSOR, CHAR_CARBON_DIOXIDE_DETECTED),
DEVICE_CLASS_DOOR: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE),
DEVICE_CLASS_GARAGE_DOOR: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE),
DEVICE_CLASS_GAS: (SERV_CARBON_MONOXIDE_SENSOR, CHAR_CARBON_MONOXIDE_DETECTED),
DEVICE_CLASS_MOISTURE: (SERV_LEAK_SENSOR, CHAR_LEAK_DETECTED),
DEVICE_CLASS_MOTION: (SERV_MOTION_SENSOR, CHAR_MOTION_DETECTED),
DEVICE_CLASS_OCCUPANCY: (SERV_OCCUPANCY_SENSOR, CHAR_OCCUPANCY_DETECTED),
DEVICE_CLASS_OPENING: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE),
DEVICE_CLASS_SMOKE: (SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED),
DEVICE_CLASS_WINDOW: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE),
DEVICE_CLASS_CO2: (SERV_CARBON_DIOXIDE_SENSOR, CHAR_CARBON_DIOXIDE_DETECTED, int),
DEVICE_CLASS_DOOR: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE, int),
DEVICE_CLASS_GARAGE_DOOR: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE, int),
DEVICE_CLASS_GAS: (SERV_CARBON_MONOXIDE_SENSOR, CHAR_CARBON_MONOXIDE_DETECTED, int),
DEVICE_CLASS_MOISTURE: (SERV_LEAK_SENSOR, CHAR_LEAK_DETECTED, int),
DEVICE_CLASS_MOTION: (SERV_MOTION_SENSOR, CHAR_MOTION_DETECTED, bool),
DEVICE_CLASS_OCCUPANCY: (SERV_OCCUPANCY_SENSOR, CHAR_OCCUPANCY_DETECTED, int),
DEVICE_CLASS_OPENING: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE, int),
DEVICE_CLASS_SMOKE: (SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED, int),
DEVICE_CLASS_WINDOW: (SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE, int),
}
@ -274,8 +274,12 @@ class BinarySensor(HomeAccessory):
else BINARY_SENSOR_SERVICE_MAP[DEVICE_CLASS_OCCUPANCY]
)
self.format = service_char[2]
service = self.add_preload_service(service_char[0])
self.char_detected = service.configure_char(service_char[1], value=0)
initial_value = False if self.format is bool else 0
self.char_detected = service.configure_char(
service_char[1], value=initial_value
)
# Set the state so it is in sync on initial
# GET to avoid an event storm after homekit startup
self.update_state(state)
@ -283,7 +287,7 @@ class BinarySensor(HomeAccessory):
def update_state(self, new_state):
"""Update accessory after state change."""
state = new_state.state
detected = state in (STATE_ON, STATE_HOME)
detected = self.format(state in (STATE_ON, STATE_HOME))
if self.char_detected.value != detected:
self.char_detected.set_value(detected)
_LOGGER.debug("%s: Set to %d", self.entity_id, detected)

View File

@ -1,6 +1,7 @@
"""Test different accessory types: Sensors."""
from homeassistant.components.homekit import get_accessory
from homeassistant.components.homekit.const import (
DEVICE_CLASS_MOTION,
PROP_CELSIUS,
THRESHOLD_CO,
THRESHOLD_CO2,
@ -256,11 +257,55 @@ async def test_binary(hass, hk_driver):
assert acc.char_detected.value == 0
async def test_motion_uses_bool(hass, hk_driver):
"""Test if accessory is updated after state change."""
entity_id = "binary_sensor.motion"
hass.states.async_set(
entity_id, STATE_UNKNOWN, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}
)
await hass.async_block_till_done()
acc = BinarySensor(hass, hk_driver, "Motion Sensor", entity_id, 2, None)
await acc.run_handler()
assert acc.aid == 2
assert acc.category == 10 # Sensor
assert acc.char_detected.value is False
hass.states.async_set(entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION})
await hass.async_block_till_done()
assert acc.char_detected.value is True
hass.states.async_set(
entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}
)
await hass.async_block_till_done()
assert acc.char_detected.value is False
hass.states.async_set(
entity_id, STATE_HOME, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}
)
await hass.async_block_till_done()
assert acc.char_detected.value is True
hass.states.async_set(
entity_id, STATE_NOT_HOME, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}
)
await hass.async_block_till_done()
assert acc.char_detected.value is False
hass.states.async_remove(entity_id)
await hass.async_block_till_done()
assert acc.char_detected.value is False
async def test_binary_device_classes(hass, hk_driver):
"""Test if services and characteristics are assigned correctly."""
entity_id = "binary_sensor.demo"
for device_class, (service, char) in BINARY_SENSOR_SERVICE_MAP.items():
for device_class, (service, char, _) in BINARY_SENSOR_SERVICE_MAP.items():
hass.states.async_set(entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: device_class})
await hass.async_block_till_done()