Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sensor platform to Kaleidescape #67884

Merged
merged 6 commits into from Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/kaleidescape/__init__.py
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/kaleidescape/manifest.json
Expand Up @@ -9,7 +9,7 @@
}
],
"documentation": "https://www.home-assistant.io/integrations/kaleidescape",
"requirements": ["pykaleidescape==2022.2.6"],
"requirements": ["pykaleidescape==1.0.1"],
SteveEasley marked this conversation as resolved.
Show resolved Hide resolved
"codeowners": [
"@SteveEasley"
],
Expand Down
186 changes: 186 additions & 0 deletions 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(
bdraco marked this conversation as resolved.
Show resolved Hide resolved
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,
bdraco marked this conversation as resolved.
Show resolved Hide resolved
),
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)
2 changes: 1 addition & 1 deletion requirements_all.txt
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions 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"