Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/arcam_fmj/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
_LOGGER = logging.getLogger(__name__)


PLATFORMS = [Platform.MEDIA_PLAYER]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.MEDIA_PLAYER]


async def async_setup_entry(hass: HomeAssistant, entry: ArcamFmjConfigEntry) -> bool:
Expand Down
89 changes: 89 additions & 0 deletions homeassistant/components/arcam_fmj/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""Arcam binary sensors for incoming stream info."""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass

from arcam.fmj.state import State

from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .coordinator import ArcamFmjConfigEntry, ArcamFmjCoordinator


@dataclass(frozen=True, kw_only=True)
class ArcamFmjBinarySensorEntityDescription(BinarySensorEntityDescription):
"""Describes an Arcam FMJ binary sensor entity."""

value_fn: Callable[[State], bool | None]


BINARY_SENSORS: tuple[ArcamFmjBinarySensorEntityDescription, ...] = (
ArcamFmjBinarySensorEntityDescription(
key="incoming_video_interlaced",
translation_key="incoming_video_interlaced",
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda state: (
vp.interlaced
if (vp := state.get_incoming_video_parameters()) is not None
else None
),
),
)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ArcamFmjConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Arcam FMJ binary sensors from a config entry."""
coordinators = config_entry.runtime_data.coordinators

entities: list[ArcamFmjBinarySensorEntity] = []
for zone in (1, 2):
coordinator = coordinators[zone]
entities.extend(
ArcamFmjBinarySensorEntity(
coordinator=coordinator,
description=description,
)
for description in BINARY_SENSORS
)
async_add_entities(entities)


class ArcamFmjBinarySensorEntity(
CoordinatorEntity[ArcamFmjCoordinator], BinarySensorEntity
):
"""Representation of an Arcam FMJ binary sensor."""

entity_description: ArcamFmjBinarySensorEntityDescription
_attr_has_entity_name = True

def __init__(
self,
coordinator: ArcamFmjCoordinator,
description: ArcamFmjBinarySensorEntityDescription,
) -> None:
"""Initialize the binary sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = (
f"{coordinator.config_entry.unique_id or coordinator.config_entry.entry_id}"
f"-{coordinator.state.zn}-{description.key}"
)
self._attr_device_info = coordinator.device_info

@property
def is_on(self) -> bool | None:
"""Return the binary sensor value."""
return self.entity_description.value_fn(self.coordinator.state)
7 changes: 7 additions & 0 deletions homeassistant/components/arcam_fmj/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,12 @@
"trigger_type": {
"turn_on": "{entity_name} was requested to turn on"
}
},
"entity": {
"binary_sensor": {
"incoming_video_interlaced": {
"name": "Incoming video interlaced"
}
}
}
}
43 changes: 43 additions & 0 deletions tests/components/arcam_fmj/test_binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for Arcam FMJ binary sensor entities."""

import pytest

from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from .conftest import MOCK_UUID


def _get_entity_id(entity_registry: er.EntityRegistry, zone: int) -> str:
"""Get entity_id for the interlaced binary sensor by unique_id."""
unique_id = f"{MOCK_UUID}-{zone}-incoming_video_interlaced"
entity_id = entity_registry.async_get_entity_id(
"binary_sensor", "arcam_fmj", unique_id
)
assert entity_id is not None, f"Missing binary sensor: zone {zone}"
return entity_id


@pytest.mark.usefixtures("player_setup")
async def test_binary_sensors_created(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Test that binary sensor entities are created for both zones."""
for zone in (1, 2):
entity_id = _get_entity_id(entity_registry, zone)
entry = entity_registry.async_get(entity_id)
assert entry is not None


@pytest.mark.usefixtures("player_setup")
async def test_binary_sensor_none(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Test binary sensor when video parameters are None."""
entity_id = _get_entity_id(entity_registry, 1)
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_UNKNOWN
Loading