diff --git a/homeassistant/components/kaleidescape/__init__.py b/homeassistant/components/kaleidescape/__init__.py index 574e74a3e14279..64205ecf838ec1 100644 --- a/homeassistant/components/kaleidescape/__init__.py +++ b/homeassistant/components/kaleidescape/__init__.py @@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) -PLATFORMS = [Platform.MEDIA_PLAYER] +PLATFORMS = [Platform.MEDIA_PLAYER, Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/kaleidescape/manifest.json b/homeassistant/components/kaleidescape/manifest.json index 88d5c7726f05ea..4fe29dd031cad8 100644 --- a/homeassistant/components/kaleidescape/manifest.json +++ b/homeassistant/components/kaleidescape/manifest.json @@ -9,7 +9,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/kaleidescape", - "requirements": ["pykaleidescape==2022.2.6"], + "requirements": ["pykaleidescape==1.0.1"], "codeowners": [ "@SteveEasley" ], diff --git a/homeassistant/components/kaleidescape/sensor.py b/homeassistant/components/kaleidescape/sensor.py new file mode 100644 index 00000000000000..468b7ced0e8f8a --- /dev/null +++ b/homeassistant/components/kaleidescape/sensor.py @@ -0,0 +1,186 @@ +"""Sensor platform for Kaleidescape integration.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from homeassistant.components.sensor import SensorEntity, SensorEntityDescription +from homeassistant.const import PERCENTAGE +from homeassistant.helpers.entity import EntityCategory + +from .const import DOMAIN as KALEIDESCAPE_DOMAIN +from .entity import KaleidescapeEntity + +if TYPE_CHECKING: + from collections.abc import Callable + + from kaleidescape import Device as KaleidescapeDevice + + from homeassistant.config_entries import ConfigEntry + from homeassistant.core import HomeAssistant + from homeassistant.helpers.entity_platform import AddEntitiesCallback + from homeassistant.helpers.typing import StateType + + +@dataclass +class BaseEntityDescriptionMixin: + """Mixin for required descriptor keys.""" + + value_fn: Callable[[KaleidescapeDevice], StateType] + + +@dataclass +class KaleidescapeSensorEntityDescription( + SensorEntityDescription, BaseEntityDescriptionMixin +): + """Describes Kaleidescape sensor entity.""" + + +SENSOR_TYPES: tuple[KaleidescapeSensorEntityDescription, ...] = ( + KaleidescapeSensorEntityDescription( + key="media_location", + name="Media Location", + icon="mdi:monitor", + value_fn=lambda device: device.automation.movie_location, + ), + KaleidescapeSensorEntityDescription( + key="play_status", + name="Play Status", + icon="mdi:monitor", + value_fn=lambda device: device.movie.play_status, + ), + KaleidescapeSensorEntityDescription( + key="play_speed", + name="Play Speed", + icon="mdi:monitor", + value_fn=lambda device: device.movie.play_speed, + ), + KaleidescapeSensorEntityDescription( + key="video_mode", + name="Video Mode", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.video_mode, + ), + KaleidescapeSensorEntityDescription( + key="video_color_eotf", + name="Video Color EOTF", + icon="mdi:monitor-eye", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.video_color_eotf, + ), + KaleidescapeSensorEntityDescription( + key="video_color_space", + name="Video Color Space", + icon="mdi:monitor-eye", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.video_color_space, + ), + KaleidescapeSensorEntityDescription( + key="video_color_depth", + name="Video Color Depth", + icon="mdi:monitor-eye", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.video_color_depth, + ), + KaleidescapeSensorEntityDescription( + key="video_color_sampling", + name="Video Color Sampling", + icon="mdi:monitor-eye", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.video_color_sampling, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_ratio", + name="Screen Mask Ratio", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.screen_mask_ratio, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_top_trim_rel", + name="Screen Mask Top Trim Rel", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=PERCENTAGE, + value_fn=lambda device: device.automation.screen_mask_top_trim_rel / 10.0, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_bottom_trim_rel", + name="Screen Mask Bottom Trim Rel", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=PERCENTAGE, + value_fn=lambda device: device.automation.screen_mask_bottom_trim_rel / 10.0, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_conservative_ratio", + name="Screen Mask Conservative Ratio", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.screen_mask_conservative_ratio, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_top_mask_abs", + name="Screen Mask Top Mask Abs", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=PERCENTAGE, + value_fn=lambda device: device.automation.screen_mask_top_mask_abs / 10.0, + ), + KaleidescapeSensorEntityDescription( + key="screen_mask_bottom_mask_abs", + name="Screen Mask Bottom Mask Abs", + icon="mdi:monitor-screenshot", + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=PERCENTAGE, + value_fn=lambda device: device.automation.screen_mask_bottom_mask_abs / 10.0, + ), + KaleidescapeSensorEntityDescription( + key="cinemascape_mask", + name="Cinemascape Mask", + icon="mdi:monitor-star", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.cinemascape_mask, + ), + KaleidescapeSensorEntityDescription( + key="cinemascape_mode", + name="Cinemascape Mode", + icon="mdi:monitor-star", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda device: device.automation.cinemascape_mode, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the platform from a config entry.""" + device: KaleidescapeDevice = hass.data[KALEIDESCAPE_DOMAIN][entry.entry_id] + async_add_entities( + KaleidescapeSensor(device, description) for description in SENSOR_TYPES + ) + + +class KaleidescapeSensor(KaleidescapeEntity, SensorEntity): + """Representation of a Kaleidescape sensor.""" + + entity_description: KaleidescapeSensorEntityDescription + + def __init__( + self, + device: KaleidescapeDevice, + entity_description: KaleidescapeSensorEntityDescription, + ) -> None: + """Initialize sensor.""" + super().__init__(device) + self.entity_description = entity_description + self._attr_unique_id = f"{self._attr_unique_id}-{entity_description.key}" + self._attr_name = f"{self._attr_name} {entity_description.name}" + + @property + def native_value(self) -> StateType: + """Return value of sensor.""" + return self.entity_description.value_fn(self._device) diff --git a/requirements_all.txt b/requirements_all.txt index e318f61ccfe701..edabda3c244f2f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1564,7 +1564,7 @@ pyisy==3.0.1 pyitachip2ir==0.0.7 # homeassistant.components.kaleidescape -pykaleidescape==2022.2.6 +pykaleidescape==1.0.1 # homeassistant.components.kira pykira==0.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f1aa2224391203..5aa88be6cd4553 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1017,7 +1017,7 @@ pyiss==1.0.1 pyisy==3.0.1 # homeassistant.components.kaleidescape -pykaleidescape==2022.2.6 +pykaleidescape==1.0.1 # homeassistant.components.kira pykira==0.1.1 diff --git a/tests/components/kaleidescape/test_sensor.py b/tests/components/kaleidescape/test_sensor.py new file mode 100644 index 00000000000000..0ae2dc15619531 --- /dev/null +++ b/tests/components/kaleidescape/test_sensor.py @@ -0,0 +1,48 @@ +"""Tests for Kaleidescape sensor platform.""" + +from unittest.mock import MagicMock + +from kaleidescape import const as kaleidescape_const + +from homeassistant.const import ATTR_FRIENDLY_NAME +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import MOCK_SERIAL + +from tests.common import MockConfigEntry + +ENTITY_ID = f"sensor.kaleidescape_device_{MOCK_SERIAL}" +FRIENDLY_NAME = f"Kaleidescape Device {MOCK_SERIAL}" + + +async def test_sensors( + hass: HomeAssistant, + mock_device: MagicMock, + mock_integration: MockConfigEntry, +) -> None: + """Test sensors.""" + entity = hass.states.get(f"{ENTITY_ID}_media_location") + entry = er.async_get(hass).async_get(f"{ENTITY_ID}_media_location") + assert entity + assert entity.state == "none" + assert ( + entity.attributes.get(ATTR_FRIENDLY_NAME) == f"{FRIENDLY_NAME} Media Location" + ) + assert entry + assert entry.unique_id == f"{MOCK_SERIAL}-media_location" + + entity = hass.states.get(f"{ENTITY_ID}_play_status") + entry = er.async_get(hass).async_get(f"{ENTITY_ID}_play_status") + assert entity + assert entity.state == "none" + assert entity.attributes.get(ATTR_FRIENDLY_NAME) == f"{FRIENDLY_NAME} Play Status" + assert entry + assert entry.unique_id == f"{MOCK_SERIAL}-play_status" + + mock_device.movie.play_status = kaleidescape_const.PLAY_STATUS_PLAYING + mock_device.dispatcher.send(kaleidescape_const.PLAY_STATUS) + await hass.async_block_till_done() + entity = hass.states.get(f"{ENTITY_ID}_play_status") + assert entity is not None + assert entity.state == "playing"