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:
@@ -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"]
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -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
|
||||
|
||||
Generated
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user