From ef1290c6a7e0e9dbf024e7f5d80671a585d6705f Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:32:21 +0000 Subject: [PATCH 01/16] feat: use runtime data instead of hass.data --- homeassistant/components/jvc_projector/__init__.py | 6 ++---- homeassistant/components/jvc_projector/binary_sensor.py | 3 +-- homeassistant/components/jvc_projector/remote.py | 3 +-- homeassistant/components/jvc_projector/select.py | 3 +-- homeassistant/components/jvc_projector/sensor.py | 3 +-- tests/components/jvc_projector/test_coordinator.py | 5 ++--- tests/components/jvc_projector/test_init.py | 2 -- 7 files changed, 8 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/jvc_projector/__init__.py b/homeassistant/components/jvc_projector/__init__.py index 8ce1fb46e3d1af..3fd3535645c22d 100644 --- a/homeassistant/components/jvc_projector/__init__.py +++ b/homeassistant/components/jvc_projector/__init__.py @@ -15,7 +15,6 @@ from homeassistant.core import Event, HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady -from .const import DOMAIN from .coordinator import JvcProjectorDataUpdateCoordinator PLATFORMS = [Platform.BINARY_SENSOR, Platform.REMOTE, Platform.SELECT, Platform.SENSOR] @@ -43,7 +42,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: coordinator = JvcProjectorDataUpdateCoordinator(hass, device) await coordinator.async_config_entry_first_refresh() - hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator + entry.runtime_data = coordinator async def disconnect(event: Event) -> None: await device.disconnect() @@ -60,6 +59,5 @@ async def disconnect(event: Event) -> None: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - await hass.data[DOMAIN][entry.entry_id].device.disconnect() - hass.data[DOMAIN].pop(entry.entry_id) + await entry.runtime_data.device.disconnect() return unload_ok diff --git a/homeassistant/components/jvc_projector/binary_sensor.py b/homeassistant/components/jvc_projector/binary_sensor.py index 7e8788aa0a63ab..ed84c71e0ec661 100644 --- a/homeassistant/components/jvc_projector/binary_sensor.py +++ b/homeassistant/components/jvc_projector/binary_sensor.py @@ -10,7 +10,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import JvcProjectorDataUpdateCoordinator -from .const import DOMAIN from .entity import JvcProjectorEntity ON_STATUS = (const.ON, const.WARMING) @@ -20,7 +19,7 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data async_add_entities([JvcBinarySensor(coordinator)]) diff --git a/homeassistant/components/jvc_projector/remote.py b/homeassistant/components/jvc_projector/remote.py index b69d3b0118b3f3..d004f96eacbb18 100644 --- a/homeassistant/components/jvc_projector/remote.py +++ b/homeassistant/components/jvc_projector/remote.py @@ -15,7 +15,6 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import DOMAIN from .entity import JvcProjectorEntity COMMANDS = { @@ -58,7 +57,7 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator = hass.data[DOMAIN][entry.entry_id] + coordinator = entry.runtime_data async_add_entities([JvcProjectorRemote(coordinator)], True) diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 1395637fad1df4..0e6f2b0691929a 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -14,7 +14,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import JvcProjectorDataUpdateCoordinator -from .const import DOMAIN from .entity import JvcProjectorEntity @@ -45,7 +44,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data async_add_entities( JvcProjectorSelectEntity(coordinator, description) for description in SELECTS diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 9be04b367e64e9..e3f000219b9ee5 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -15,7 +15,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import JvcProjectorDataUpdateCoordinator -from .const import DOMAIN from .entity import JvcProjectorEntity JVC_SENSORS = ( @@ -39,7 +38,7 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data async_add_entities( JvcSensor(coordinator, description) for description in JVC_SENSORS diff --git a/tests/components/jvc_projector/test_coordinator.py b/tests/components/jvc_projector/test_coordinator.py index 24297348653026..b9211250aff7f8 100644 --- a/tests/components/jvc_projector/test_coordinator.py +++ b/tests/components/jvc_projector/test_coordinator.py @@ -5,7 +5,6 @@ from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError -from homeassistant.components.jvc_projector import DOMAIN from homeassistant.components.jvc_projector.coordinator import ( INTERVAL_FAST, INTERVAL_SLOW, @@ -29,7 +28,7 @@ async def test_coordinator_update( ) await hass.async_block_till_done() assert mock_device.get_state.call_count == 3 - coordinator = hass.data[DOMAIN][mock_integration.entry_id] + coordinator = mock_integration.runtime_data assert coordinator.update_interval == INTERVAL_SLOW @@ -69,5 +68,5 @@ async def test_coordinator_device_on( mock_config_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() - coordinator = hass.data[DOMAIN][mock_config_entry.entry_id] + coordinator = mock_config_entry.runtime_data assert coordinator.update_interval == INTERVAL_FAST diff --git a/tests/components/jvc_projector/test_init.py b/tests/components/jvc_projector/test_init.py index ef9de41ca3233a..baf088a5dba620 100644 --- a/tests/components/jvc_projector/test_init.py +++ b/tests/components/jvc_projector/test_init.py @@ -38,8 +38,6 @@ async def test_unload_config_entry( await hass.config_entries.async_unload(mock_config_entry.entry_id) await hass.async_block_till_done() - assert mock_config_entry.entry_id not in hass.data[DOMAIN] - async def test_config_entry_connect_error( hass: HomeAssistant, From 9303984ea8f1647ea38c46731ab378192a10b74d Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:22:18 +0000 Subject: [PATCH 02/16] fix: extend ConfigEntry --- homeassistant/components/jvc_projector/__init__.py | 6 ++++-- homeassistant/components/jvc_projector/binary_sensor.py | 7 +++---- homeassistant/components/jvc_projector/remote.py | 4 ++-- homeassistant/components/jvc_projector/select.py | 7 +++---- homeassistant/components/jvc_projector/sensor.py | 7 +++---- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/jvc_projector/__init__.py b/homeassistant/components/jvc_projector/__init__.py index 3fd3535645c22d..09e93127e40d5c 100644 --- a/homeassistant/components/jvc_projector/__init__.py +++ b/homeassistant/components/jvc_projector/__init__.py @@ -17,10 +17,12 @@ from .coordinator import JvcProjectorDataUpdateCoordinator +type JVCConfigEntry = ConfigEntry[JvcProjectorDataUpdateCoordinator] + PLATFORMS = [Platform.BINARY_SENSOR, Platform.REMOTE, Platform.SELECT, Platform.SENSOR] -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool: """Set up integration from a config entry.""" device = JvcProjector( host=entry.data[CONF_HOST], @@ -56,7 +58,7 @@ async def disconnect(event: Event) -> None: return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool: """Unload config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): await entry.runtime_data.device.disconnect() diff --git a/homeassistant/components/jvc_projector/binary_sensor.py b/homeassistant/components/jvc_projector/binary_sensor.py index ed84c71e0ec661..6dfac63892bec0 100644 --- a/homeassistant/components/jvc_projector/binary_sensor.py +++ b/homeassistant/components/jvc_projector/binary_sensor.py @@ -5,21 +5,20 @@ from jvcprojector import const from homeassistant.components.binary_sensor import BinarySensorEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import JvcProjectorDataUpdateCoordinator +from . import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity ON_STATUS = (const.ON, const.WARMING) async def async_setup_entry( - hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: JVCConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data + coordinator = entry.runtime_data async_add_entities([JvcBinarySensor(coordinator)]) diff --git a/homeassistant/components/jvc_projector/remote.py b/homeassistant/components/jvc_projector/remote.py index d004f96eacbb18..f90a2816363d8a 100644 --- a/homeassistant/components/jvc_projector/remote.py +++ b/homeassistant/components/jvc_projector/remote.py @@ -10,11 +10,11 @@ from jvcprojector import const from homeassistant.components.remote import RemoteEntity -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import JVCConfigEntry from .entity import JvcProjectorEntity COMMANDS = { @@ -54,7 +54,7 @@ async def async_setup_entry( - hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: JVCConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" coordinator = entry.runtime_data diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 0e6f2b0691929a..60c80f98fc0702 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -9,11 +9,10 @@ from jvcprojector import JvcProjector, const from homeassistant.components.select import SelectEntity, SelectEntityDescription -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import JvcProjectorDataUpdateCoordinator +from . import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity @@ -40,11 +39,11 @@ class JvcProjectorSelectDescription(SelectEntityDescription): async def async_setup_entry( hass: HomeAssistant, - entry: ConfigEntry, + entry: JVCConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data + coordinator = entry.runtime_data async_add_entities( JvcProjectorSelectEntity(coordinator, description) for description in SELECTS diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index e3f000219b9ee5..3edf51e4316cbd 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -9,12 +9,11 @@ SensorEntity, SensorEntityDescription, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import JvcProjectorDataUpdateCoordinator +from . import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity JVC_SENSORS = ( @@ -35,10 +34,10 @@ async def async_setup_entry( - hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: JVCConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the JVC Projector platform from a config entry.""" - coordinator: JvcProjectorDataUpdateCoordinator = entry.runtime_data + coordinator = entry.runtime_data async_add_entities( JvcSensor(coordinator, description) for description in JVC_SENSORS From 9c46e826539ec37a7bba5190f5435b08dc8e3a43 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Fri, 22 Nov 2024 03:34:46 +0000 Subject: [PATCH 03/16] feat: add new sensors --- .../components/jvc_projector/config_flow.py | 5 +- .../components/jvc_projector/entity.py | 4 +- .../components/jvc_projector/sensor.py | 163 +++++++++++++++++- 3 files changed, 168 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/jvc_projector/config_flow.py b/homeassistant/components/jvc_projector/config_flow.py index 7fbfb17a976281..d508df7a4affad 100644 --- a/homeassistant/components/jvc_projector/config_flow.py +++ b/homeassistant/components/jvc_projector/config_flow.py @@ -9,11 +9,12 @@ from jvcprojector.projector import DEFAULT_PORT import voluptuous as vol -from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT from homeassistant.helpers.device_registry import format_mac from homeassistant.util.network import is_host_valid +from . import JVCConfigEntry from .const import DOMAIN, NAME @@ -22,7 +23,7 @@ class JvcProjectorConfigFlow(ConfigFlow, domain=DOMAIN): VERSION = 1 - _reauth_entry: ConfigEntry | None = None + _reauth_entry: JVCConfigEntry | None = None async def async_step_user( self, user_input: dict[str, Any] | None = None diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index a88fba03cb03d0..d484d76aaee36e 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -6,7 +6,7 @@ from jvcprojector import JvcProjector -from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, MANUFACTURER, NAME @@ -30,6 +30,8 @@ def __init__(self, coordinator: JvcProjectorDataUpdateCoordinator) -> None: name=NAME, model=self.device.model, manufacturer=MANUFACTURER, + sw_version=self.device.version, + connections={(CONNECTION_NETWORK_MAC, self.device.mac)}, ) @property diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 3edf51e4316cbd..4c94b7cc6c9fad 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -18,7 +18,7 @@ JVC_SENSORS = ( SensorEntityDescription( - key="power", + key=const.KEY_POWER, translation_key="jvc_power_status", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, @@ -30,6 +30,167 @@ const.ERROR, ], ), + SensorEntityDescription( + key=const.KEY_INPUT, + translation_key="jvc_hdmi_input", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.HDMI1, + const.HDMI2, + ], + ), + SensorEntityDescription( + key=const.KEY_SOURCE, + translation_key="jvc_source_status", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.SIGNAL, + const.NOSIGNAL, + ], + ), + SensorEntityDescription( + key=const.KEY_PICTURE_MODE, + translation_key="jvc_picture_mode", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key=const.KEY_LOW_LATENCY, + translation_key="jvc_low_latency_status", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.OFF, + const.ON, + ], + ), + SensorEntityDescription( + key=const.KEY_INSTALLATION_MODE, + translation_key="jvc_installation_mode", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key=const.KEY_ANAMORPHIC, + translation_key="jvc_anamorphic_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.OFF, + const.ANAMORPHIC_A, + const.ANAMORPHIC_B, + const.ANAMORPHIC_C, + const.ANAMORPHIC_D, + ], + ), + SensorEntityDescription( + key=const.KEY_HDR, + translation_key="jvc_hdr_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.HDR_CONTENT_NONE, + const.HDR_CONTENT_HDR10, + const.HDR_CONTENT_HDR10PLUS, + const.HDR_CONTENT_HLG, + const.HDR_CONTENT_SDR, + ], + ), + SensorEntityDescription( + key=const.KEY_HDMI_INPUT_LEVEL, + translation_key="jvc_hdmi_input_level", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_HDMI_INPUT_LEVEL, + ), + SensorEntityDescription( + key=const.KEY_HDMI_COLOR_SPACE, + translation_key="jvc_hdmi_color_space", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_HDMI_COLOR_SPACE, + ), + SensorEntityDescription( + key=const.KEY_COLOR_PROFILE, + translation_key="jvc_color_profile", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key=const.KEY_GRAPHICS_MODE, + translation_key="jvc_graphics_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_GRAPHICS_MODE, + ), + SensorEntityDescription( + key=const.KEY_COLOR_SPACE, + translation_key="jvc_color_space", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_COLOR_SPACE, + ), + SensorEntityDescription( + key=const.KEY_ESHIFT, + translation_key="jvc_eshift", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.OFF, + const.ON, + ], + ), + SensorEntityDescription( + key=const.KEY_LASER_DIMMING, + translation_key="jvc_laser_dimming_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_LASER_DIMMING, + ), + SensorEntityDescription( + key=const.KEY_LASER_VALUE, + translation_key="jvc_laser_value", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key=const.KEY_LASER_POWER, + translation_key="jvc_laser_power", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_LASER_POWER, + ), + SensorEntityDescription( + key=const.KEY_LASER_TIME, + translation_key="jvc_laser_time", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key=const.KEY_MOTION_ENHANCE, + translation_key="jvc_motion_enhance", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_MOTION_ENHANCE, + ), + SensorEntityDescription( + key=const.KEY_CLEAR_MOTION_DRIVE, + translation_key="jvc_clear_motion_drive", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_CLEAR_MOTION_DRIVE, + ), + SensorEntityDescription( + key=const.KEY_HDR_PROCESSING, + translation_key="jvc_hdr_processing_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_HDR_PROCESSING, + ), + SensorEntityDescription( + key=const.KEY_HDR_CONTENT_TYPE, + translation_key="jvc_hdr_content_type", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_HDR_CONTENT_TYPE, + ), ) From 779c9106aebc54b50705989d770b8667ae7d28fd Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sat, 23 Nov 2024 00:42:48 +0000 Subject: [PATCH 04/16] add names, fix empty values, get command working, tests --- .../components/jvc_projector/const.py | 35 +++++ .../components/jvc_projector/remote.py | 58 +++---- .../components/jvc_projector/sensor.py | 4 +- .../components/jvc_projector/strings.json | 142 ++++++++++++++++++ tests/components/jvc_projector/test_remote.py | 37 ++++- 5 files changed, 229 insertions(+), 47 deletions(-) diff --git a/homeassistant/components/jvc_projector/const.py b/homeassistant/components/jvc_projector/const.py index e15aa93bfa5db0..1ad7bf112afd06 100644 --- a/homeassistant/components/jvc_projector/const.py +++ b/homeassistant/components/jvc_projector/const.py @@ -1,5 +1,40 @@ """Constants for the jvc_projector integration.""" +from jvcprojector import const + NAME = "JVC Projector" DOMAIN = "jvc_projector" MANUFACTURER = "JVC" + +REMOTE_COMMANDS = { + "menu": const.REMOTE_MENU, + "up": const.REMOTE_UP, + "down": const.REMOTE_DOWN, + "left": const.REMOTE_LEFT, + "right": const.REMOTE_RIGHT, + "ok": const.REMOTE_OK, + "back": const.REMOTE_BACK, + "mpc": const.REMOTE_MPC, + "hide": const.REMOTE_HIDE, + "info": const.REMOTE_INFO, + "input": const.REMOTE_INPUT, + "cmd": const.REMOTE_CMD, + "advanced_menu": const.REMOTE_ADVANCED_MENU, + "picture_mode": const.REMOTE_PICTURE_MODE, + "color_profile": const.REMOTE_COLOR_PROFILE, + "lens_control": const.REMOTE_LENS_CONTROL, + "setting_memory": const.REMOTE_SETTING_MEMORY, + "gamma_settings": const.REMOTE_GAMMA_SETTINGS, + "hdmi_1": const.REMOTE_HDMI_1, + "hdmi_2": const.REMOTE_HDMI_2, + "mode_1": const.REMOTE_MODE_1, + "mode_2": const.REMOTE_MODE_2, + "mode_3": const.REMOTE_MODE_3, + "lens_ap": const.REMOTE_LENS_AP, + "gamma": const.REMOTE_GAMMA, + "color_temp": const.REMOTE_COLOR_TEMP, + "natural": const.REMOTE_NATURAL, + "cinema": const.REMOTE_CINEMA, + "anamo": const.REMOTE_ANAMO, + "3d_format": const.REMOTE_3D_FORMAT, +} diff --git a/homeassistant/components/jvc_projector/remote.py b/homeassistant/components/jvc_projector/remote.py index f90a2816363d8a..c5b6780e89e315 100644 --- a/homeassistant/components/jvc_projector/remote.py +++ b/homeassistant/components/jvc_projector/remote.py @@ -11,45 +11,12 @@ from homeassistant.components.remote import RemoteEntity from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import JVCConfigEntry +from .const import REMOTE_COMMANDS from .entity import JvcProjectorEntity -COMMANDS = { - "menu": const.REMOTE_MENU, - "up": const.REMOTE_UP, - "down": const.REMOTE_DOWN, - "left": const.REMOTE_LEFT, - "right": const.REMOTE_RIGHT, - "ok": const.REMOTE_OK, - "back": const.REMOTE_BACK, - "mpc": const.REMOTE_MPC, - "hide": const.REMOTE_HIDE, - "info": const.REMOTE_INFO, - "input": const.REMOTE_INPUT, - "cmd": const.REMOTE_CMD, - "advanced_menu": const.REMOTE_ADVANCED_MENU, - "picture_mode": const.REMOTE_PICTURE_MODE, - "color_profile": const.REMOTE_COLOR_PROFILE, - "lens_control": const.REMOTE_LENS_CONTROL, - "setting_memory": const.REMOTE_SETTING_MEMORY, - "gamma_settings": const.REMOTE_GAMMA_SETTINGS, - "hdmi_1": const.REMOTE_HDMI_1, - "hdmi_2": const.REMOTE_HDMI_2, - "mode_1": const.REMOTE_MODE_1, - "mode_2": const.REMOTE_MODE_2, - "mode_3": const.REMOTE_MODE_3, - "lens_ap": const.REMOTE_LENS_AP, - "gamma": const.REMOTE_GAMMA, - "color_temp": const.REMOTE_COLOR_TEMP, - "natural": const.REMOTE_NATURAL, - "cinema": const.REMOTE_CINEMA, - "anamo": const.REMOTE_ANAMO, - "3d_format": const.REMOTE_3D_FORMAT, -} - _LOGGER = logging.getLogger(__name__) @@ -85,8 +52,23 @@ async def async_turn_off(self, **kwargs: Any) -> None: async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None: """Send a remote command to the device.""" + _LOGGER.debug("Sending command '%s'", command) + for cmd in command: - if cmd not in COMMANDS: - raise HomeAssistantError(f"{cmd} is not a known command") - _LOGGER.debug("Sending command '%s'", cmd) - await self.device.remote(COMMANDS[cmd]) + _LOGGER.debug("Processing command '%s'", cmd) + + # Split command and value + parts = cmd.split(",", 1) + if len(parts) != 2: + raise ValueError(f"Invalid command format: {cmd}") + + cmd_name, value = parts + cmd_name = cmd_name.strip().lower() + value = value.strip() + + if cmd_name == "remote": + if value not in REMOTE_COMMANDS: + raise ValueError(f"Unknown remote command: {value}") + await self.device.remote(REMOTE_COMMANDS[value]) + else: + await self.device.send_command(cmd_name, value) diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 4c94b7cc6c9fad..c7d8f41b75e365 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -125,9 +125,7 @@ SensorEntityDescription( key=const.KEY_COLOR_SPACE, translation_key="jvc_color_space", - device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_COLOR_SPACE, ), SensorEntityDescription( key=const.KEY_ESHIFT, @@ -221,4 +219,4 @@ def __init__( @property def native_value(self) -> str | None: """Return the native value.""" - return self.coordinator.data[self.entity_description.key] + return self.coordinator.data.get(self.entity_description.key) diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index b89139cbab3e94..ea80e2066e406a 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -57,6 +57,148 @@ "cooling": "Cooling", "error": "Error" } + }, + "jvc_hdmi_input": { + "name": "HDMI input", + "state": { + "hdmi1": "HDMI 1", + "hdmi2": "HDMI 2" + } + }, + "jvc_source_status": { + "name": "Source status", + "state": { + "signal": "Signal", + "no_signal": "No signal" + } + }, + "jvc_picture_mode": { + "name": "Picture mode" + }, + "jvc_low_latency_status": { + "name": "Low latency", + "state": { + "off": "[%key:common::state::off%]", + "on": "[%key:common::state::on%]" + } + }, + "jvc_installation_mode": { + "name": "Installation mode" + }, + "jvc_anamorphic_mode": { + "name": "Anamorphic mode", + "state": { + "off": "[%key:common::state::off%]", + "a": "Mode A", + "b": "Mode B", + "c": "Mode C", + "d": "Mode D" + } + }, + "jvc_hdr_mode": { + "name": "HDR mode", + "state": { + "none": "None", + "hdr10": "HDR10", + "hdr10_plus": "HDR10+", + "hlg": "HLG", + "sdr": "SDR" + } + }, + "jvc_hdmi_input_level": { + "name": "HDMI input level", + "state": { + "standard": "Standard", + "enhanced": "Enhanced", + "super_white": "Super White", + "auto": "Auto" + } + }, + "jvc_hdmi_color_space": { + "name": "HDMI color space" + }, + "jvc_color_profile": { + "name": "Color profile" + }, + "jvc_graphics_mode": { + "name": "Graphics mode", + "state": { + "standard": "Standard", + "high-res": "High Resolution" + } + }, + "jvc_color_space": { + "name": "Color space", + "state": { + "rgb": "RGB", + "yuv": "YUV" + } + }, + "jvc_eshift": { + "name": "eShift", + "state": { + "off": "[%key:common::state::off%]", + "on": "[%key:common::state::on%]" + } + }, + "jvc_laser_dimming_mode": { + "name": "Laser dimming", + "state": { + "off": "[%key:common::state::off%]", + "auto1": "Auto 1", + "auto2": "Auto 2", + "auto3": "Auto 3" + } + }, + "jvc_laser_value": { + "name": "Laser value" + }, + "jvc_laser_power": { + "name": "Laser power", + "state": { + "low": "Low", + "medium": "Medium", + "high": "High" + } + }, + "jvc_laser_time": { + "name": "Laser time" + }, + "jvc_motion_enhance": { + "name": "Motion enhance", + "state": { + "off": "[%key:common::state::off%]", + "low": "Low", + "high": "High" + } + }, + "jvc_clear_motion_drive": { + "name": "Clear motion drive", + "state": { + "off": "[%key:common::state::off%]", + "none": "None", + "low": "Low", + "high": "High", + "inverse_telecine": "Inverse Telecine" + } + }, + "jvc_hdr_processing_mode": { + "name": "HDR processing", + "state": { + "static": "Static", + "frame": "Frame by Frame", + "scene": "Scene by Scene" + } + }, + "jvc_hdr_content_type": { + "name": "HDR content type", + "state": { + "auto": "Auto", + "sdr": "SDR", + "none": "None", + "hdr10": "HDR10", + "hlg": "HLG" + } } } } diff --git a/tests/components/jvc_projector/test_remote.py b/tests/components/jvc_projector/test_remote.py index 28bf835e0329e8..091deaab5b3b9e 100644 --- a/tests/components/jvc_projector/test_remote.py +++ b/tests/components/jvc_projector/test_remote.py @@ -11,7 +11,6 @@ ) from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from tests.common import MockConfigEntry @@ -56,7 +55,7 @@ async def test_commands( await hass.services.async_call( REMOTE_DOMAIN, SERVICE_SEND_COMMAND, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["ok"]}, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["remote, hdmi_1"]}, blocking=True, ) assert mock_device.remote.call_count == 1 @@ -64,23 +63,49 @@ async def test_commands( await hass.services.async_call( REMOTE_DOMAIN, SERVICE_SEND_COMMAND, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["hdmi_1"]}, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["laser_power, medium"]}, blocking=True, ) - assert mock_device.remote.call_count == 2 + assert mock_device.send_command.call_count == 1 + await hass.services.async_call( + REMOTE_DOMAIN, + SERVICE_SEND_COMMAND, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["laser_power, high"]}, + blocking=True, + ) + assert mock_device.send_command.call_count == 2 -async def test_unknown_command( + +async def test_bad_format_command( hass: HomeAssistant, mock_device: MagicMock, mock_integration: MockConfigEntry, ) -> None: """Test unknown service call errors.""" - with pytest.raises(HomeAssistantError) as err: + with pytest.raises(ValueError) as err: await hass.services.async_call( REMOTE_DOMAIN, SERVICE_SEND_COMMAND, {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["bad"]}, blocking=True, ) + assert str(err.value) == "Invalid command format: bad" + + +async def test_unknown_command( + hass: HomeAssistant, + mock_device: MagicMock, + mock_integration: MockConfigEntry, +) -> None: + """Test unknown service call errors.""" + mock_device.send_command.side_effect = ValueError("bad is not a known command") + + with pytest.raises(ValueError) as err: + await hass.services.async_call( + REMOTE_DOMAIN, + SERVICE_SEND_COMMAND, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["bad, bad"]}, + blocking=True, + ) assert str(err.value) == "bad is not a known command" From 123d7eec32894cc6de08b16b911744061329605c Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 24 Nov 2024 00:25:43 +0000 Subject: [PATCH 05/16] add sensors off by default, add test coverage --- .../components/jvc_projector/sensor.py | 139 +- tests/components/jvc_projector/__init__.py | 13 + tests/components/jvc_projector/conftest.py | 25 +- .../jvc_projector/snapshots/test_sensor.ambr | 1221 +++++++++++++++++ .../jvc_projector/test_binary_sensor.py | 11 +- .../jvc_projector/test_config_flow.py | 42 +- tests/components/jvc_projector/test_init.py | 5 +- tests/components/jvc_projector/test_remote.py | 27 +- tests/components/jvc_projector/test_select.py | 16 +- tests/components/jvc_projector/test_sensor.py | 43 +- 10 files changed, 1440 insertions(+), 102 deletions(-) create mode 100644 tests/components/jvc_projector/snapshots/test_sensor.ambr diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index c7d8f41b75e365..207e0d3eb61678 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -2,6 +2,8 @@ from __future__ import annotations +from dataclasses import dataclass + from jvcprojector import const from homeassistant.components.sensor import ( @@ -16,8 +18,16 @@ from . import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity + +@dataclass(frozen=True, kw_only=True) +class JVCSensorEntityDescription(SensorEntityDescription): + """Describe JVC sensor entity.""" + + enabled_default: bool = True + + JVC_SENSORS = ( - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_POWER, translation_key="jvc_power_status", device_class=SensorDeviceClass.ENUM, @@ -30,7 +40,7 @@ const.ERROR, ], ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_INPUT, translation_key="jvc_hdmi_input", device_class=SensorDeviceClass.ENUM, @@ -40,7 +50,7 @@ const.HDMI2, ], ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_SOURCE, translation_key="jvc_source_status", device_class=SensorDeviceClass.ENUM, @@ -50,12 +60,12 @@ const.NOSIGNAL, ], ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_PICTURE_MODE, translation_key="jvc_picture_mode", entity_category=EntityCategory.DIAGNOSTIC, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_LOW_LATENCY, translation_key="jvc_low_latency_status", device_class=SensorDeviceClass.ENUM, @@ -65,12 +75,54 @@ const.ON, ], ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_INSTALLATION_MODE, translation_key="jvc_installation_mode", entity_category=EntityCategory.DIAGNOSTIC, ), - SensorEntityDescription( + JVCSensorEntityDescription( + key=const.KEY_ESHIFT, + translation_key="jvc_eshift", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + const.OFF, + const.ON, + ], + ), + JVCSensorEntityDescription( + key=const.KEY_LASER_DIMMING, + translation_key="jvc_laser_dimming_mode", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_LASER_DIMMING, + ), + JVCSensorEntityDescription( + key=const.KEY_LASER_VALUE, + translation_key="jvc_laser_value", + entity_category=EntityCategory.DIAGNOSTIC, + ), + JVCSensorEntityDescription( + key=const.KEY_LASER_POWER, + translation_key="jvc_laser_power", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_LASER_POWER, + ), + JVCSensorEntityDescription( + key=const.KEY_LASER_TIME, + translation_key="jvc_laser_time", + entity_category=EntityCategory.DIAGNOSTIC, + ), + JVCSensorEntityDescription( + key=const.KEY_HDR_CONTENT_TYPE, + translation_key="jvc_hdr_content_type", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=const.VAL_HDR_CONTENT_TYPE, + ), + # niche sensors that are disabled by default + JVCSensorEntityDescription( key=const.KEY_ANAMORPHIC, translation_key="jvc_anamorphic_mode", device_class=SensorDeviceClass.ENUM, @@ -82,8 +134,9 @@ const.ANAMORPHIC_C, const.ANAMORPHIC_D, ], + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_HDR, translation_key="jvc_hdr_mode", device_class=SensorDeviceClass.ENUM, @@ -95,99 +148,67 @@ const.HDR_CONTENT_HLG, const.HDR_CONTENT_SDR, ], + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_HDMI_INPUT_LEVEL, translation_key="jvc_hdmi_input_level", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_HDMI_INPUT_LEVEL, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_HDMI_COLOR_SPACE, translation_key="jvc_hdmi_color_space", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_HDMI_COLOR_SPACE, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_COLOR_PROFILE, translation_key="jvc_color_profile", entity_category=EntityCategory.DIAGNOSTIC, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_GRAPHICS_MODE, translation_key="jvc_graphics_mode", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_GRAPHICS_MODE, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_COLOR_SPACE, translation_key="jvc_color_space", entity_category=EntityCategory.DIAGNOSTIC, + enabled_default=False, ), - SensorEntityDescription( - key=const.KEY_ESHIFT, - translation_key="jvc_eshift", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.OFF, - const.ON, - ], - ), - SensorEntityDescription( - key=const.KEY_LASER_DIMMING, - translation_key="jvc_laser_dimming_mode", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_LASER_DIMMING, - ), - SensorEntityDescription( - key=const.KEY_LASER_VALUE, - translation_key="jvc_laser_value", - entity_category=EntityCategory.DIAGNOSTIC, - ), - SensorEntityDescription( - key=const.KEY_LASER_POWER, - translation_key="jvc_laser_power", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_LASER_POWER, - ), - SensorEntityDescription( - key=const.KEY_LASER_TIME, - translation_key="jvc_laser_time", - entity_category=EntityCategory.DIAGNOSTIC, - ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_MOTION_ENHANCE, translation_key="jvc_motion_enhance", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_MOTION_ENHANCE, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_CLEAR_MOTION_DRIVE, translation_key="jvc_clear_motion_drive", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_CLEAR_MOTION_DRIVE, + enabled_default=False, ), - SensorEntityDescription( + JVCSensorEntityDescription( key=const.KEY_HDR_PROCESSING, translation_key="jvc_hdr_processing_mode", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_HDR_PROCESSING, - ), - SensorEntityDescription( - key=const.KEY_HDR_CONTENT_TYPE, - translation_key="jvc_hdr_content_type", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_HDR_CONTENT_TYPE, + enabled_default=False, ), ) @@ -197,7 +218,6 @@ async def async_setup_entry( ) -> None: """Set up the JVC Projector platform from a config entry.""" coordinator = entry.runtime_data - async_add_entities( JvcSensor(coordinator, description) for description in JVC_SENSORS ) @@ -209,12 +229,13 @@ class JvcSensor(JvcProjectorEntity, SensorEntity): def __init__( self, coordinator: JvcProjectorDataUpdateCoordinator, - description: SensorEntityDescription, + description: JVCSensorEntityDescription, ) -> None: """Initialize the JVC Projector sensor.""" super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{coordinator.unique_id}_{description.key}" + self._attr_entity_registry_enabled_default = description.enabled_default @property def native_value(self) -> str | None: diff --git a/tests/components/jvc_projector/__init__.py b/tests/components/jvc_projector/__init__.py index d8554e8f4cd738..b981733e254146 100644 --- a/tests/components/jvc_projector/__init__.py +++ b/tests/components/jvc_projector/__init__.py @@ -1,7 +1,20 @@ """Tests for JVC Projector integration.""" +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + MOCK_HOST = "127.0.0.1" MOCK_PORT = 20554 MOCK_PASSWORD = "jvcpasswd" MOCK_MAC = "jvcmac" MOCK_MODEL = "jvcmodel" + + +# used to load a single platform in a test +async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None: + """Fixture for setting up the component.""" + config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() diff --git a/tests/components/jvc_projector/conftest.py b/tests/components/jvc_projector/conftest.py index 3115cbfe2522f9..c2ccd4c1617e98 100644 --- a/tests/components/jvc_projector/conftest.py +++ b/tests/components/jvc_projector/conftest.py @@ -29,7 +29,30 @@ def fixture_mock_device( device.port = MOCK_PORT device.mac = MOCK_MAC device.model = MOCK_MODEL - device.get_state.return_value = {"power": "standby", "input": "hdmi1"} + device.get_state.return_value = { + "power": "standby", + "input": "hdmi1", + "source": "signal", + "picture_mode": "natural", + "low_latency": "off", + "installation_mode": "mode1", + "eshift": "on", + "laser_dimming": "auto1", + "laser_value": "100", + "laser_power": "high", + "laser_time": "1000", + "hdr_content_type": "sdr", + "anamorphic": "off", + "hdr": "none", + "hdmi_input_level": "enhanced", + "hdmi_color_space": "rgb", + "color_profile": "bt2020(wide)", + "graphics_mode": "standard", + "color_space": "rgb", + "motion_enhance": "low", + "clear_motion_drive": "low", + "hdr_processing": "static", + } yield device diff --git a/tests/components/jvc_projector/snapshots/test_sensor.ambr b/tests/components/jvc_projector/snapshots/test_sensor.ambr new file mode 100644 index 00000000000000..b172d11c03f6e1 --- /dev/null +++ b/tests/components/jvc_projector/snapshots/test_sensor.ambr @@ -0,0 +1,1221 @@ +# serializer version: 1 +# name: test_entity_state[sensor.jvc_projector_anamorphic_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'a', + 'b', + 'c', + 'd', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_anamorphic_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Anamorphic mode', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_anamorphic_mode', + 'unique_id': 'jvcmac_anamorphic', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_anamorphic_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Anamorphic mode', + 'options': list([ + 'off', + 'a', + 'b', + 'c', + 'd', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_anamorphic_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_clear_motion_drive-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'none', + 'low', + 'high', + 'inverse_telecine', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_clear_motion_drive', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Clear motion drive', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_clear_motion_drive', + 'unique_id': 'jvcmac_clear_motion_drive', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_clear_motion_drive-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Clear motion drive', + 'options': list([ + 'off', + 'none', + 'low', + 'high', + 'inverse_telecine', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_clear_motion_drive', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'low', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_color_profile-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_color_profile', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Color profile', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_color_profile', + 'unique_id': 'jvcmac_color_profile', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_color_profile-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Color profile', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_color_profile', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'bt2020(wide)', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_color_space-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_color_space', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Color space', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_color_space', + 'unique_id': 'jvcmac_color_space', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_color_space-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Color space', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_color_space', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'rgb', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_eshift-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'on', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_eshift', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'eShift', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_eshift', + 'unique_id': 'jvcmac_eshift', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_eshift-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector eShift', + 'options': list([ + 'off', + 'on', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_eshift', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_graphics_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'standard', + 'high-res', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_graphics_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Graphics mode', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_graphics_mode', + 'unique_id': 'jvcmac_graphics_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_graphics_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Graphics mode', + 'options': list([ + 'standard', + 'high-res', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_graphics_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'standard', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_color_space-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'auto', + 'ycbcr(4:4:4)', + 'ycbcr(4:2:2)', + 'rgb', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdmi_color_space', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDMI color space', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdmi_color_space', + 'unique_id': 'jvcmac_hdmi_color_space', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_color_space-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDMI color space', + 'options': list([ + 'auto', + 'ycbcr(4:4:4)', + 'ycbcr(4:2:2)', + 'rgb', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdmi_color_space', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'rgb', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_input-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'hdmi1', + 'hdmi2', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdmi_input', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDMI input', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdmi_input', + 'unique_id': 'jvcmac_input', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_input-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDMI input', + 'options': list([ + 'hdmi1', + 'hdmi2', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdmi_input', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'hdmi1', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_input_level-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'standard', + 'enhanced', + 'super_white', + 'auto', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdmi_input_level', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDMI input level', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdmi_input_level', + 'unique_id': 'jvcmac_hdmi_input_level', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdmi_input_level-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDMI input level', + 'options': list([ + 'standard', + 'enhanced', + 'super_white', + 'auto', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdmi_input_level', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'enhanced', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_content_type-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'auto', + 'sdr', + 'none', + 'hdr10', + 'hlg', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdr_content_type', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDR content type', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdr_content_type', + 'unique_id': 'jvcmac_hdr_content_type', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_content_type-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDR content type', + 'options': list([ + 'auto', + 'sdr', + 'none', + 'hdr10', + 'hlg', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdr_content_type', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'sdr', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'none', + 'hdr10', + 'hdr10_plus', + 'hlg', + 'sdr', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdr_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDR mode', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdr_mode', + 'unique_id': 'jvcmac_hdr', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDR mode', + 'options': list([ + 'none', + 'hdr10', + 'hdr10_plus', + 'hlg', + 'sdr', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdr_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'none', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_processing-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'static', + 'frame', + 'scene', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_hdr_processing', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'HDR processing', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_hdr_processing_mode', + 'unique_id': 'jvcmac_hdr_processing', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_hdr_processing-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector HDR processing', + 'options': list([ + 'static', + 'frame', + 'scene', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_hdr_processing', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'static', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_installation_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_installation_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Installation mode', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_installation_mode', + 'unique_id': 'jvcmac_installation_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_installation_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Installation mode', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_installation_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'mode1', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_dimming-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'auto1', + 'auto2', + 'auto3', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_laser_dimming', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Laser dimming', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_laser_dimming_mode', + 'unique_id': 'jvcmac_laser_dimming', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_dimming-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Laser dimming', + 'options': list([ + 'off', + 'auto1', + 'auto2', + 'auto3', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_laser_dimming', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'auto1', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'low', + 'high', + 'medium', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_laser_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Laser power', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_laser_power', + 'unique_id': 'jvcmac_laser_power', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Laser power', + 'options': list([ + 'low', + 'high', + 'medium', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_laser_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'high', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_time-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_laser_time', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Laser time', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_laser_time', + 'unique_id': 'jvcmac_laser_time', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_time-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Laser time', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_laser_time', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1000', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_value-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_laser_value', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Laser value', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_laser_value', + 'unique_id': 'jvcmac_laser_value', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_laser_value-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Laser value', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_laser_value', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_low_latency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'on', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_low_latency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Low latency', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_low_latency_status', + 'unique_id': 'jvcmac_low_latency', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_low_latency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Low latency', + 'options': list([ + 'off', + 'on', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_low_latency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_motion_enhance-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'off', + 'low', + 'high', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_motion_enhance', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Motion enhance', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_motion_enhance', + 'unique_id': 'jvcmac_motion_enhance', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_motion_enhance-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Motion enhance', + 'options': list([ + 'off', + 'low', + 'high', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_motion_enhance', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'low', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_picture_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_picture_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Picture mode', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_picture_mode', + 'unique_id': 'jvcmac_picture_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_picture_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Picture mode', + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_picture_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'natural', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_power_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'standby', + 'on', + 'warming', + 'cooling', + 'error', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_power_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power status', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_power_status', + 'unique_id': 'jvcmac_power', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_power_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Power status', + 'options': list([ + 'standby', + 'on', + 'warming', + 'cooling', + 'error', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_power_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'standby', + }) +# --- +# name: test_entity_state[sensor.jvc_projector_source_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'signal', + 'nosignal', + ]), + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jvc_projector_source_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Source status', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_source_status', + 'unique_id': 'jvcmac_source', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity_state[sensor.jvc_projector_source_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'JVC Projector Source status', + 'options': list([ + 'signal', + 'nosignal', + ]), + }), + 'context': , + 'entity_id': 'sensor.jvc_projector_source_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'signal', + }) +# --- diff --git a/tests/components/jvc_projector/test_binary_sensor.py b/tests/components/jvc_projector/test_binary_sensor.py index b327538991ca3c..95b63433587e5a 100644 --- a/tests/components/jvc_projector/test_binary_sensor.py +++ b/tests/components/jvc_projector/test_binary_sensor.py @@ -1,10 +1,13 @@ """Tests for the JVC Projector binary sensor device.""" -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch +from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from . import setup_integration + from tests.common import MockConfigEntry ENTITY_ID = "binary_sensor.jvc_projector_power" @@ -14,9 +17,13 @@ async def test_entity_state( hass: HomeAssistant, entity_registry: er.EntityRegistry, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Tests entity state is registered.""" + with patch( + "homeassistant.components.jvc_projector.PLATFORMS", [Platform.BINARY_SENSOR] + ): + await setup_integration(hass, mock_config_entry) entity = hass.states.get(ENTITY_ID) assert entity assert entity_registry.async_get(entity.entity_id) diff --git a/tests/components/jvc_projector/test_config_flow.py b/tests/components/jvc_projector/test_config_flow.py index 282411540a4c29..10fd5677efb2d3 100644 --- a/tests/components/jvc_projector/test_config_flow.py +++ b/tests/components/jvc_projector/test_config_flow.py @@ -82,9 +82,10 @@ async def test_user_config_flow_bad_connect_errors( @pytest.mark.parametrize("mock_device", [TARGET], indirect=True) async def test_user_config_flow_device_exists_abort( - hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry + hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry ) -> None: """Test flow aborts when device already configured.""" + mock_config_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -160,14 +161,15 @@ async def test_user_config_flow_bad_auth_errors( @pytest.mark.parametrize("mock_device", [TARGET], indirect=True) async def test_reauth_config_flow_success( - hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry + hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry ) -> None: """Test reauth config flow success.""" + mock_config_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={ "source": SOURCE_REAUTH, - "entry_id": mock_integration.entry_id, + "entry_id": mock_config_entry.entry_id, }, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}, ) @@ -182,23 +184,23 @@ async def test_reauth_config_flow_success( assert result["type"] is FlowResultType.ABORT assert result["reason"] == "reauth_successful" - assert mock_integration.data[CONF_HOST] == MOCK_HOST - assert mock_integration.data[CONF_PORT] == MOCK_PORT - assert mock_integration.data[CONF_PASSWORD] == MOCK_PASSWORD + assert mock_config_entry.data[CONF_HOST] == MOCK_HOST + assert mock_config_entry.data[CONF_PORT] == MOCK_PORT + assert mock_config_entry.data[CONF_PASSWORD] == MOCK_PASSWORD @pytest.mark.parametrize("mock_device", [TARGET], indirect=True) async def test_reauth_config_flow_auth_error( - hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry + hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry ) -> None: """Test reauth config flow when connect fails.""" mock_device.connect.side_effect = JvcProjectorAuthError - + mock_config_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={ "source": SOURCE_REAUTH, - "entry_id": mock_integration.entry_id, + "entry_id": mock_config_entry.entry_id, }, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}, ) @@ -222,7 +224,7 @@ async def test_reauth_config_flow_auth_error( DOMAIN, context={ "source": SOURCE_REAUTH, - "entry_id": mock_integration.entry_id, + "entry_id": mock_config_entry.entry_id, }, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}, ) @@ -237,23 +239,23 @@ async def test_reauth_config_flow_auth_error( assert result["type"] is FlowResultType.ABORT assert result["reason"] == "reauth_successful" - assert mock_integration.data[CONF_HOST] == MOCK_HOST - assert mock_integration.data[CONF_PORT] == MOCK_PORT - assert mock_integration.data[CONF_PASSWORD] == MOCK_PASSWORD + assert mock_config_entry.data[CONF_HOST] == MOCK_HOST + assert mock_config_entry.data[CONF_PORT] == MOCK_PORT + assert mock_config_entry.data[CONF_PASSWORD] == MOCK_PASSWORD @pytest.mark.parametrize("mock_device", [TARGET], indirect=True) async def test_reauth_config_flow_connect_error( - hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry + hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry ) -> None: """Test reauth config flow when connect fails.""" mock_device.connect.side_effect = JvcProjectorConnectError - + mock_config_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={ "source": SOURCE_REAUTH, - "entry_id": mock_integration.entry_id, + "entry_id": mock_config_entry.entry_id, }, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}, ) @@ -277,7 +279,7 @@ async def test_reauth_config_flow_connect_error( DOMAIN, context={ "source": SOURCE_REAUTH, - "entry_id": mock_integration.entry_id, + "entry_id": mock_config_entry.entry_id, }, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}, ) @@ -292,6 +294,6 @@ async def test_reauth_config_flow_connect_error( assert result["type"] is FlowResultType.ABORT assert result["reason"] == "reauth_successful" - assert mock_integration.data[CONF_HOST] == MOCK_HOST - assert mock_integration.data[CONF_PORT] == MOCK_PORT - assert mock_integration.data[CONF_PASSWORD] == MOCK_PASSWORD + assert mock_config_entry.data[CONF_HOST] == MOCK_HOST + assert mock_config_entry.data[CONF_PORT] == MOCK_PORT + assert mock_config_entry.data[CONF_PASSWORD] == MOCK_PASSWORD diff --git a/tests/components/jvc_projector/test_init.py b/tests/components/jvc_projector/test_init.py index baf088a5dba620..a2374fda5c0e01 100644 --- a/tests/components/jvc_projector/test_init.py +++ b/tests/components/jvc_projector/test_init.py @@ -32,10 +32,9 @@ async def test_unload_config_entry( mock_integration: MockConfigEntry, ) -> None: """Test config entry loading and unloading.""" - mock_config_entry = mock_integration - assert mock_config_entry.state is ConfigEntryState.LOADED + assert mock_integration.state is ConfigEntryState.LOADED - await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.config_entries.async_unload(mock_integration.entry_id) await hass.async_block_till_done() diff --git a/tests/components/jvc_projector/test_remote.py b/tests/components/jvc_projector/test_remote.py index 091deaab5b3b9e..73746676861206 100644 --- a/tests/components/jvc_projector/test_remote.py +++ b/tests/components/jvc_projector/test_remote.py @@ -1,6 +1,6 @@ """Tests for JVC Projector remote platform.""" -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch import pytest @@ -9,10 +9,17 @@ DOMAIN as REMOTE_DOMAIN, SERVICE_SEND_COMMAND, ) -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from . import setup_integration + from tests.common import MockConfigEntry ENTITY_ID = "remote.jvc_projector" @@ -22,9 +29,11 @@ async def test_entity_state( hass: HomeAssistant, entity_registry: er.EntityRegistry, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Tests entity state is registered.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.REMOTE]): + await setup_integration(hass, mock_config_entry) entity = hass.states.get(ENTITY_ID) assert entity assert entity_registry.async_get(entity.entity_id) @@ -33,9 +42,11 @@ async def test_entity_state( async def test_commands( hass: HomeAssistant, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Test service call are called.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.REMOTE]): + await setup_integration(hass, mock_config_entry) await hass.services.async_call( REMOTE_DOMAIN, SERVICE_TURN_ON, @@ -80,9 +91,11 @@ async def test_commands( async def test_bad_format_command( hass: HomeAssistant, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Test unknown service call errors.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.REMOTE]): + await setup_integration(hass, mock_config_entry) with pytest.raises(ValueError) as err: await hass.services.async_call( REMOTE_DOMAIN, @@ -96,9 +109,11 @@ async def test_bad_format_command( async def test_unknown_command( hass: HomeAssistant, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Test unknown service call errors.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.REMOTE]): + await setup_integration(hass, mock_config_entry) mock_device.send_command.side_effect = ValueError("bad is not a known command") with pytest.raises(ValueError) as err: diff --git a/tests/components/jvc_projector/test_select.py b/tests/components/jvc_projector/test_select.py index a52133bd688e2f..e28fcaaaf26aa1 100644 --- a/tests/components/jvc_projector/test_select.py +++ b/tests/components/jvc_projector/test_select.py @@ -1,6 +1,6 @@ """Tests for JVC Projector select platform.""" -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch from jvcprojector import const @@ -9,10 +9,17 @@ DOMAIN as SELECT_DOMAIN, SERVICE_SELECT_OPTION, ) -from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_OPTION +from homeassistant.const import ( + ATTR_ENTITY_ID, + ATTR_FRIENDLY_NAME, + ATTR_OPTION, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from . import setup_integration + from tests.common import MockConfigEntry INPUT_ENTITY_ID = "select.jvc_projector_input" @@ -22,9 +29,12 @@ async def test_input_select( hass: HomeAssistant, entity_registry: er.EntityRegistry, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Test input select.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SELECT]): + await setup_integration(hass, mock_config_entry) + entity = hass.states.get(INPUT_ENTITY_ID) assert entity assert entity.attributes.get(ATTR_FRIENDLY_NAME) == "JVC Projector Input" diff --git a/tests/components/jvc_projector/test_sensor.py b/tests/components/jvc_projector/test_sensor.py index 1827363e5ad9dd..b16ef19c68dca8 100644 --- a/tests/components/jvc_projector/test_sensor.py +++ b/tests/components/jvc_projector/test_sensor.py @@ -1,24 +1,51 @@ """Tests for the JVC Projector binary sensor device.""" -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch +import pytest +from syrupy import SnapshotAssertion + +from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from tests.common import MockConfigEntry +from . import setup_integration -POWER_ID = "sensor.jvc_projector_power_status" +from tests.common import MockConfigEntry, snapshot_platform +@pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_entity_state( hass: HomeAssistant, + snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry, mock_device: MagicMock, - mock_integration: MockConfigEntry, + mock_config_entry: MockConfigEntry, ) -> None: """Tests entity state is registered.""" - state = hass.states.get(POWER_ID) - assert state - assert entity_registry.async_get(state.entity_id) + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SENSOR]): + await setup_integration(hass, mock_config_entry) + + # use a snapshot to validate state of entities + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +async def test_disabled_entity( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_device: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Tests entity is disabled by default.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SENSOR]): + await setup_integration(hass, mock_config_entry) + ANAMORPHIC_ID = "sensor.jvc_projector_anamorphic_mode" + + assert hass.states.get(ANAMORPHIC_ID) is None - assert state.state == "standby" + # Entity should exist in registry but be disabled + entity = entity_registry.async_get(ANAMORPHIC_ID) + assert entity + assert entity.disabled + assert entity.entity_category == "diagnostic" From ac80242bb836214185d60fd0d9f62881e20d9211 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:09:28 +0000 Subject: [PATCH 06/16] improve sensors --- .../components/jvc_projector/binary_sensor.py | 70 +++++-- .../components/jvc_projector/sensor.py | 30 --- .../components/jvc_projector/strings.json | 30 +-- .../snapshots/test_binary_sensor.ambr | 186 ++++++++++++++++++ .../jvc_projector/snapshots/test_sensor.ambr | 168 ---------------- .../jvc_projector/test_binary_sensor.py | 30 ++- 6 files changed, 274 insertions(+), 240 deletions(-) create mode 100644 tests/components/jvc_projector/snapshots/test_binary_sensor.ambr diff --git a/homeassistant/components/jvc_projector/binary_sensor.py b/homeassistant/components/jvc_projector/binary_sensor.py index 6dfac63892bec0..6a24e477680bc6 100644 --- a/homeassistant/components/jvc_projector/binary_sensor.py +++ b/homeassistant/components/jvc_projector/binary_sensor.py @@ -2,41 +2,89 @@ from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass + from jvcprojector import const -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity -ON_STATUS = (const.ON, const.WARMING) + +@dataclass(frozen=True, kw_only=True) +class JVCBinarySensorEntityDescription(BinarySensorEntityDescription): + """Describe JVC binary sensor entity.""" + + value_fn: Callable[[str | None], bool | None] = lambda x: x == "on" + + +JVC_BINARY_SENSORS = ( + JVCBinarySensorEntityDescription( + key=const.KEY_POWER, + translation_key="jvc_power", + device_class=BinarySensorDeviceClass.POWER, + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda x: x in (const.ON, const.WARMING) if x is not None else None, + ), + JVCBinarySensorEntityDescription( + key=const.KEY_LOW_LATENCY, + translation_key="jvc_low_latency_status", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda x: x == const.ON if x is not None else None, + ), + JVCBinarySensorEntityDescription( + key=const.KEY_ESHIFT, + translation_key="jvc_eshift", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda x: x == const.ON if x is not None else None, + ), + JVCBinarySensorEntityDescription( + key=const.KEY_SOURCE, + translation_key="jvc_source_status", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda x: x == const.SIGNAL if x is not None else None, + ), +) async def async_setup_entry( hass: HomeAssistant, entry: JVCConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: - """Set up the JVC Projector platform from a config entry.""" + """Set up the JVC Projector binary sensor platform from a config entry.""" coordinator = entry.runtime_data - - async_add_entities([JvcBinarySensor(coordinator)]) + async_add_entities( + JvcBinarySensor(coordinator, description) for description in JVC_BINARY_SENSORS + ) class JvcBinarySensor(JvcProjectorEntity, BinarySensorEntity): """The entity class for JVC Projector Binary Sensor.""" - _attr_translation_key = "jvc_power" + entity_description: JVCBinarySensorEntityDescription def __init__( self, coordinator: JvcProjectorDataUpdateCoordinator, + description: JVCBinarySensorEntityDescription, ) -> None: - """Initialize the JVC Projector sensor.""" + """Initialize the JVC Projector binary sensor.""" super().__init__(coordinator) - self._attr_unique_id = f"{coordinator.device.mac}_power" + self.entity_description = description + self._attr_unique_id = f"{coordinator.unique_id}_{description.key}" @property - def is_on(self) -> bool: - """Return true if the JVC is on.""" - return self.coordinator.data["power"] in ON_STATUS + def is_on(self) -> bool | None: + """Return true if the binary sensor is on.""" + value = self.coordinator.data.get(self.entity_description.key) + if value is None: + return None + return self.entity_description.value_fn(value) diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 207e0d3eb61678..e8f596a72f71d1 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -50,46 +50,16 @@ class JVCSensorEntityDescription(SensorEntityDescription): const.HDMI2, ], ), - JVCSensorEntityDescription( - key=const.KEY_SOURCE, - translation_key="jvc_source_status", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.SIGNAL, - const.NOSIGNAL, - ], - ), JVCSensorEntityDescription( key=const.KEY_PICTURE_MODE, translation_key="jvc_picture_mode", entity_category=EntityCategory.DIAGNOSTIC, ), - JVCSensorEntityDescription( - key=const.KEY_LOW_LATENCY, - translation_key="jvc_low_latency_status", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.OFF, - const.ON, - ], - ), JVCSensorEntityDescription( key=const.KEY_INSTALLATION_MODE, translation_key="jvc_installation_mode", entity_category=EntityCategory.DIAGNOSTIC, ), - JVCSensorEntityDescription( - key=const.KEY_ESHIFT, - translation_key="jvc_eshift", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.OFF, - const.ON, - ], - ), JVCSensorEntityDescription( key=const.KEY_LASER_DIMMING, translation_key="jvc_laser_dimming_mode", diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index ea80e2066e406a..6328c5a35d6dd5 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -36,6 +36,15 @@ "binary_sensor": { "jvc_power": { "name": "[%key:component::sensor::entity_component::power::name%]" + }, + "jvc_source_status": { + "name": "Source status" + }, + "jvc_low_latency_status": { + "name": "Low latency" + }, + "jvc_eshift": { + "name": "eShift" } }, "select": { @@ -65,23 +74,9 @@ "hdmi2": "HDMI 2" } }, - "jvc_source_status": { - "name": "Source status", - "state": { - "signal": "Signal", - "no_signal": "No signal" - } - }, "jvc_picture_mode": { "name": "Picture mode" }, - "jvc_low_latency_status": { - "name": "Low latency", - "state": { - "off": "[%key:common::state::off%]", - "on": "[%key:common::state::on%]" - } - }, "jvc_installation_mode": { "name": "Installation mode" }, @@ -134,13 +129,6 @@ "yuv": "YUV" } }, - "jvc_eshift": { - "name": "eShift", - "state": { - "off": "[%key:common::state::off%]", - "on": "[%key:common::state::on%]" - } - }, "jvc_laser_dimming_mode": { "name": "Laser dimming", "state": { diff --git a/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000000..0a3c116cc39a51 --- /dev/null +++ b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr @@ -0,0 +1,186 @@ +# serializer version: 1 +# name: test_binary_sensor_states[binary_sensor.jvc_projector_eshift-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.jvc_projector_eshift', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'eShift', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_eshift', + 'unique_id': 'jvcmac_eshift', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_eshift-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector eShift', + }), + 'context': , + 'entity_id': 'binary_sensor.jvc_projector_eshift', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_low_latency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.jvc_projector_low_latency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Low latency', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_low_latency_status', + 'unique_id': 'jvcmac_low_latency', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_low_latency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Low latency', + }), + 'context': , + 'entity_id': 'binary_sensor.jvc_projector_low_latency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.jvc_projector_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_power', + 'unique_id': 'jvcmac_power', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'JVC Projector Power', + }), + 'context': , + 'entity_id': 'binary_sensor.jvc_projector_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_source_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.jvc_projector_source_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Source status', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_source_status', + 'unique_id': 'jvcmac_source', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_source_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector Source status', + }), + 'context': , + 'entity_id': 'binary_sensor.jvc_projector_source_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/jvc_projector/snapshots/test_sensor.ambr b/tests/components/jvc_projector/snapshots/test_sensor.ambr index b172d11c03f6e1..77b0d5c8bc000e 100644 --- a/tests/components/jvc_projector/snapshots/test_sensor.ambr +++ b/tests/components/jvc_projector/snapshots/test_sensor.ambr @@ -215,62 +215,6 @@ 'state': 'rgb', }) # --- -# name: test_entity_state[sensor.jvc_projector_eshift-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'off', - 'on', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_eshift', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'eShift', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_eshift', - 'unique_id': 'jvcmac_eshift', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_eshift-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector eShift', - 'options': list([ - 'off', - 'on', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_eshift', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'on', - }) -# --- # name: test_entity_state[sensor.jvc_projector_graphics_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -941,62 +885,6 @@ 'state': '100', }) # --- -# name: test_entity_state[sensor.jvc_projector_low_latency-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'off', - 'on', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_low_latency', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Low latency', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_low_latency_status', - 'unique_id': 'jvcmac_low_latency', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_low_latency-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector Low latency', - 'options': list([ - 'off', - 'on', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_low_latency', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'off', - }) -# --- # name: test_entity_state[sensor.jvc_projector_motion_enhance-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1163,59 +1051,3 @@ 'state': 'standby', }) # --- -# name: test_entity_state[sensor.jvc_projector_source_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'signal', - 'nosignal', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_source_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Source status', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_source_status', - 'unique_id': 'jvcmac_source', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_source_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector Source status', - 'options': list([ - 'signal', - 'nosignal', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_source_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'signal', - }) -# --- diff --git a/tests/components/jvc_projector/test_binary_sensor.py b/tests/components/jvc_projector/test_binary_sensor.py index 95b63433587e5a..5170fbbfe3c60d 100644 --- a/tests/components/jvc_projector/test_binary_sensor.py +++ b/tests/components/jvc_projector/test_binary_sensor.py @@ -1,29 +1,39 @@ -"""Tests for the JVC Projector binary sensor device.""" +"""Tests for the JVC Projector binary sensor devices.""" from unittest.mock import MagicMock, patch +from syrupy import SnapshotAssertion + from homeassistant.const import Platform from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er +import homeassistant.helpers.entity_registry as er from . import setup_integration -from tests.common import MockConfigEntry - -ENTITY_ID = "binary_sensor.jvc_projector_power" +from tests.common import MockConfigEntry, snapshot_platform -async def test_entity_state( +async def test_binary_sensor_states( hass: HomeAssistant, + snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry, mock_device: MagicMock, mock_config_entry: MockConfigEntry, ) -> None: - """Tests entity state is registered.""" + """Test setup of the binary sensor entities and their states.""" + # Set up mock device with all binary sensor states + mock_device.get_state.return_value = { + "power": "standby", + "low_latency": "off", + "eshift": "on", + "source": "signal", + } + + # Set up integration with only binary sensor platform with patch( "homeassistant.components.jvc_projector.PLATFORMS", [Platform.BINARY_SENSOR] ): await setup_integration(hass, mock_config_entry) - entity = hass.states.get(ENTITY_ID) - assert entity - assert entity_registry.async_get(entity.entity_id) + + # Validate all binary sensor states via snapshot + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) From cefd366b8b479c6951f0583a58b390ff25c41de8 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 24 Nov 2024 05:39:24 +0000 Subject: [PATCH 07/16] add new selects --- .../components/jvc_projector/select.py | 38 +++++++-- .../components/jvc_projector/strings.json | 51 +++++++++++- .../snapshots/test_binary_sensor.ambr | 4 +- tests/components/jvc_projector/test_select.py | 83 +++++++++++++------ 4 files changed, 140 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 60c80f98fc0702..3006dabb25a3e2 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -23,17 +23,41 @@ class JvcProjectorSelectDescription(SelectEntityDescription): command: Callable[[JvcProjector, str], Awaitable[None]] -OPTIONS: Final[dict[str, dict[str, str]]] = { - "input": {const.HDMI1: const.REMOTE_HDMI_1, const.HDMI2: const.REMOTE_HDMI_2} +# these options correspond to a command and its possible values +OPTIONS: Final[dict[str, list[str]]] = { + "input": [const.HDMI1, const.HDMI2], + "eshift": [const.ON, const.OFF], + "installation_mode": [f"mode{i}" for i in range(1, 11)], + "anamorphic": [ + const.ANAMORPHIC_A, + const.ANAMORPHIC_B, + const.OFF, + const.ANAMORPHIC_C, + const.ANAMORPHIC_D, + ], + "laser_power": [const.LOW, const.MEDIUM, const.HIGH], + "laser_dimming": [const.OFF, const.AUTO1, const.AUTO2, const.AUTO3], } + +def create_select_command(key: str) -> Callable[[JvcProjector, str], Awaitable[None]]: + """Create a command function for a select.""" + + async def command(device: JvcProjector, option: str) -> None: + await device.send_command(key, option) + + return command + + +# create a select for each option defined SELECTS: Final[list[JvcProjectorSelectDescription]] = [ JvcProjectorSelectDescription( - key="input", - translation_key="input", - options=list(OPTIONS["input"]), - command=lambda device, option: device.remote(OPTIONS["input"][option]), + key=key, + translation_key=key, + options=list(options), + command=create_select_command(key), ) + for key, options in OPTIONS.items() ] @@ -68,7 +92,7 @@ def __init__( @property def current_option(self) -> str | None: """Return the selected entity option to represent the entity state.""" - return self.coordinator.data[self.entity_description.key] + return self.coordinator.data.get(self.entity_description.key) async def async_select_option(self, option: str) -> None: """Change the selected option.""" diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index 6328c5a35d6dd5..040ea6fb997b9c 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -44,7 +44,7 @@ "name": "Low latency" }, "jvc_eshift": { - "name": "eShift" + "name": "eshift" } }, "select": { @@ -54,6 +54,55 @@ "hdmi1": "HDMI 1", "hdmi2": "HDMI 2" } + }, + "eshift": { + "name": "Eshift", + "state": { + "on": "On", + "off": "Off" + } + }, + "installation_mode": { + "name": "Installation Mode", + "state": { + "mode1": "Mode 1", + "mode2": "Mode 2", + "mode3": "Mode 3", + "mode4": "Mode 4", + "mode5": "Mode 5", + "mode6": "Mode 6", + "mode7": "Mode 7", + "mode8": "Mode 8", + "mode9": "Mode 9", + "mode10": "Mode 10" + } + }, + "anamorphic": { + "name": "Anamorphic", + "state": { + "off": "Off", + "a": "Mode A", + "b": "Mode B", + "c": "Mode C", + "d": "Mode D" + } + }, + "laser_power": { + "name": "Laser Power", + "state": { + "low": "Low", + "medium": "Medium", + "high": "High" + } + }, + "laser_dimming": { + "name": "Laser Dimming", + "state": { + "off": "Off", + "auto1": "Auto 1", + "auto2": "Auto 2", + "auto3": "Auto 3" + } } }, "sensor": { diff --git a/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr index 0a3c116cc39a51..d279f669c39dc9 100644 --- a/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr +++ b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr @@ -23,7 +23,7 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'eShift', + 'original_name': 'eshift', 'platform': 'jvc_projector', 'previous_unique_id': None, 'supported_features': 0, @@ -35,7 +35,7 @@ # name: test_binary_sensor_states[binary_sensor.jvc_projector_eshift-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'JVC Projector eShift', + 'friendly_name': 'JVC Projector eshift', }), 'context': , 'entity_id': 'binary_sensor.jvc_projector_eshift', diff --git a/tests/components/jvc_projector/test_select.py b/tests/components/jvc_projector/test_select.py index e28fcaaaf26aa1..8efed81688090a 100644 --- a/tests/components/jvc_projector/test_select.py +++ b/tests/components/jvc_projector/test_select.py @@ -4,17 +4,13 @@ from jvcprojector import const +from homeassistant.components.jvc_projector.select import OPTIONS from homeassistant.components.select import ( ATTR_OPTIONS, DOMAIN as SELECT_DOMAIN, SERVICE_SELECT_OPTION, ) -from homeassistant.const import ( - ATTR_ENTITY_ID, - ATTR_FRIENDLY_NAME, - ATTR_OPTION, - Platform, -) +from homeassistant.const import ATTR_ENTITY_ID, ATTR_OPTION, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -22,33 +18,68 @@ from tests.common import MockConfigEntry -INPUT_ENTITY_ID = "select.jvc_projector_input" + +async def test_all_selects( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_device: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test all selects are created correctly.""" + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SELECT]): + await setup_integration(hass, mock_config_entry) + + # Test each defined select entity + for cmd_key, expected_options in OPTIONS.items(): + entity_id = f"select.jvc_projector_{cmd_key}" + entity = hass.states.get(entity_id) + assert entity, f"Entity {entity_id} was not created" + + # Verify the entity's options + assert entity.attributes.get(ATTR_OPTIONS) == expected_options + + # Verify the current state matches what's in the mock device + expected_state = mock_device.get_state.return_value.get(cmd_key) + if expected_state: + assert entity.state == expected_state -async def test_input_select( +async def test_select_option( hass: HomeAssistant, entity_registry: er.EntityRegistry, mock_device: MagicMock, mock_config_entry: MockConfigEntry, ) -> None: - """Test input select.""" + """Test selecting an option for each select.""" with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SELECT]): await setup_integration(hass, mock_config_entry) - entity = hass.states.get(INPUT_ENTITY_ID) - assert entity - assert entity.attributes.get(ATTR_FRIENDLY_NAME) == "JVC Projector Input" - assert entity.attributes.get(ATTR_OPTIONS) == [const.HDMI1, const.HDMI2] - assert entity.state == const.HDMI1 - - await hass.services.async_call( - SELECT_DOMAIN, - SERVICE_SELECT_OPTION, - { - ATTR_ENTITY_ID: INPUT_ENTITY_ID, - ATTR_OPTION: const.HDMI2, - }, - blocking=True, - ) - - mock_device.remote.assert_called_once_with(const.REMOTE_HDMI_2) + # Test each select's option selection + test_cases = [ + ("input", const.HDMI2), + ("eshift", const.OFF), + ("laser_power", const.HIGH), + ("installation_mode", "mode2"), + ("anamorphic", const.ANAMORPHIC_A), + ("laser_dimming", const.AUTO1), + ] + + for cmd_key, test_value in test_cases: + entity_id = f"select.jvc_projector_{cmd_key}" + + # Call the service to change the option + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: entity_id, + ATTR_OPTION: test_value, + }, + blocking=True, + ) + + # Verify the command was sent + mock_device.send_command.assert_any_call(cmd_key, test_value) + + # Reset the mock for the next test + mock_device.send_command.reset_mock() From 6b3fc916a6962c144e4ea1d4848931720aae2377 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:55:52 +0000 Subject: [PATCH 08/16] use built in consts --- .../components/jvc_projector/select.py | 20 +++++++----------- .../components/jvc_projector/sensor.py | 21 +++---------------- .../jvc_projector/snapshots/test_sensor.ambr | 4 ++-- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 3006dabb25a3e2..dbd22adfb7ab8f 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -24,22 +24,18 @@ class JvcProjectorSelectDescription(SelectEntityDescription): # these options correspond to a command and its possible values +# note low latency is intentionally excluded because you can't just turn it on you need to meet conditions first so you should instead switch picture modes OPTIONS: Final[dict[str, list[str]]] = { - "input": [const.HDMI1, const.HDMI2], - "eshift": [const.ON, const.OFF], - "installation_mode": [f"mode{i}" for i in range(1, 11)], - "anamorphic": [ - const.ANAMORPHIC_A, - const.ANAMORPHIC_B, - const.OFF, - const.ANAMORPHIC_C, - const.ANAMORPHIC_D, - ], - "laser_power": [const.LOW, const.MEDIUM, const.HIGH], - "laser_dimming": [const.OFF, const.AUTO1, const.AUTO2, const.AUTO3], + "input": const.VAL_FUNCTION_INPUT, + "eshift": const.VAL_TOGGLE, + "installation_mode": const.VAL_INSTALLATION_MODE, + "anamorphic": const.VAL_ANAMORPHIC, + "laser_power": const.VAL_LASER_POWER, + "laser_dimming": const.VAL_LASER_DIMMING, } +# type safe command function for a select def create_select_command(key: str) -> Callable[[JvcProjector, str], Awaitable[None]]: """Create a command function for a select.""" diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index e8f596a72f71d1..93640d19785bfe 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -32,23 +32,14 @@ class JVCSensorEntityDescription(SensorEntityDescription): translation_key="jvc_power_status", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.STANDBY, - const.ON, - const.WARMING, - const.COOLING, - const.ERROR, - ], + options=const.VAL_POWER, ), JVCSensorEntityDescription( key=const.KEY_INPUT, translation_key="jvc_hdmi_input", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.HDMI1, - const.HDMI2, - ], + options=const.VAL_FUNCTION_INPUT, ), JVCSensorEntityDescription( key=const.KEY_PICTURE_MODE, @@ -97,13 +88,7 @@ class JVCSensorEntityDescription(SensorEntityDescription): translation_key="jvc_anamorphic_mode", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.OFF, - const.ANAMORPHIC_A, - const.ANAMORPHIC_B, - const.ANAMORPHIC_C, - const.ANAMORPHIC_D, - ], + options=const.VAL_ANAMORPHIC, enabled_default=False, ), JVCSensorEntityDescription( diff --git a/tests/components/jvc_projector/snapshots/test_sensor.ambr b/tests/components/jvc_projector/snapshots/test_sensor.ambr index 77b0d5c8bc000e..512ac535288907 100644 --- a/tests/components/jvc_projector/snapshots/test_sensor.ambr +++ b/tests/components/jvc_projector/snapshots/test_sensor.ambr @@ -998,8 +998,8 @@ 'options': list([ 'standby', 'on', - 'warming', 'cooling', + 'warming', 'error', ]), }), @@ -1038,8 +1038,8 @@ 'options': list([ 'standby', 'on', - 'warming', 'cooling', + 'warming', 'error', ]), }), From db95f376e441a1da9172fc971afb0f6bc20a8c7b Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:20:50 +0000 Subject: [PATCH 09/16] fix imports --- homeassistant/components/jvc_projector/__init__.py | 3 ++- .../components/jvc_projector/config_flow.py | 4 ++-- .../components/jvc_projector/coordinator.py | 12 +++++------- homeassistant/components/jvc_projector/entity.py | 2 +- homeassistant/components/jvc_projector/select.py | 2 +- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/jvc_projector/__init__.py b/homeassistant/components/jvc_projector/__init__.py index 09e93127e40d5c..b035cce3a9aa6d 100644 --- a/homeassistant/components/jvc_projector/__init__.py +++ b/homeassistant/components/jvc_projector/__init__.py @@ -2,7 +2,8 @@ from __future__ import annotations -from jvcprojector import JvcProjector, JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector.device import JvcProjectorAuthError +from jvcprojector.projector import JvcProjector, JvcProjectorConnectError from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( diff --git a/homeassistant/components/jvc_projector/config_flow.py b/homeassistant/components/jvc_projector/config_flow.py index d508df7a4affad..2ec3e50cd58db2 100644 --- a/homeassistant/components/jvc_projector/config_flow.py +++ b/homeassistant/components/jvc_projector/config_flow.py @@ -5,8 +5,8 @@ from collections.abc import Mapping from typing import Any -from jvcprojector import JvcProjector, JvcProjectorAuthError, JvcProjectorConnectError -from jvcprojector.projector import DEFAULT_PORT +from jvcprojector.device import JvcProjectorAuthError +from jvcprojector.projector import DEFAULT_PORT, JvcProjector, JvcProjectorConnectError import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult diff --git a/homeassistant/components/jvc_projector/coordinator.py b/homeassistant/components/jvc_projector/coordinator.py index 874253b3324b8d..745471d874f788 100644 --- a/homeassistant/components/jvc_projector/coordinator.py +++ b/homeassistant/components/jvc_projector/coordinator.py @@ -5,12 +5,8 @@ from datetime import timedelta import logging -from jvcprojector import ( - JvcProjector, - JvcProjectorAuthError, - JvcProjectorConnectError, - const, -) +from jvcprojector.device import JvcProjectorAuthError +from jvcprojector.projector import JvcProjector, JvcProjectorConnectError, const from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed @@ -43,7 +39,9 @@ def __init__(self, hass: HomeAssistant, device: JvcProjector) -> None: async def _async_update_data(self) -> dict[str, str]: """Get the latest state data.""" try: - state = await self.device.get_state() + state_mapping = await self.device.get_state() + # Convert Mapping[str, str | None] to dict[str, str] + state = {k: v if v is not None else "" for k, v in state_mapping.items()} except JvcProjectorConnectError as err: raise UpdateFailed(f"Unable to connect to {self.device.host}") from err except JvcProjectorAuthError as err: diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index d484d76aaee36e..dc19e1d48a8edc 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -4,7 +4,7 @@ import logging -from jvcprojector import JvcProjector +from jvcprojector.projector import JvcProjector from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index dbd22adfb7ab8f..3ae2ed4b23d9bc 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from typing import Final -from jvcprojector import JvcProjector, const +from jvcprojector.projector import JvcProjector, const from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.core import HomeAssistant From c3470d17584b4f6644264a5820db7df5d727844e Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Thu, 28 Nov 2024 04:45:34 +0000 Subject: [PATCH 10/16] fix enum errors --- homeassistant/components/jvc_projector/coordinator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/jvc_projector/coordinator.py b/homeassistant/components/jvc_projector/coordinator.py index 745471d874f788..4191675f7b1c18 100644 --- a/homeassistant/components/jvc_projector/coordinator.py +++ b/homeassistant/components/jvc_projector/coordinator.py @@ -40,8 +40,8 @@ async def _async_update_data(self) -> dict[str, str]: """Get the latest state data.""" try: state_mapping = await self.device.get_state() - # Convert Mapping[str, str | None] to dict[str, str] - state = {k: v if v is not None else "" for k, v in state_mapping.items()} + # Only include non-None values in the final state dict + state = {k: v for k, v in state_mapping.items() if v is not None} except JvcProjectorConnectError as err: raise UpdateFailed(f"Unable to connect to {self.device.host}") from err except JvcProjectorAuthError as err: From 96b4908cf47e57f6b30a53752e2d76678ea02e40 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Thu, 28 Nov 2024 05:02:41 +0000 Subject: [PATCH 11/16] remove redundant sensors --- .../components/jvc_projector/sensor.py | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 93640d19785bfe..349edf5b344260 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -34,42 +34,16 @@ class JVCSensorEntityDescription(SensorEntityDescription): entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_POWER, ), - JVCSensorEntityDescription( - key=const.KEY_INPUT, - translation_key="jvc_hdmi_input", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_FUNCTION_INPUT, - ), JVCSensorEntityDescription( key=const.KEY_PICTURE_MODE, translation_key="jvc_picture_mode", entity_category=EntityCategory.DIAGNOSTIC, ), - JVCSensorEntityDescription( - key=const.KEY_INSTALLATION_MODE, - translation_key="jvc_installation_mode", - entity_category=EntityCategory.DIAGNOSTIC, - ), - JVCSensorEntityDescription( - key=const.KEY_LASER_DIMMING, - translation_key="jvc_laser_dimming_mode", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_LASER_DIMMING, - ), JVCSensorEntityDescription( key=const.KEY_LASER_VALUE, translation_key="jvc_laser_value", entity_category=EntityCategory.DIAGNOSTIC, ), - JVCSensorEntityDescription( - key=const.KEY_LASER_POWER, - translation_key="jvc_laser_power", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_LASER_POWER, - ), JVCSensorEntityDescription( key=const.KEY_LASER_TIME, translation_key="jvc_laser_time", @@ -83,14 +57,6 @@ class JVCSensorEntityDescription(SensorEntityDescription): options=const.VAL_HDR_CONTENT_TYPE, ), # niche sensors that are disabled by default - JVCSensorEntityDescription( - key=const.KEY_ANAMORPHIC, - translation_key="jvc_anamorphic_mode", - device_class=SensorDeviceClass.ENUM, - entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_ANAMORPHIC, - enabled_default=False, - ), JVCSensorEntityDescription( key=const.KEY_HDR, translation_key="jvc_hdr_mode", From 6af8e31a390aa29979740f0814c56f16987d5bf4 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Fri, 20 Dec 2024 23:37:11 +0000 Subject: [PATCH 12/16] fix sensor references and names --- .../components/jvc_projector/sensor.py | 13 +++++-------- .../components/jvc_projector/strings.json | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 349edf5b344260..7233bfbc769243 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -43,11 +43,13 @@ class JVCSensorEntityDescription(SensorEntityDescription): key=const.KEY_LASER_VALUE, translation_key="jvc_laser_value", entity_category=EntityCategory.DIAGNOSTIC, + enabled_default=False, ), JVCSensorEntityDescription( key=const.KEY_LASER_TIME, translation_key="jvc_laser_time", entity_category=EntityCategory.DIAGNOSTIC, + enabled_default=False, ), JVCSensorEntityDescription( key=const.KEY_HDR_CONTENT_TYPE, @@ -55,6 +57,7 @@ class JVCSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=const.VAL_HDR_CONTENT_TYPE, + enabled_default=False, ), # niche sensors that are disabled by default JVCSensorEntityDescription( @@ -62,13 +65,7 @@ class JVCSensorEntityDescription(SensorEntityDescription): translation_key="jvc_hdr_mode", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=[ - const.HDR_CONTENT_NONE, - const.HDR_CONTENT_HDR10, - const.HDR_CONTENT_HDR10PLUS, - const.HDR_CONTENT_HLG, - const.HDR_CONTENT_SDR, - ], + options=const.VAL_HDR_MODES, enabled_default=False, ), JVCSensorEntityDescription( @@ -128,7 +125,7 @@ class JVCSensorEntityDescription(SensorEntityDescription): translation_key="jvc_hdr_processing_mode", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, - options=const.VAL_HDR_PROCESSING, + options=["0", "1", "2", "3"], # translated enabled_default=False, ), ) diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index 040ea6fb997b9c..b8cacb03e1e526 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -44,7 +44,7 @@ "name": "Low latency" }, "jvc_eshift": { - "name": "eshift" + "name": "e-shift" } }, "select": { @@ -165,10 +165,12 @@ "name": "Color profile" }, "jvc_graphics_mode": { - "name": "Graphics mode", + "name": "Graphic mode", "state": { "standard": "Standard", - "high-res": "High Resolution" + "high-res": "High Resolution", + "high-res2": "High Resolution 2", + "off": "[%key:common::state::off%]" } }, "jvc_color_space": { @@ -191,7 +193,7 @@ "name": "Laser value" }, "jvc_laser_power": { - "name": "Laser power", + "name": "Laser/Lamp power", "state": { "low": "Low", "medium": "Medium", @@ -199,7 +201,7 @@ } }, "jvc_laser_time": { - "name": "Laser time" + "name": "Laser/Lamp time" }, "jvc_motion_enhance": { "name": "Motion enhance", @@ -222,9 +224,10 @@ "jvc_hdr_processing_mode": { "name": "HDR processing", "state": { - "static": "Static", - "frame": "Frame by Frame", - "scene": "Scene by Scene" + "0": "HDR10+", + "1": "Static", + "2": "Frame by Frame", + "3": "Scene by Scene" } }, "jvc_hdr_content_type": { From a6cc222013e7222c1cabcc224f2c1d8b74e2099d Mon Sep 17 00:00:00 2001 From: Steve Easley Date: Sun, 22 Dec 2024 14:24:05 -0500 Subject: [PATCH 13/16] Detect model when enabling entities --- .../components/jvc_projector/__init__.py | 1 + .../components/jvc_projector/binary_sensor.py | 7 ++ .../components/jvc_projector/entity.py | 10 +++ .../components/jvc_projector/icons.json | 6 ++ .../components/jvc_projector/select.py | 72 +++++++++++++------ .../components/jvc_projector/strings.json | 2 +- 6 files changed, 74 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/jvc_projector/__init__.py b/homeassistant/components/jvc_projector/__init__.py index b035cce3a9aa6d..c24818fd70f943 100644 --- a/homeassistant/components/jvc_projector/__init__.py +++ b/homeassistant/components/jvc_projector/__init__.py @@ -29,6 +29,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool: host=entry.data[CONF_HOST], port=entry.data[CONF_PORT], password=entry.data[CONF_PASSWORD], + timeout=1, ) try: diff --git a/homeassistant/components/jvc_projector/binary_sensor.py b/homeassistant/components/jvc_projector/binary_sensor.py index 6a24e477680bc6..f2c54c2140fd49 100644 --- a/homeassistant/components/jvc_projector/binary_sensor.py +++ b/homeassistant/components/jvc_projector/binary_sensor.py @@ -25,6 +25,7 @@ class JVCBinarySensorEntityDescription(BinarySensorEntityDescription): """Describe JVC binary sensor entity.""" value_fn: Callable[[str | None], bool | None] = lambda x: x == "on" + enabled_default: bool | Callable[[JvcProjectorEntity], bool] = True JVC_BINARY_SENSORS = ( @@ -46,6 +47,7 @@ class JVCBinarySensorEntityDescription(BinarySensorEntityDescription): translation_key="jvc_eshift", entity_category=EntityCategory.DIAGNOSTIC, value_fn=lambda x: x == const.ON if x is not None else None, + enabled_default=JvcProjectorEntity.has_eshift, ), JVCBinarySensorEntityDescription( key=const.KEY_SOURCE, @@ -80,6 +82,11 @@ def __init__( super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{coordinator.unique_id}_{description.key}" + self._attr_entity_registry_enabled_default = ( + description.enabled_default(self) + if callable(description.enabled_default) + else description.enabled_default + ) @property def is_on(self) -> bool | None: diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index dc19e1d48a8edc..8d77cb4e0a715d 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -38,3 +38,13 @@ def __init__(self, coordinator: JvcProjectorDataUpdateCoordinator) -> None: def device(self) -> JvcProjector: """Return the device representing the projector.""" return self.coordinator.device + + @staticmethod + def has_eshift(entity: JvcProjectorEntity) -> bool: + """Return if device has e-shift.""" + return "NZ" in entity.device.model + + @staticmethod + def has_laser(entity: JvcProjectorEntity) -> bool: + """Return if device has laser.""" + return "NZ" in entity.device.model or "NX9" in entity.device.model diff --git a/homeassistant/components/jvc_projector/icons.json b/homeassistant/components/jvc_projector/icons.json index a0404b328e1419..4fca5d00572afe 100644 --- a/homeassistant/components/jvc_projector/icons.json +++ b/homeassistant/components/jvc_projector/icons.json @@ -11,6 +11,12 @@ "select": { "input": { "default": "mdi:hdmi-port" + }, + "anamorphic": { + "default": "mdi:stretch-to-page-outline" + }, + "laser_power": { + "default": "mdi:brightness-5" } }, "sensor": { diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 3ae2ed4b23d9bc..2b3f0de45b01d4 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -4,7 +4,6 @@ from collections.abc import Awaitable, Callable from dataclasses import dataclass -from typing import Final from jvcprojector.projector import JvcProjector, const @@ -21,18 +20,7 @@ class JvcProjectorSelectDescription(SelectEntityDescription): """Describes JVC Projector select entities.""" command: Callable[[JvcProjector, str], Awaitable[None]] - - -# these options correspond to a command and its possible values -# note low latency is intentionally excluded because you can't just turn it on you need to meet conditions first so you should instead switch picture modes -OPTIONS: Final[dict[str, list[str]]] = { - "input": const.VAL_FUNCTION_INPUT, - "eshift": const.VAL_TOGGLE, - "installation_mode": const.VAL_INSTALLATION_MODE, - "anamorphic": const.VAL_ANAMORPHIC, - "laser_power": const.VAL_LASER_POWER, - "laser_dimming": const.VAL_LASER_DIMMING, -} + enabled_default: bool | Callable[[JvcProjectorEntity], bool] = True # type safe command function for a select @@ -45,16 +33,48 @@ async def command(device: JvcProjector, option: str) -> None: return command -# create a select for each option defined -SELECTS: Final[list[JvcProjectorSelectDescription]] = [ +# these options correspond to a command and its possible values +# note low latency is intentionally excluded because you can't just turn it on you need to meet conditions first so you should instead switch picture modes +JVC_SELECTS = ( JvcProjectorSelectDescription( - key=key, - translation_key=key, - options=list(options), - command=create_select_command(key), - ) - for key, options in OPTIONS.items() -] + key=const.KEY_INPUT, + translation_key=const.KEY_INPUT, + options=const.VAL_FUNCTION_INPUT, + command=create_select_command(const.KEY_INPUT), + ), + JvcProjectorSelectDescription( + key=const.KEY_INSTALLATION_MODE, + translation_key=const.KEY_INSTALLATION_MODE, + options=const.VAL_INSTALLATION_MODE, + command=create_select_command(const.KEY_INSTALLATION_MODE), + ), + JvcProjectorSelectDescription( + key=const.KEY_ANAMORPHIC, + translation_key=const.KEY_ANAMORPHIC, + options=const.VAL_ANAMORPHIC, + command=create_select_command(const.KEY_ANAMORPHIC), + ), + JvcProjectorSelectDescription( + key=const.KEY_ESHIFT, + translation_key=const.KEY_ESHIFT, + options=const.VAL_TOGGLE, + command=create_select_command(const.KEY_ESHIFT), + enabled_default=JvcProjectorEntity.has_eshift, + ), + JvcProjectorSelectDescription( + key=const.KEY_LASER_POWER, + translation_key=const.KEY_LASER_POWER, + options=const.VAL_LASER_POWER, + command=create_select_command(const.KEY_LASER_POWER), + ), + JvcProjectorSelectDescription( + key=const.KEY_LASER_DIMMING, + translation_key=const.KEY_LASER_DIMMING, + options=const.VAL_LASER_DIMMING, + command=create_select_command(const.KEY_LASER_DIMMING), + enabled_default=JvcProjectorEntity.has_laser, + ), +) async def async_setup_entry( @@ -66,7 +86,8 @@ async def async_setup_entry( coordinator = entry.runtime_data async_add_entities( - JvcProjectorSelectEntity(coordinator, description) for description in SELECTS + JvcProjectorSelectEntity(coordinator, description) + for description in JVC_SELECTS ) @@ -84,6 +105,11 @@ def __init__( super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{coordinator.unique_id}_{description.key}" + self._attr_entity_registry_enabled_default = ( + description.enabled_default(self) + if callable(description.enabled_default) + else description.enabled_default + ) @property def current_option(self) -> str | None: diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index b8cacb03e1e526..e94d1d72168ed6 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -88,7 +88,7 @@ } }, "laser_power": { - "name": "Laser Power", + "name": "Laser/Lamp Power", "state": { "low": "Low", "medium": "Medium", From 8d618cf54c0876cdf83cd3c759507e2d67710bc8 Mon Sep 17 00:00:00 2001 From: ilan <31193909+iloveicedgreentea@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:51:31 -0500 Subject: [PATCH 14/16] Add NX9 model check for e-shift --- homeassistant/components/jvc_projector/entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index 8d77cb4e0a715d..f9129c3cc2f9bd 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -42,7 +42,7 @@ def device(self) -> JvcProjector: @staticmethod def has_eshift(entity: JvcProjectorEntity) -> bool: """Return if device has e-shift.""" - return "NZ" in entity.device.model + return "NZ" in entity.device.model or "NX9" in entity.device.model #nx9 is the only lamp model with eshift @staticmethod def has_laser(entity: JvcProjectorEntity) -> bool: From 52363409bf7679c4b7f31e1865f9b17926b79070 Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:31:18 +0000 Subject: [PATCH 15/16] fix tests, separate laser key --- .../components/jvc_projector/entity.py | 18 +- .../components/jvc_projector/select.py | 12 + .../components/jvc_projector/strings.json | 9 +- tests/components/jvc_projector/__init__.py | 2 +- tests/components/jvc_projector/conftest.py | 2 +- .../snapshots/test_binary_sensor.ambr | 46 +++ .../jvc_projector/snapshots/test_sensor.ambr | 342 ++---------------- .../jvc_projector/test_config_flow.py | 2 +- .../jvc_projector/test_coordinator.py | 2 +- tests/components/jvc_projector/test_init.py | 2 +- tests/components/jvc_projector/test_select.py | 41 ++- tests/components/jvc_projector/test_sensor.py | 6 +- 12 files changed, 151 insertions(+), 333 deletions(-) diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index f9129c3cc2f9bd..435de30aee5eba 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -2,8 +2,6 @@ from __future__ import annotations -import logging - from jvcprojector.projector import JvcProjector from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo @@ -12,8 +10,6 @@ from .const import DOMAIN, MANUFACTURER, NAME from .coordinator import JvcProjectorDataUpdateCoordinator -_LOGGER = logging.getLogger(__name__) - class JvcProjectorEntity(CoordinatorEntity[JvcProjectorDataUpdateCoordinator]): """Defines a base JVC Projector entity.""" @@ -39,12 +35,14 @@ def device(self) -> JvcProjector: """Return the device representing the projector.""" return self.coordinator.device - @staticmethod - def has_eshift(entity: JvcProjectorEntity) -> bool: + @property + def has_eshift(self) -> bool: """Return if device has e-shift.""" - return "NZ" in entity.device.model or "NX9" in entity.device.model #nx9 is the only lamp model with eshift + return ( + "NZ" in self.device.model or "NX9" in self.device.model + ) # nx9 is the only lamp model with eshift - @staticmethod - def has_laser(entity: JvcProjectorEntity) -> bool: + @property + def has_laser(self) -> bool: """Return if device has laser.""" - return "NZ" in entity.device.model or "NX9" in entity.device.model + return "NZ" in self.device.model diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index 2b3f0de45b01d4..4f6757bbac88d3 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -21,6 +21,7 @@ class JvcProjectorSelectDescription(SelectEntityDescription): command: Callable[[JvcProjector, str], Awaitable[None]] enabled_default: bool | Callable[[JvcProjectorEntity], bool] = True + translation_key_override: str | None | Callable[[JvcProjectorEntity], str] = None # type safe command function for a select @@ -64,6 +65,9 @@ async def command(device: JvcProjector, option: str) -> None: JvcProjectorSelectDescription( key=const.KEY_LASER_POWER, translation_key=const.KEY_LASER_POWER, + translation_key_override=lambda entity: const.KEY_LASER_POWER + if entity.has_laser + else "lamp_power", options=const.VAL_LASER_POWER, command=create_select_command(const.KEY_LASER_POWER), ), @@ -110,6 +114,14 @@ def __init__( if callable(description.enabled_default) else description.enabled_default ) + # allow for translation key override with callable + self._attr_translation_key = ( + description.translation_key_override(self) + if callable(description.translation_key_override) + else description.translation_key_override + if description.translation_key_override is not None + else description.translation_key + ) @property def current_option(self) -> str | None: diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index e94d1d72168ed6..ee999a4a047f32 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -88,13 +88,20 @@ } }, "laser_power": { - "name": "Laser/Lamp Power", + "name": "Laser Power", "state": { "low": "Low", "medium": "Medium", "high": "High" } }, + "lamp_power": { + "name": "Lamp Power", + "state": { + "low": "Low", + "high": "High" + } + }, "laser_dimming": { "name": "Laser Dimming", "state": { diff --git a/tests/components/jvc_projector/__init__.py b/tests/components/jvc_projector/__init__.py index b981733e254146..1ea60b2fa3c555 100644 --- a/tests/components/jvc_projector/__init__.py +++ b/tests/components/jvc_projector/__init__.py @@ -8,7 +8,7 @@ MOCK_PORT = 20554 MOCK_PASSWORD = "jvcpasswd" MOCK_MAC = "jvcmac" -MOCK_MODEL = "jvcmodel" +MOCK_MODEL = "jvcmodelNZ" # used to load a single platform in a test diff --git a/tests/components/jvc_projector/conftest.py b/tests/components/jvc_projector/conftest.py index c2ccd4c1617e98..6fb4add3631f82 100644 --- a/tests/components/jvc_projector/conftest.py +++ b/tests/components/jvc_projector/conftest.py @@ -51,7 +51,7 @@ def fixture_mock_device( "color_space": "rgb", "motion_enhance": "low", "clear_motion_drive": "low", - "hdr_processing": "static", + "hdr_processing": "1", } yield device diff --git a/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr index d279f669c39dc9..6cb91c3a24c98a 100644 --- a/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr +++ b/tests/components/jvc_projector/snapshots/test_binary_sensor.ambr @@ -1,4 +1,50 @@ # serializer version: 1 +# name: test_binary_sensor_states[binary_sensor.jvc_projector_e_shift-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.jvc_projector_e_shift', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'e-shift', + 'platform': 'jvc_projector', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'jvc_eshift', + 'unique_id': 'jvcmac_eshift', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_states[binary_sensor.jvc_projector_e_shift-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'JVC Projector e-shift', + }), + 'context': , + 'entity_id': 'binary_sensor.jvc_projector_e_shift', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_binary_sensor_states[binary_sensor.jvc_projector_eshift-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/jvc_projector/snapshots/test_sensor.ambr b/tests/components/jvc_projector/snapshots/test_sensor.ambr index 512ac535288907..5caecd49da97e9 100644 --- a/tests/components/jvc_projector/snapshots/test_sensor.ambr +++ b/tests/components/jvc_projector/snapshots/test_sensor.ambr @@ -1,66 +1,4 @@ # serializer version: 1 -# name: test_entity_state[sensor.jvc_projector_anamorphic_mode-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'off', - 'a', - 'b', - 'c', - 'd', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_anamorphic_mode', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Anamorphic mode', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_anamorphic_mode', - 'unique_id': 'jvcmac_anamorphic', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_anamorphic_mode-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector Anamorphic mode', - 'options': list([ - 'off', - 'a', - 'b', - 'c', - 'd', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_anamorphic_mode', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'off', - }) -# --- # name: test_entity_state[sensor.jvc_projector_clear_motion_drive-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -215,7 +153,7 @@ 'state': 'rgb', }) # --- -# name: test_entity_state[sensor.jvc_projector_graphics_mode-entry] +# name: test_entity_state[sensor.jvc_projector_graphic_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -224,6 +162,8 @@ 'options': list([ 'standard', 'high-res', + 'high-res2', + 'off', ]), }), 'config_entry_id': , @@ -232,7 +172,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.jvc_projector_graphics_mode', + 'entity_id': 'sensor.jvc_projector_graphic_mode', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -244,7 +184,7 @@ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Graphics mode', + 'original_name': 'Graphic mode', 'platform': 'jvc_projector', 'previous_unique_id': None, 'supported_features': 0, @@ -253,18 +193,20 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity_state[sensor.jvc_projector_graphics_mode-state] +# name: test_entity_state[sensor.jvc_projector_graphic_mode-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'enum', - 'friendly_name': 'JVC Projector Graphics mode', + 'friendly_name': 'JVC Projector Graphic mode', 'options': list([ 'standard', 'high-res', + 'high-res2', + 'off', ]), }), 'context': , - 'entity_id': 'sensor.jvc_projector_graphics_mode', + 'entity_id': 'sensor.jvc_projector_graphic_mode', 'last_changed': , 'last_reported': , 'last_updated': , @@ -331,62 +273,6 @@ 'state': 'rgb', }) # --- -# name: test_entity_state[sensor.jvc_projector_hdmi_input-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'hdmi1', - 'hdmi2', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_hdmi_input', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'HDMI input', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_hdmi_input', - 'unique_id': 'jvcmac_input', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_hdmi_input-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector HDMI input', - 'options': list([ - 'hdmi1', - 'hdmi2', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_hdmi_input', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'hdmi1', - }) -# --- # name: test_entity_state[sensor.jvc_projector_hdmi_input_level-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -516,11 +402,11 @@ 'area_id': None, 'capabilities': dict({ 'options': list([ - 'none', - 'hdr10', - 'hdr10_plus', - 'hlg', 'sdr', + 'hdr', + 'smpte_st_2084', + 'hybrid_log', + 'none', ]), }), 'config_entry_id': , @@ -556,11 +442,11 @@ 'device_class': 'enum', 'friendly_name': 'JVC Projector HDR mode', 'options': list([ - 'none', - 'hdr10', - 'hdr10_plus', - 'hlg', 'sdr', + 'hdr', + 'smpte_st_2084', + 'hybrid_log', + 'none', ]), }), 'context': , @@ -578,9 +464,10 @@ 'area_id': None, 'capabilities': dict({ 'options': list([ - 'static', - 'frame', - 'scene', + '0', + '1', + '2', + '3', ]), }), 'config_entry_id': , @@ -616,9 +503,10 @@ 'device_class': 'enum', 'friendly_name': 'JVC Projector HDR processing', 'options': list([ - 'static', - 'frame', - 'scene', + '0', + '1', + '2', + '3', ]), }), 'context': , @@ -626,174 +514,10 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'static', - }) -# --- -# name: test_entity_state[sensor.jvc_projector_installation_mode-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_installation_mode', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Installation mode', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_installation_mode', - 'unique_id': 'jvcmac_installation_mode', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_installation_mode-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'JVC Projector Installation mode', - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_installation_mode', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'mode1', - }) -# --- -# name: test_entity_state[sensor.jvc_projector_laser_dimming-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'off', - 'auto1', - 'auto2', - 'auto3', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_laser_dimming', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Laser dimming', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_laser_dimming_mode', - 'unique_id': 'jvcmac_laser_dimming', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_laser_dimming-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector Laser dimming', - 'options': list([ - 'off', - 'auto1', - 'auto2', - 'auto3', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_laser_dimming', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'auto1', - }) -# --- -# name: test_entity_state[sensor.jvc_projector_laser_power-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'low', - 'high', - 'medium', - ]), - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': , - 'entity_id': 'sensor.jvc_projector_laser_power', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Laser power', - 'platform': 'jvc_projector', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'jvc_laser_power', - 'unique_id': 'jvcmac_laser_power', - 'unit_of_measurement': None, - }) -# --- -# name: test_entity_state[sensor.jvc_projector_laser_power-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'JVC Projector Laser power', - 'options': list([ - 'low', - 'high', - 'medium', - ]), - }), - 'context': , - 'entity_id': 'sensor.jvc_projector_laser_power', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'high', + 'state': '1', }) # --- -# name: test_entity_state[sensor.jvc_projector_laser_time-entry] +# name: test_entity_state[sensor.jvc_projector_laser_lamp_time-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -805,7 +529,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.jvc_projector_laser_time', + 'entity_id': 'sensor.jvc_projector_laser_lamp_time', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -817,7 +541,7 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Laser time', + 'original_name': 'Laser/Lamp time', 'platform': 'jvc_projector', 'previous_unique_id': None, 'supported_features': 0, @@ -826,13 +550,13 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity_state[sensor.jvc_projector_laser_time-state] +# name: test_entity_state[sensor.jvc_projector_laser_lamp_time-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'JVC Projector Laser time', + 'friendly_name': 'JVC Projector Laser/Lamp time', }), 'context': , - 'entity_id': 'sensor.jvc_projector_laser_time', + 'entity_id': 'sensor.jvc_projector_laser_lamp_time', 'last_changed': , 'last_reported': , 'last_updated': , diff --git a/tests/components/jvc_projector/test_config_flow.py b/tests/components/jvc_projector/test_config_flow.py index 10fd5677efb2d3..94cd80848a4066 100644 --- a/tests/components/jvc_projector/test_config_flow.py +++ b/tests/components/jvc_projector/test_config_flow.py @@ -2,7 +2,7 @@ from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector.error import JvcProjectorAuthError, JvcProjectorConnectError import pytest from homeassistant.components.jvc_projector.const import DOMAIN diff --git a/tests/components/jvc_projector/test_coordinator.py b/tests/components/jvc_projector/test_coordinator.py index b9211250aff7f8..fc556b681eb778 100644 --- a/tests/components/jvc_projector/test_coordinator.py +++ b/tests/components/jvc_projector/test_coordinator.py @@ -3,7 +3,7 @@ from datetime import timedelta from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector.error import JvcProjectorAuthError, JvcProjectorConnectError from homeassistant.components.jvc_projector.coordinator import ( INTERVAL_FAST, diff --git a/tests/components/jvc_projector/test_init.py b/tests/components/jvc_projector/test_init.py index a2374fda5c0e01..d61b2a17e75203 100644 --- a/tests/components/jvc_projector/test_init.py +++ b/tests/components/jvc_projector/test_init.py @@ -2,7 +2,7 @@ from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector.error import JvcProjectorAuthError, JvcProjectorConnectError from homeassistant.components.jvc_projector.const import DOMAIN from homeassistant.config_entries import ConfigEntryState diff --git a/tests/components/jvc_projector/test_select.py b/tests/components/jvc_projector/test_select.py index 8efed81688090a..eade9905e4d21f 100644 --- a/tests/components/jvc_projector/test_select.py +++ b/tests/components/jvc_projector/test_select.py @@ -4,7 +4,8 @@ from jvcprojector import const -from homeassistant.components.jvc_projector.select import OPTIONS +from homeassistant.components.jvc_projector.entity import JvcProjectorEntity +from homeassistant.components.jvc_projector.select import JVC_SELECTS from homeassistant.components.select import ( ATTR_OPTIONS, DOMAIN as SELECT_DOMAIN, @@ -30,20 +31,50 @@ async def test_all_selects( await setup_integration(hass, mock_config_entry) # Test each defined select entity - for cmd_key, expected_options in OPTIONS.items(): - entity_id = f"select.jvc_projector_{cmd_key}" + for item in JVC_SELECTS: + # Verify the entity was created + entity_id = f"select.jvc_projector_{item.key}" entity = hass.states.get(entity_id) assert entity, f"Entity {entity_id} was not created" # Verify the entity's options - assert entity.attributes.get(ATTR_OPTIONS) == expected_options + assert entity.attributes.get(ATTR_OPTIONS) == item.options # Verify the current state matches what's in the mock device - expected_state = mock_device.get_state.return_value.get(cmd_key) + expected_state = mock_device.get_state.return_value.get(item.key) if expected_state: assert entity.state == expected_state +async def test_override( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_device: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test all selects are created correctly.""" + # things not having NZ should not have laser entity + mock_device.model = "NX9" + + with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SELECT]): + await setup_integration(hass, mock_config_entry) + + # Test override for lamps + for item in JVC_SELECTS: + if item.key == "laser_power": + assert mock_device.model == "NX9" + assert item.translation_key_override is not None + + coordinator = mock_config_entry.runtime_data + entity_id = "select.jvc_projector_lamp_power" + state = hass.states.get(entity_id) + + ent = JvcProjectorEntity(coordinator) + assert ent.has_laser is False + assert ent.has_eshift is True + assert state.name == "JVC Projector Lamp Power" + + async def test_select_option( hass: HomeAssistant, entity_registry: er.EntityRegistry, diff --git a/tests/components/jvc_projector/test_sensor.py b/tests/components/jvc_projector/test_sensor.py index b16ef19c68dca8..3877ee4f52dc95 100644 --- a/tests/components/jvc_projector/test_sensor.py +++ b/tests/components/jvc_projector/test_sensor.py @@ -40,12 +40,12 @@ async def test_disabled_entity( """Tests entity is disabled by default.""" with patch("homeassistant.components.jvc_projector.PLATFORMS", [Platform.SENSOR]): await setup_integration(hass, mock_config_entry) - ANAMORPHIC_ID = "sensor.jvc_projector_anamorphic_mode" + DISABLED_ID = "sensor.jvc_projector_color_space" - assert hass.states.get(ANAMORPHIC_ID) is None + assert hass.states.get(DISABLED_ID) is None # Entity should exist in registry but be disabled - entity = entity_registry.async_get(ANAMORPHIC_ID) + entity = entity_registry.async_get(DISABLED_ID) assert entity assert entity.disabled assert entity.entity_category == "diagnostic" From 0a0af31821d5b38178c4dd0032fa72afca81e9fe Mon Sep 17 00:00:00 2001 From: iloveicedgreentea <31193909+iloveicedgreentea@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:35:17 +0000 Subject: [PATCH 16/16] fix logging IO error on test --- tests/components/jvc_projector/conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/components/jvc_projector/conftest.py b/tests/components/jvc_projector/conftest.py index 6fb4add3631f82..8f76fa73820e2e 100644 --- a/tests/components/jvc_projector/conftest.py +++ b/tests/components/jvc_projector/conftest.py @@ -1,6 +1,7 @@ """Fixtures for JVC Projector integration.""" from collections.abc import Generator +import logging from unittest.mock import MagicMock, patch import pytest @@ -81,3 +82,9 @@ async def fixture_mock_integration( await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() return mock_config_entry + + +@pytest.fixture(autouse=True) +def configure_logging(): + """Configure logging for tests.""" + logging.getLogger().handlers = [logging.NullHandler()]