168 lines
5.9 KiB
Python
168 lines
5.9 KiB
Python
"""Support for Samsung Printers with SyncThru web interface."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass
|
|
from typing import Any, cast
|
|
|
|
from pysyncthru import SyncThru, SyncthruState
|
|
|
|
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
|
from homeassistant.const import PERCENTAGE, EntityCategory
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .coordinator import SyncThruConfigEntry
|
|
from .entity import SyncthruEntity
|
|
|
|
SYNCTHRU_STATE_HUMAN = {
|
|
SyncthruState.INVALID: "invalid",
|
|
SyncthruState.OFFLINE: "unreachable",
|
|
SyncthruState.NORMAL: "normal",
|
|
SyncthruState.UNKNOWN: "unknown",
|
|
SyncthruState.WARNING: "warning",
|
|
SyncthruState.TESTING: "testing",
|
|
SyncthruState.ERROR: "error",
|
|
}
|
|
|
|
|
|
@dataclass(frozen=True, kw_only=True)
|
|
class SyncThruSensorDescription(SensorEntityDescription):
|
|
"""Describes a SyncThru sensor entity."""
|
|
|
|
value_fn: Callable[[SyncThru], str | None]
|
|
extra_state_attributes_fn: Callable[[SyncThru], dict[str, str | int]] | None = None
|
|
|
|
|
|
def get_toner_entity_description(color: str) -> SyncThruSensorDescription:
|
|
"""Get toner entity description for a specific color."""
|
|
return SyncThruSensorDescription(
|
|
key=f"toner_{color}",
|
|
translation_key=f"toner_{color}",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
value_fn=lambda printer: printer.toner_status().get(color, {}).get("remaining"),
|
|
extra_state_attributes_fn=lambda printer: printer.toner_status().get(color, {}),
|
|
)
|
|
|
|
|
|
def get_drum_entity_description(color: str) -> SyncThruSensorDescription:
|
|
"""Get drum entity description for a specific color."""
|
|
return SyncThruSensorDescription(
|
|
key=f"drum_{color}",
|
|
translation_key=f"drum_{color}",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
value_fn=lambda printer: printer.drum_status().get(color, {}).get("remaining"),
|
|
extra_state_attributes_fn=lambda printer: printer.drum_status().get(color, {}),
|
|
)
|
|
|
|
|
|
def get_input_tray_entity_description(tray: str) -> SyncThruSensorDescription:
|
|
"""Get input tray entity description for a specific tray."""
|
|
placeholders = {}
|
|
translation_key = f"tray_{tray}"
|
|
if "_" in tray:
|
|
_, identifier = tray.split("_")
|
|
placeholders["tray_number"] = identifier
|
|
translation_key = "tray"
|
|
return SyncThruSensorDescription(
|
|
key=f"tray_{tray}",
|
|
translation_key=translation_key,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
translation_placeholders=placeholders,
|
|
value_fn=(
|
|
lambda printer: printer.input_tray_status().get(tray, {}).get("newError")
|
|
or "Ready"
|
|
),
|
|
extra_state_attributes_fn=(
|
|
lambda printer: printer.input_tray_status().get(tray, {})
|
|
),
|
|
)
|
|
|
|
|
|
def get_output_tray_entity_description(tray: int) -> SyncThruSensorDescription:
|
|
"""Get output tray entity description for a specific tray."""
|
|
return SyncThruSensorDescription(
|
|
key=f"output_tray_{tray}",
|
|
translation_key="output_tray",
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
translation_placeholders={"tray_number": str(tray)},
|
|
value_fn=(
|
|
lambda printer: printer.output_tray_status().get(tray, {}).get("status")
|
|
or "Ready"
|
|
),
|
|
extra_state_attributes_fn=(
|
|
lambda printer: cast(
|
|
dict[str, str | int], printer.output_tray_status().get(tray, {})
|
|
)
|
|
),
|
|
)
|
|
|
|
|
|
SENSOR_TYPES: tuple[SyncThruSensorDescription, ...] = (
|
|
SyncThruSensorDescription(
|
|
key="active_alerts",
|
|
translation_key="active_alerts",
|
|
value_fn=lambda printer: printer.raw().get("GXI_ACTIVE_ALERT_TOTAL"),
|
|
),
|
|
SyncThruSensorDescription(
|
|
key="main",
|
|
name=None,
|
|
value_fn=lambda printer: SYNCTHRU_STATE_HUMAN[printer.device_status()],
|
|
extra_state_attributes_fn=lambda printer: {
|
|
"display_text": printer.device_status_details(),
|
|
},
|
|
),
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: SyncThruConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up from config entry."""
|
|
|
|
coordinator = config_entry.runtime_data
|
|
printer = coordinator.data
|
|
|
|
supp_toner = printer.toner_status(filter_supported=True)
|
|
supp_drum = printer.drum_status(filter_supported=True)
|
|
supp_tray = printer.input_tray_status(filter_supported=True)
|
|
supp_output_tray = printer.output_tray_status()
|
|
|
|
entities: list[SyncThruSensorDescription] = [
|
|
get_toner_entity_description(color) for color in supp_toner
|
|
]
|
|
entities.extend(get_drum_entity_description(color) for color in supp_drum)
|
|
entities.extend(get_input_tray_entity_description(key) for key in supp_tray)
|
|
entities.extend(get_output_tray_entity_description(key) for key in supp_output_tray)
|
|
|
|
async_add_entities(
|
|
SyncThruSensor(coordinator, description)
|
|
for description in SENSOR_TYPES + tuple(entities)
|
|
)
|
|
|
|
|
|
class SyncThruSensor(SyncthruEntity, SensorEntity):
|
|
"""Implementation of an abstract Samsung Printer sensor platform."""
|
|
|
|
_attr_icon = "mdi:printer"
|
|
entity_description: SyncThruSensorDescription
|
|
|
|
@property
|
|
def native_value(self) -> str | int | None:
|
|
"""Return the state of the sensor."""
|
|
return self.entity_description.value_fn(self.coordinator.data)
|
|
|
|
@property
|
|
def extra_state_attributes(self) -> dict[str, Any] | None:
|
|
"""Return the state attributes."""
|
|
if self.entity_description.extra_state_attributes_fn:
|
|
return self.entity_description.extra_state_attributes_fn(
|
|
self.coordinator.data
|
|
)
|
|
return None
|