mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 09:23:17 -04:00
Add new sensors and controls to JVC Projector integration (#181471)
This commit is contained in:
@@ -14,9 +14,10 @@ from jvcprojector import (
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import NAME
|
||||
from .const import DOMAIN, NAME
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from jvcprojector import Command
|
||||
@@ -32,6 +33,7 @@ CORE_COMMANDS: tuple[type[Command], ...] = (
|
||||
cmd.Signal,
|
||||
cmd.Input,
|
||||
cmd.LightTime,
|
||||
cmd.Version,
|
||||
)
|
||||
|
||||
TRANSLATIONS = str.maketrans({"+": "p", "%": "p", ":": "x"})
|
||||
@@ -69,6 +71,19 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
|
||||
|
||||
self.state: dict[type[Command], str] = {}
|
||||
|
||||
@property
|
||||
def software_version(self) -> str | None:
|
||||
"""Return the formatted software version, if it has been cached."""
|
||||
value = self.state.get(cmd.Version)
|
||||
if not value:
|
||||
return None
|
||||
|
||||
try:
|
||||
value = value.removesuffix("PJ").zfill(4)
|
||||
return f"{int(value[:2])}.{value[2:]}"
|
||||
except ValueError, IndexError:
|
||||
return value
|
||||
|
||||
@override
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update state with the current value of a command."""
|
||||
@@ -89,7 +104,7 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
|
||||
else:
|
||||
raise UpdateFailed(str(last_timeout)) from last_timeout
|
||||
|
||||
# Clear state on signal loss
|
||||
# Clear state on signal loss, but keep LightTime and Version
|
||||
if (
|
||||
new_state.get(cmd.Signal) == cmd.Signal.NONE
|
||||
and self.state.get(cmd.Signal) != cmd.Signal.NONE
|
||||
@@ -105,8 +120,22 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
|
||||
else:
|
||||
self.update_interval = INTERVAL_SLOW
|
||||
|
||||
self._update_device_registry()
|
||||
|
||||
return {k.name: v for k, v in self.state.items()}
|
||||
|
||||
def _update_device_registry(self) -> None:
|
||||
"""Update the device registry with the cached software version."""
|
||||
if (software_version := self.software_version) is None:
|
||||
return
|
||||
|
||||
device_registry = dr.async_get(self.hass)
|
||||
device = device_registry.async_get_device_by_identifier(
|
||||
(DOMAIN, self.unique_id), self.config_entry.entry_id
|
||||
)
|
||||
if device is not None and device.sw_version != software_version:
|
||||
device_registry.async_update_device(device.id, sw_version=software_version)
|
||||
|
||||
async def _get_device_state(
|
||||
self, commands: set[type[Command]]
|
||||
) -> dict[type[Command], str]:
|
||||
@@ -143,6 +172,14 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
|
||||
elif self.state.get(cmd.Signal) != cmd.Signal.NONE:
|
||||
new_state[cmd.Signal] = cmd.Signal.NONE
|
||||
|
||||
# Fetch software version once while the projector is on and use the
|
||||
# cached value for device info. A timeout must not prevent setup.
|
||||
if power == cmd.Power.ON and cmd.Version not in self.state:
|
||||
try:
|
||||
await self._update_command_state(cmd.Version, new_state)
|
||||
except JvcProjectorTimeoutError:
|
||||
_LOGGER.debug("Command %s timed out; will retry", cmd.Version.name)
|
||||
|
||||
return new_state
|
||||
|
||||
async def _update_command_state(
|
||||
|
||||
@@ -36,6 +36,7 @@ class JvcProjectorEntity(CoordinatorEntity[JvcProjectorDataUpdateCoordinator]):
|
||||
name=NAME,
|
||||
model=self.device.model,
|
||||
manufacturer=MANUFACTURER,
|
||||
sw_version=coordinator.software_version,
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@@ -22,40 +22,55 @@ class JvcProjectorSelectDescription(SelectEntityDescription):
|
||||
|
||||
|
||||
SELECTS: Final[tuple[JvcProjectorSelectDescription, ...]] = (
|
||||
JvcProjectorSelectDescription(key="input", command=cmd.Input),
|
||||
JvcProjectorSelectDescription(
|
||||
key="input", translation_key="input", command=cmd.Input
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="installation_mode",
|
||||
translation_key="installation_mode",
|
||||
command=cmd.InstallationMode,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="light_power",
|
||||
translation_key="light_power",
|
||||
command=cmd.LightPower,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="dynamic_control",
|
||||
translation_key="dynamic_control",
|
||||
command=cmd.DynamicControl,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="clear_motion_drive",
|
||||
translation_key="clear_motion_drive",
|
||||
command=cmd.ClearMotionDrive,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="motion_enhance",
|
||||
translation_key="motion_enhance",
|
||||
command=cmd.MotionEnhance,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="anamorphic",
|
||||
translation_key="anamorphic",
|
||||
command=cmd.Anamorphic,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="hdr_processing",
|
||||
translation_key="hdr_processing",
|
||||
command=cmd.HdrProcessing,
|
||||
entity_registry_enabled_default=False,
|
||||
snake_case_states=True,
|
||||
),
|
||||
JvcProjectorSelectDescription(
|
||||
key="picture_mode",
|
||||
translation_key="picture_mode",
|
||||
command=cmd.PictureMode,
|
||||
entity_registry_enabled_default=False,
|
||||
snake_case_states=True,
|
||||
@@ -91,7 +106,7 @@ class JvcProjectorSelectEntity(JvcProjectorEntity, SelectEntity):
|
||||
self.command: type[Command] = description.command
|
||||
|
||||
self.entity_description = description
|
||||
self._attr_translation_key = description.key
|
||||
self._attr_translation_key = description.translation_key
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
|
||||
|
||||
self._options_map: dict[str, str] = coordinator.get_options_map(
|
||||
|
||||
@@ -31,11 +31,13 @@ class JvcProjectorSensorDescription(SensorEntityDescription):
|
||||
SENSORS: tuple[JvcProjectorSensorDescription, ...] = (
|
||||
JvcProjectorSensorDescription(
|
||||
key="power",
|
||||
translation_key="power",
|
||||
command=cmd.Power,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="light_time",
|
||||
translation_key="light_time",
|
||||
command=cmd.LightTime,
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -43,6 +45,7 @@ SENSORS: tuple[JvcProjectorSensorDescription, ...] = (
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="color_depth",
|
||||
translation_key="color_depth",
|
||||
command=cmd.ColorDepth,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -50,6 +53,7 @@ SENSORS: tuple[JvcProjectorSensorDescription, ...] = (
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="color_space",
|
||||
translation_key="color_space",
|
||||
command=cmd.ColorSpace,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -57,13 +61,17 @@ SENSORS: tuple[JvcProjectorSensorDescription, ...] = (
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="hdr",
|
||||
translation_key="hdr",
|
||||
command=cmd.Hdr,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
# Keep these entities available for existing installations while they are
|
||||
# migrated to the equivalent select entities.
|
||||
JvcProjectorSensorDescription(
|
||||
key="hdr_processing",
|
||||
translation_key="hdr_processing",
|
||||
command=cmd.HdrProcessing,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -71,11 +79,36 @@ SENSORS: tuple[JvcProjectorSensorDescription, ...] = (
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="picture_mode",
|
||||
translation_key="picture_mode",
|
||||
command=cmd.PictureMode,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="resolution",
|
||||
translation_key="resolution",
|
||||
command=cmd.Source,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="colorimetry",
|
||||
translation_key="colorimetry",
|
||||
command=cmd.Colorimetry,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSensorDescription(
|
||||
key="link_rate",
|
||||
translation_key="link_rate",
|
||||
command=cmd.LinkRate,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -124,7 +157,7 @@ class JvcProjectorSensorEntity(JvcProjectorEntity, SensorEntity):
|
||||
self.command: type[Command] = description.command
|
||||
|
||||
self.entity_description = description
|
||||
self._attr_translation_key = description.key
|
||||
self._attr_translation_key = description.translation_key
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
|
||||
|
||||
self._options_map: dict[str, str] = {}
|
||||
|
||||
@@ -109,6 +109,14 @@
|
||||
"normal": "[%key:common::state::normal%]"
|
||||
}
|
||||
},
|
||||
"motion_enhance": {
|
||||
"name": "Motion Enhance",
|
||||
"state": {
|
||||
"high": "[%key:common::state::high%]",
|
||||
"low": "[%key:common::state::low%]",
|
||||
"off": "[%key:common::state::off%]"
|
||||
}
|
||||
},
|
||||
"picture_mode": {
|
||||
"name": "Picture Mode",
|
||||
"state": {
|
||||
@@ -147,6 +155,25 @@
|
||||
"yuv": "YUV"
|
||||
}
|
||||
},
|
||||
"colorimetry": {
|
||||
"name": "Colorimetry",
|
||||
"state": {
|
||||
"adobe-rgb": "Adobe RGB",
|
||||
"adobe-ycc-601": "Adobe YCC 601",
|
||||
"bt-2020-constant-luminance": "BT.2020 Constant Luminance",
|
||||
"bt-2020-non-constant-luminance": "BT.2020 Non-Constant Luminance",
|
||||
"bt-601": "BT.601",
|
||||
"bt-709": "BT.709",
|
||||
"dci-p3-d65": "DCI-P3 D65",
|
||||
"dci-p3-theater": "DCI-P3 Theater",
|
||||
"no-data": "No Data",
|
||||
"other": "Other",
|
||||
"srgb": "sRGB",
|
||||
"sycc-601": "sYCC 601",
|
||||
"xvycc-601": "xvYCC 601",
|
||||
"xvycc-709": "xvYCC 709"
|
||||
}
|
||||
},
|
||||
"hdr": {
|
||||
"name": "HDR",
|
||||
"state": {
|
||||
@@ -170,6 +197,17 @@
|
||||
"light_time": {
|
||||
"name": "Light Time"
|
||||
},
|
||||
"link_rate": {
|
||||
"name": "Link Rate",
|
||||
"state": {
|
||||
"3-gbps-3-lanes": "3 Gbps 3 Lanes",
|
||||
"6-gbps-3-lanes": "6 Gbps 3 Lanes",
|
||||
"6-gbps-4-lanes": "6 Gbps 4 Lanes",
|
||||
"8-gbps-4-lanes": "8 Gbps 4 Lanes",
|
||||
"10-gbps-4-lanes": "10 Gbps 4 Lanes",
|
||||
"disable": "Disabled"
|
||||
}
|
||||
},
|
||||
"picture_mode": {
|
||||
"name": "Picture Mode",
|
||||
"state": {
|
||||
@@ -196,6 +234,75 @@
|
||||
"standby": "[%key:common::state::standby%]",
|
||||
"warming": "Warming"
|
||||
}
|
||||
},
|
||||
"resolution": {
|
||||
"name": "Resolution",
|
||||
"state": {
|
||||
"4k": "4K",
|
||||
"4k-3840-24": "4K 3840 24 Hz",
|
||||
"4k-3840-25": "4K 3840 25 Hz",
|
||||
"4k-3840-30": "4K 3840 30 Hz",
|
||||
"4k-3840-50": "4K 3840 50 Hz",
|
||||
"4k-3840-60": "4K 3840 60 Hz",
|
||||
"4k-4096-24": "4K 4096 24 Hz",
|
||||
"4k-4096-25": "4K 4096 25 Hz",
|
||||
"4k-4096-30": "4K 4096 30 Hz",
|
||||
"4k-4096-50": "4K 4096 50 Hz",
|
||||
"4k-4096-60": "4K 4096 60 Hz",
|
||||
"8k-7680x4320-24": "8K 7680x4320 24 Hz",
|
||||
"8k-7680x4320-25": "8K 7680x4320 25 Hz",
|
||||
"8k-7680x4320-30": "8K 7680x4320 30 Hz",
|
||||
"8k-7680x4320-48": "8K 7680x4320 48 Hz",
|
||||
"8k-7680x4320-50": "8K 7680x4320 50 Hz",
|
||||
"8k-7680x4320-60": "8K 7680x4320 60 Hz",
|
||||
"480i": "480i",
|
||||
"480p": "480p",
|
||||
"576i": "576i",
|
||||
"576p": "576p",
|
||||
"720p-3d": "720p 3D",
|
||||
"720p-50": "720p 50 Hz",
|
||||
"720p-60": "720p 60 Hz",
|
||||
"1080i-3d": "1080i 3D",
|
||||
"1080i-50": "1080i 50 Hz",
|
||||
"1080i-60": "1080i 60 Hz",
|
||||
"1080p-100": "1080p 100 Hz",
|
||||
"1080p-120": "1080p 120 Hz",
|
||||
"1080p-24": "1080p 24 Hz",
|
||||
"1080p-25": "1080p 25 Hz",
|
||||
"1080p-30": "1080p 30 Hz",
|
||||
"1080p-3d": "1080p 3D",
|
||||
"1080p-50": "1080p 50 Hz",
|
||||
"1080p-60": "1080p 60 Hz",
|
||||
"2048x1080-p24": "2048x1080 24 Hz",
|
||||
"2048x1080-p25": "2048x1080 25 Hz",
|
||||
"2048x1080-p30": "2048x1080 30 Hz",
|
||||
"2048x1080-p50": "2048x1080 50 Hz",
|
||||
"2048x1080-p60": "2048x1080 60 Hz",
|
||||
"3840x1080-p50": "3840x1080 50 Hz",
|
||||
"3840x1080-p60": "3840x1080 60 Hz",
|
||||
"3840x2160-100hz": "3840x2160 100 Hz",
|
||||
"3840x2160-p120": "3840x2160 120 Hz",
|
||||
"4096x2160-100hz": "4096x2160 100 Hz",
|
||||
"4096x2160-p120": "4096x2160 120 Hz",
|
||||
"fwxga-1366x768": "FWXGA 1366x768",
|
||||
"no-signal": "No Signal",
|
||||
"out-of-range": "Out of Range",
|
||||
"qxga": "QXGA",
|
||||
"svga-800x600": "SVGA 800x600",
|
||||
"sxga-1280x1024": "SXGA 1280x1024",
|
||||
"uxga-1600x1200": "UXGA 1600x1200",
|
||||
"vga-640x480": "VGA 640x480",
|
||||
"wqhd-120": "WQHD 120 Hz",
|
||||
"wqhd-60": "WQHD 60 Hz",
|
||||
"wqxga": "WQXGA",
|
||||
"wsxgap1680x1050": "WSXGA+ 1680x1050",
|
||||
"wuxga-1920x1200": "WUXGA 1920x1200",
|
||||
"wxga-1280x768": "WXGA 1280x768",
|
||||
"wxga-1280x800": "WXGA 1280x800",
|
||||
"wxgap1440x900": "WXGA+ 1440x900",
|
||||
"wxgapp1600x900": "WXGA++ 1600x900",
|
||||
"xga-1024x768": "XGA 1024x768"
|
||||
}
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
||||
@@ -24,11 +24,13 @@ class JvcProjectorSwitchDescription(SwitchEntityDescription):
|
||||
SWITCHES: Final[tuple[JvcProjectorSwitchDescription, ...]] = (
|
||||
JvcProjectorSwitchDescription(
|
||||
key="low_latency_mode",
|
||||
translation_key="low_latency_mode",
|
||||
command=cmd.LowLatencyMode,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
JvcProjectorSwitchDescription(
|
||||
key="eshift",
|
||||
translation_key="eshift",
|
||||
command=cmd.EShift,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
@@ -63,7 +65,7 @@ class JvcProjectorSwitchEntity(JvcProjectorEntity, SwitchEntity):
|
||||
self.command: type[Command] = description.command
|
||||
|
||||
self.entity_description = description
|
||||
self._attr_translation_key = description.key
|
||||
self._attr_translation_key = description.translation_key
|
||||
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
|
||||
|
||||
@property
|
||||
|
||||
@@ -23,6 +23,7 @@ FIXTURES: dict[str, dict[type[Command], str | type[Exception]]] = {
|
||||
cmd.Input: "hdmi1",
|
||||
cmd.Signal: "none",
|
||||
cmd.LightTime: "100",
|
||||
cmd.Version: "0301PJ",
|
||||
cmd.Source: JvcProjectorTimeoutError,
|
||||
cmd.Hdr: JvcProjectorTimeoutError,
|
||||
cmd.HdrProcessing: JvcProjectorTimeoutError,
|
||||
@@ -35,7 +36,10 @@ FIXTURES: dict[str, dict[type[Command], str | type[Exception]]] = {
|
||||
cmd.Input: "hdmi1",
|
||||
cmd.Signal: "signal",
|
||||
cmd.LightTime: "100",
|
||||
cmd.Version: "0301PJ",
|
||||
cmd.Source: "4k",
|
||||
cmd.Colorimetry: "bt-709",
|
||||
cmd.LinkRate: "6-gbps-4-lanes",
|
||||
cmd.Hdr: "hdr",
|
||||
cmd.HdrProcessing: "static",
|
||||
cmd.EShift: "on",
|
||||
@@ -59,6 +63,14 @@ CAPABILITIES = {
|
||||
"name": cmd.Source.name,
|
||||
"parameter": {"read": {"0": "4k"}},
|
||||
},
|
||||
cmd.Colorimetry.name: {
|
||||
"name": cmd.Colorimetry.name,
|
||||
"parameter": {"read": {"0": "no-data", "2": "bt-709"}},
|
||||
},
|
||||
cmd.LinkRate.name: {
|
||||
"name": cmd.LinkRate.name,
|
||||
"parameter": {"read": {"0": "disable", "4": "6-gbps-4-lanes"}},
|
||||
},
|
||||
cmd.Hdr.name: {
|
||||
"name": cmd.Hdr.name,
|
||||
"parameter": {"read": {"0": "sdr", "1": "hdr"}},
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
'name': 'JVC Projector',
|
||||
'name_by_user': None,
|
||||
'serial_number': None,
|
||||
'sw_version': None,
|
||||
'sw_version': '3.01',
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -10,6 +10,7 @@ from jvcprojector import (
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.jvc_projector.const import DOMAIN
|
||||
from homeassistant.components.jvc_projector.coordinator import (
|
||||
INTERVAL_FAST,
|
||||
INTERVAL_SLOW,
|
||||
@@ -17,8 +18,12 @@ from homeassistant.components.jvc_projector.coordinator import (
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from . import MOCK_MAC
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
@@ -102,3 +107,44 @@ async def test_coordinator_command_error_keeps_other_entities_available(
|
||||
light_time = hass.states.get("sensor.jvc_projector_light_time")
|
||||
assert light_time is not None
|
||||
assert light_time.state != STATE_UNAVAILABLE
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device",
|
||||
[{"fixture_override": {cmd.Version: JvcProjectorTimeoutError}}],
|
||||
indirect=True,
|
||||
)
|
||||
async def test_coordinator_version_timeout_recovers_and_updates_device(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mock_device: AsyncMock,
|
||||
mock_integration: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test a version timeout does not prevent setup and later recovers."""
|
||||
assert mock_integration.state is ConfigEntryState.LOADED
|
||||
|
||||
initial_get = mock_device.get.side_effect
|
||||
|
||||
async def recover_version(command) -> str:
|
||||
if command is cmd.Version:
|
||||
return "0301PJ"
|
||||
return await initial_get(command)
|
||||
|
||||
mock_device.get.side_effect = recover_version
|
||||
|
||||
device = device_registry.async_get_device_by_identifier(
|
||||
(DOMAIN, format_mac(MOCK_MAC)), mock_integration.entry_id
|
||||
)
|
||||
assert device is not None
|
||||
assert device.sw_version is None
|
||||
|
||||
async_fire_time_changed(
|
||||
hass, utcnow() + timedelta(seconds=INTERVAL_FAST.seconds + 1)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
device = device_registry.async_get_device_by_identifier(
|
||||
(DOMAIN, format_mac(MOCK_MAC)), mock_integration.entry_id
|
||||
)
|
||||
assert device is not None
|
||||
assert device.sw_version == "3.01"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from jvcprojector import command as cmd
|
||||
from jvcprojector import Command, command as cmd
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
@@ -13,6 +14,38 @@ POWER_ID = "sensor.jvc_projector_status"
|
||||
HDR_ENTITY_ID = "sensor.jvc_projector_hdr"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_id", "expected_state"),
|
||||
[
|
||||
("sensor.jvc_projector_resolution", "4k"),
|
||||
("sensor.jvc_projector_colorimetry", "bt-709"),
|
||||
("sensor.jvc_projector_link_rate", "6-gbps-4-lanes"),
|
||||
],
|
||||
)
|
||||
async def test_diagnostic_sensor_state(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_device: MagicMock,
|
||||
mock_integration: MockConfigEntry,
|
||||
entity_id: str,
|
||||
expected_state: str,
|
||||
) -> None:
|
||||
"""Test diagnostic sensor state and disabled-by-default behavior."""
|
||||
entry = entity_registry.async_get(entity_id)
|
||||
assert entry is not None
|
||||
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
|
||||
|
||||
entity_registry.async_update_entity(entity_id, disabled_by=None)
|
||||
await hass.config_entries.async_reload(mock_integration.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await mock_integration.runtime_data.async_refresh()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
assert state.state == expected_state
|
||||
|
||||
|
||||
async def test_entity_state(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
@@ -50,17 +83,29 @@ async def test_enable_hdr_sensor(
|
||||
assert state is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("unsupported_command", "entity_id"),
|
||||
[
|
||||
(cmd.Source, "sensor.jvc_projector_resolution"),
|
||||
(cmd.Colorimetry, "sensor.jvc_projector_colorimetry"),
|
||||
(cmd.LinkRate, "sensor.jvc_projector_link_rate"),
|
||||
],
|
||||
)
|
||||
async def test_unsupported_sensor_not_added(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_device: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
unsupported_command: type[Command],
|
||||
entity_id: str,
|
||||
) -> None:
|
||||
"""Test unsupported sensor descriptions are skipped."""
|
||||
mock_device.supports.side_effect = lambda command: command is not cmd.ColorDepth
|
||||
mock_device.supports.side_effect = lambda command: (
|
||||
command is not unsupported_command
|
||||
)
|
||||
|
||||
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 entity_registry.async_get("sensor.jvc_projector_color_depth") is None
|
||||
assert entity_registry.async_get(entity_id) is None
|
||||
|
||||
Reference in New Issue
Block a user