1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Fix jvcprojector entities going unavailable on transient command errors (#168985)

This commit is contained in:
Steve Easley
2026-04-29 03:21:53 -04:00
committed by GitHub
parent acd9dd218a
commit 3dd972cc7a
5 changed files with 64 additions and 6 deletions
@@ -7,7 +7,12 @@ from datetime import timedelta
import logging
from typing import TYPE_CHECKING, Any
from jvcprojector import JvcProjector, JvcProjectorTimeoutError, command as cmd
from jvcprojector import (
JvcProjector,
JvcProjectorCommandError,
JvcProjectorTimeoutError,
command as cmd,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@@ -144,7 +149,16 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
self, command: type[Command], new_state: dict[type[Command], str]
) -> str | None:
"""Update state with the current value of a command."""
value = await self.device.get(command)
try:
value = await self.device.get(command)
except JvcProjectorCommandError as err:
_LOGGER.warning("Command %s failed: %s", command.name, err)
cached = self.state.get(command)
if command is cmd.Power and cached is None:
raise UpdateFailed(
f"Failed to fetch {command.name} and no cached value is available"
) from err
return cached
if value != self.state.get(command):
new_state[command] = value
@@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["jvcprojector"],
"requirements": ["pyjvcprojector==2.0.5"]
"requirements": ["pyjvcprojector==2.0.6"]
}
+1 -1
View File
@@ -2222,7 +2222,7 @@ pyitachip2ir==0.0.7
pyituran==0.1.5
# homeassistant.components.jvc_projector
pyjvcprojector==2.0.5
pyjvcprojector==2.0.6
# homeassistant.components.kaleidescape
pykaleidescape==1.1.5
+1 -1
View File
@@ -1905,7 +1905,7 @@ pyisy==3.4.1
pyituran==0.1.5
# homeassistant.components.jvc_projector
pyjvcprojector==2.0.5
pyjvcprojector==2.0.6
# homeassistant.components.kaleidescape
pykaleidescape==1.1.5
@@ -3,7 +3,11 @@
from datetime import timedelta
from unittest.mock import AsyncMock
from jvcprojector import JvcProjectorTimeoutError, command as cmd
from jvcprojector import (
JvcProjectorCommandError,
JvcProjectorTimeoutError,
command as cmd,
)
import pytest
from homeassistant.components.jvc_projector.coordinator import (
@@ -11,6 +15,7 @@ from homeassistant.components.jvc_projector.coordinator import (
INTERVAL_SLOW,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.util.dt import utcnow
@@ -58,3 +63,42 @@ async def test_coordinator_setup_connect_error(
) -> None:
"""Test coordinator connect error."""
assert mock_integration.state is ConfigEntryState.SETUP_RETRY
@pytest.mark.parametrize(
"mock_device",
[{"fixture_override": {cmd.Power: JvcProjectorCommandError}}],
indirect=True,
)
async def test_coordinator_setup_power_command_error(
hass: HomeAssistant,
mock_device: AsyncMock,
mock_integration: MockConfigEntry,
) -> None:
"""Test coordinator fails setup when Power command errors with no cached value."""
assert mock_integration.state is ConfigEntryState.SETUP_RETRY
@pytest.mark.parametrize(
"mock_device",
[{"fixture_override": {cmd.Input: JvcProjectorCommandError}}],
indirect=True,
)
async def test_coordinator_command_error_keeps_other_entities_available(
hass: HomeAssistant,
mock_device: AsyncMock,
mock_integration: MockConfigEntry,
) -> None:
"""Test a failing command does not take every entity offline."""
assert mock_integration.state is ConfigEntryState.LOADED
coordinator = mock_integration.runtime_data
assert coordinator.last_update_success is True
power = hass.states.get("sensor.jvc_projector_status")
assert power is not None
assert power.state == "on"
light_time = hass.states.get("sensor.jvc_projector_light_time")
assert light_time is not None
assert light_time.state != STATE_UNAVAILABLE