Stop the Hikvision event stream on Home Assistant shutdown (#180873)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Paul Tarjan
2026-08-31 08:51:24 +00:00
committed by Franck Nijhof
co-authored by Claude Opus 5
parent fb26a28312
commit 7051bd5bb6
2 changed files with 49 additions and 3 deletions
+17 -1
View File
@@ -15,9 +15,10 @@ from homeassistant.const import (
CONF_PORT,
CONF_SSL,
CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import Event, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
@@ -142,6 +143,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: HikvisionConfigEntry) ->
# Start the event stream
await hass.async_add_executor_job(camera.start_stream)
async def _async_stop_stream(event: Event) -> None:
await hass.async_add_executor_job(camera.disconnect)
# pyHik's stream thread is non-daemonic and publishes straight into hass, so
# it has to be joined before the event loop closes. Starting it yields, so
# the stop event may already have been fired by the time we get here, and
# listening for it now would never hear it.
if hass.is_stopping:
await hass.async_add_executor_job(camera.disconnect)
raise ConfigEntryNotReady("Home Assistant is stopping")
entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop_stream)
)
# Register the main device before platforms that use via_device
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
+32 -2
View File
@@ -8,8 +8,8 @@ import pytest
import requests
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_SSL
from homeassistant.core import HomeAssistant
from homeassistant.const import CONF_SSL, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import CoreState, HomeAssistant
from . import setup_integration
from .conftest import TEST_HOST, TEST_PASSWORD, TEST_PORT, TEST_USERNAME
@@ -40,6 +40,36 @@ async def test_setup_and_unload_entry(
mock_hikcamera.return_value.disconnect.assert_called_once()
async def test_stream_stopped_on_shutdown(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_hikcamera: MagicMock,
) -> None:
"""Test the event stream thread is joined before the event loop closes."""
await setup_integration(hass, mock_config_entry)
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
await hass.async_block_till_done()
mock_hikcamera.return_value.disconnect.assert_called_once()
async def test_stream_stopped_when_shutdown_starts_during_setup(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_hikcamera: MagicMock,
) -> None:
"""Test the stream is stopped when shutdown begins while setting up."""
hass.set_state(CoreState.stopping)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
mock_hikcamera.return_value.disconnect.assert_called_once()
async def test_setup_entry_with_ssl(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,