core/homeassistant/components/fully_kiosk/switch.py

167 lines
5.8 KiB
Python

"""Fully Kiosk Browser switch."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from fullykiosk import FullyKiosk
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import FullyKioskDataUpdateCoordinator
from .entity import FullyKioskEntity
@dataclass(frozen=True)
class FullySwitchEntityDescriptionMixin:
"""Fully Kiosk Browser switch entity description mixin."""
on_action: Callable[[FullyKiosk], Any]
off_action: Callable[[FullyKiosk], Any]
is_on_fn: Callable[[dict[str, Any]], Any]
mqtt_on_event: str | None
mqtt_off_event: str | None
@dataclass(frozen=True)
class FullySwitchEntityDescription(
SwitchEntityDescription, FullySwitchEntityDescriptionMixin
):
"""Fully Kiosk Browser switch entity description."""
SWITCHES: tuple[FullySwitchEntityDescription, ...] = (
FullySwitchEntityDescription(
key="screensaver",
translation_key="screensaver",
on_action=lambda fully: fully.startScreensaver(),
off_action=lambda fully: fully.stopScreensaver(),
is_on_fn=lambda data: data.get("isInScreensaver"),
mqtt_on_event="onScreensaverStart",
mqtt_off_event="onScreensaverStop",
),
FullySwitchEntityDescription(
key="maintenance",
translation_key="maintenance",
entity_category=EntityCategory.CONFIG,
on_action=lambda fully: fully.enableLockedMode(),
off_action=lambda fully: fully.disableLockedMode(),
is_on_fn=lambda data: data.get("maintenanceMode"),
mqtt_on_event=None,
mqtt_off_event=None,
),
FullySwitchEntityDescription(
key="kiosk",
translation_key="kiosk",
entity_category=EntityCategory.CONFIG,
on_action=lambda fully: fully.lockKiosk(),
off_action=lambda fully: fully.unlockKiosk(),
is_on_fn=lambda data: data.get("kioskLocked"),
mqtt_on_event=None,
mqtt_off_event=None,
),
FullySwitchEntityDescription(
key="motion-detection",
translation_key="motion_detection",
entity_category=EntityCategory.CONFIG,
on_action=lambda fully: fully.enableMotionDetection(),
off_action=lambda fully: fully.disableMotionDetection(),
is_on_fn=lambda data: data["settings"].get("motionDetection"),
mqtt_on_event=None,
mqtt_off_event=None,
),
FullySwitchEntityDescription(
key="screenOn",
translation_key="screen_on",
on_action=lambda fully: fully.screenOn(),
off_action=lambda fully: fully.screenOff(),
is_on_fn=lambda data: data.get("screenOn"),
mqtt_on_event="screenOn",
mqtt_off_event="screenOff",
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Fully Kiosk Browser switch."""
coordinator: FullyKioskDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]
async_add_entities(
FullySwitchEntity(coordinator, description) for description in SWITCHES
)
class FullySwitchEntity(FullyKioskEntity, SwitchEntity):
"""Fully Kiosk Browser switch entity."""
entity_description: FullySwitchEntityDescription
def __init__(
self,
coordinator: FullyKioskDataUpdateCoordinator,
description: FullySwitchEntityDescription,
) -> None:
"""Initialize the Fully Kiosk Browser switch entity."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{coordinator.data['deviceID']}-{description.key}"
self._turned_on_subscription: CALLBACK_TYPE | None = None
self._turned_off_subscription: CALLBACK_TYPE | None = None
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
description = self.entity_description
self._turned_on_subscription = await self.mqtt_subscribe(
description.mqtt_off_event, self._turn_off
)
self._turned_off_subscription = await self.mqtt_subscribe(
description.mqtt_on_event, self._turn_on
)
async def async_will_remove_from_hass(self) -> None:
"""Close MQTT subscriptions when removed."""
await super().async_will_remove_from_hass()
if self._turned_off_subscription is not None:
self._turned_off_subscription()
if self._turned_on_subscription is not None:
self._turned_on_subscription()
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
await self.entity_description.on_action(self.coordinator.fully)
await self.coordinator.async_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
await self.entity_description.off_action(self.coordinator.fully)
await self.coordinator.async_refresh()
def _turn_off(self, **kwargs: Any) -> None:
"""Optimistically turn off."""
self._attr_is_on = False
self.async_write_ha_state()
def _turn_on(self, **kwargs: Any) -> None:
"""Optimistically turn on."""
self._attr_is_on = True
self.async_write_ha_state()
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_is_on = bool(self.entity_description.is_on_fn(self.coordinator.data))
self.async_write_ha_state()