mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Avoid retriggering HomeKit doorbells on forced updates (#74141)
This commit is contained in:
parent
ee6866b8a3
commit
629c68221e
@ -14,7 +14,7 @@ from pyhap.const import CATEGORY_CAMERA
|
||||
from homeassistant.components import camera
|
||||
from homeassistant.components.ffmpeg import get_ffmpeg_manager
|
||||
from homeassistant.const import STATE_ON
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import Event, callback
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_state_change_event,
|
||||
async_track_time_interval,
|
||||
@ -56,7 +56,7 @@ from .const import (
|
||||
SERV_SPEAKER,
|
||||
SERV_STATELESS_PROGRAMMABLE_SWITCH,
|
||||
)
|
||||
from .util import pid_is_alive
|
||||
from .util import pid_is_alive, state_changed_event_is_same_state
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -265,8 +265,9 @@ class Camera(HomeAccessory, PyhapCamera):
|
||||
await super().run()
|
||||
|
||||
@callback
|
||||
def _async_update_motion_state_event(self, event):
|
||||
def _async_update_motion_state_event(self, event: Event) -> None:
|
||||
"""Handle state change event listener callback."""
|
||||
if not state_changed_event_is_same_state(event):
|
||||
self._async_update_motion_state(event.data.get("new_state"))
|
||||
|
||||
@callback
|
||||
@ -288,8 +289,9 @@ class Camera(HomeAccessory, PyhapCamera):
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_update_doorbell_state_event(self, event):
|
||||
def _async_update_doorbell_state_event(self, event: Event) -> None:
|
||||
"""Handle state change event listener callback."""
|
||||
if not state_changed_event_is_same_state(event):
|
||||
self._async_update_doorbell_state(event.data.get("new_state"))
|
||||
|
||||
@callback
|
||||
|
@ -37,7 +37,7 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, State, callback, split_entity_id
|
||||
from homeassistant.core import Event, HomeAssistant, State, callback, split_entity_id
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.storage import STORAGE_DIR
|
||||
import homeassistant.util.temperature as temp_util
|
||||
@ -572,3 +572,11 @@ def state_needs_accessory_mode(state: State) -> bool:
|
||||
and state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||
& RemoteEntityFeature.ACTIVITY
|
||||
)
|
||||
|
||||
|
||||
def state_changed_event_is_same_state(event: Event) -> bool:
|
||||
"""Check if a state changed event is the same state."""
|
||||
event_data = event.data
|
||||
old_state: State | None = event_data.get("old_state")
|
||||
new_state: State | None = event_data.get("new_state")
|
||||
return bool(new_state and old_state and new_state.state == old_state.state)
|
||||
|
@ -642,11 +642,15 @@ async def test_camera_with_linked_motion_sensor(hass, run_driver, events):
|
||||
assert char
|
||||
|
||||
assert char.value is True
|
||||
broker = MagicMock()
|
||||
char.broker = broker
|
||||
|
||||
hass.states.async_set(
|
||||
motion_entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(broker.mock_calls) == 2
|
||||
broker.reset_mock()
|
||||
assert char.value is False
|
||||
|
||||
char.set_value(True)
|
||||
@ -654,8 +658,28 @@ async def test_camera_with_linked_motion_sensor(hass, run_driver, events):
|
||||
motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(broker.mock_calls) == 2
|
||||
broker.reset_mock()
|
||||
assert char.value is True
|
||||
|
||||
hass.states.async_set(
|
||||
motion_entity_id,
|
||||
STATE_ON,
|
||||
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION},
|
||||
force_update=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(broker.mock_calls) == 0
|
||||
broker.reset_mock()
|
||||
|
||||
hass.states.async_set(
|
||||
motion_entity_id,
|
||||
STATE_ON,
|
||||
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION, "other": "attr"},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(broker.mock_calls) == 0
|
||||
broker.reset_mock()
|
||||
# Ensure we do not throw when the linked
|
||||
# motion sensor is removed
|
||||
hass.states.async_remove(motion_entity_id)
|
||||
@ -747,7 +771,8 @@ async def test_camera_with_linked_doorbell_sensor(hass, run_driver, events):
|
||||
assert service2
|
||||
char2 = service.get_characteristic(CHAR_PROGRAMMABLE_SWITCH_EVENT)
|
||||
assert char2
|
||||
|
||||
broker = MagicMock()
|
||||
char2.broker = broker
|
||||
assert char2.value is None
|
||||
|
||||
hass.states.async_set(
|
||||
@ -758,9 +783,12 @@ async def test_camera_with_linked_doorbell_sensor(hass, run_driver, events):
|
||||
await hass.async_block_till_done()
|
||||
assert char.value is None
|
||||
assert char2.value is None
|
||||
assert len(broker.mock_calls) == 0
|
||||
|
||||
char.set_value(True)
|
||||
char2.set_value(True)
|
||||
broker.reset_mock()
|
||||
|
||||
hass.states.async_set(
|
||||
doorbell_entity_id,
|
||||
STATE_ON,
|
||||
@ -769,6 +797,31 @@ async def test_camera_with_linked_doorbell_sensor(hass, run_driver, events):
|
||||
await hass.async_block_till_done()
|
||||
assert char.value is None
|
||||
assert char2.value is None
|
||||
assert len(broker.mock_calls) == 2
|
||||
broker.reset_mock()
|
||||
|
||||
hass.states.async_set(
|
||||
doorbell_entity_id,
|
||||
STATE_ON,
|
||||
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY},
|
||||
force_update=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert char.value is None
|
||||
assert char2.value is None
|
||||
assert len(broker.mock_calls) == 0
|
||||
broker.reset_mock()
|
||||
|
||||
hass.states.async_set(
|
||||
doorbell_entity_id,
|
||||
STATE_ON,
|
||||
{ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY, "other": "attr"},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert char.value is None
|
||||
assert char2.value is None
|
||||
assert len(broker.mock_calls) == 0
|
||||
broker.reset_mock()
|
||||
|
||||
# Ensure we do not throw when the linked
|
||||
# doorbell sensor is removed
|
||||
|
Loading…
x
Reference in New Issue
Block a user