1 """PrusaLink sensors."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
7 from datetime
import datetime, timedelta
8 from typing
import Generic, TypeVar, cast
10 from pyprusalink.types
import JobInfo, PrinterInfo, PrinterState, PrinterStatus
11 from pyprusalink.types_legacy
import LegacyPrinterStatus
16 SensorEntityDescription,
22 REVOLUTIONS_PER_MINUTE,
32 from .const
import DOMAIN
33 from .coordinator
import PrusaLinkUpdateCoordinator
34 from .entity
import PrusaLinkEntity
36 T = TypeVar(
"T", PrinterStatus, LegacyPrinterStatus, JobInfo, PrinterInfo)
39 @dataclass(frozen=True)
41 """Mixin for required keys."""
43 value_fn: Callable[[T], datetime | StateType]
46 @dataclass(frozen=True)
48 SensorEntityDescription, PrusaLinkSensorEntityDescriptionMixin[T], Generic[T]
50 """Describes PrusaLink sensor entity."""
52 available_fn: Callable[[T], bool] =
lambda _:
True
55 SENSORS: dict[str, tuple[PrusaLinkSensorEntityDescription, ...]] = {
57 PrusaLinkSensorEntityDescription[PrinterStatus](
60 value_fn=
lambda data: (cast(str, data[
"printer"][
"state"].lower())),
61 device_class=SensorDeviceClass.ENUM,
62 options=[state.value.lower()
for state
in PrinterState],
63 translation_key=
"printer_state",
65 PrusaLinkSensorEntityDescription[PrinterStatus](
66 key=
"printer.telemetry.temp-bed",
67 translation_key=
"heatbed_temperature",
68 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
69 device_class=SensorDeviceClass.TEMPERATURE,
70 state_class=SensorStateClass.MEASUREMENT,
71 value_fn=
lambda data: cast(float, data[
"printer"][
"temp_bed"]),
72 entity_registry_enabled_default=
False,
74 PrusaLinkSensorEntityDescription[PrinterStatus](
75 key=
"printer.telemetry.temp-nozzle",
76 translation_key=
"nozzle_temperature",
77 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
78 device_class=SensorDeviceClass.TEMPERATURE,
79 state_class=SensorStateClass.MEASUREMENT,
80 value_fn=
lambda data: cast(float, data[
"printer"][
"temp_nozzle"]),
81 entity_registry_enabled_default=
False,
83 PrusaLinkSensorEntityDescription[PrinterStatus](
84 key=
"printer.telemetry.temp-bed.target",
85 translation_key=
"heatbed_target_temperature",
86 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
87 device_class=SensorDeviceClass.TEMPERATURE,
88 state_class=SensorStateClass.MEASUREMENT,
89 value_fn=
lambda data: cast(float, data[
"printer"][
"target_bed"]),
90 entity_registry_enabled_default=
False,
92 PrusaLinkSensorEntityDescription[PrinterStatus](
93 key=
"printer.telemetry.temp-nozzle.target",
94 translation_key=
"nozzle_target_temperature",
95 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
96 device_class=SensorDeviceClass.TEMPERATURE,
97 state_class=SensorStateClass.MEASUREMENT,
98 value_fn=
lambda data: cast(float, data[
"printer"][
"target_nozzle"]),
99 entity_registry_enabled_default=
False,
101 PrusaLinkSensorEntityDescription[PrinterStatus](
102 key=
"printer.telemetry.z-height",
103 translation_key=
"z_height",
104 native_unit_of_measurement=UnitOfLength.MILLIMETERS,
105 device_class=SensorDeviceClass.DISTANCE,
106 state_class=SensorStateClass.MEASUREMENT,
107 value_fn=
lambda data: cast(float, data[
"printer"][
"axis_z"]),
108 entity_registry_enabled_default=
False,
110 PrusaLinkSensorEntityDescription[PrinterStatus](
111 key=
"printer.telemetry.print-speed",
112 translation_key=
"print_speed",
113 native_unit_of_measurement=PERCENTAGE,
114 value_fn=
lambda data: cast(float, data[
"printer"][
"speed"]),
116 PrusaLinkSensorEntityDescription[PrinterStatus](
117 key=
"printer.telemetry.print-flow",
118 translation_key=
"print_flow",
119 native_unit_of_measurement=PERCENTAGE,
120 value_fn=
lambda data: cast(float, data[
"printer"][
"flow"]),
121 entity_registry_enabled_default=
False,
123 PrusaLinkSensorEntityDescription[PrinterStatus](
124 key=
"printer.telemetry.fan-hotend",
125 translation_key=
"fan_hotend",
126 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
127 value_fn=
lambda data: cast(float, data[
"printer"][
"fan_hotend"]),
128 entity_registry_enabled_default=
False,
130 PrusaLinkSensorEntityDescription[PrinterStatus](
131 key=
"printer.telemetry.fan-print",
132 translation_key=
"fan_print",
133 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
134 value_fn=
lambda data: cast(float, data[
"printer"][
"fan_print"]),
135 entity_registry_enabled_default=
False,
139 PrusaLinkSensorEntityDescription[LegacyPrinterStatus](
140 key=
"printer.telemetry.material",
141 translation_key=
"material",
142 value_fn=
lambda data: cast(str, data[
"telemetry"][
"material"]),
146 PrusaLinkSensorEntityDescription[JobInfo](
148 translation_key=
"progress",
149 native_unit_of_measurement=PERCENTAGE,
150 value_fn=
lambda data: cast(float, data[
"progress"]),
151 available_fn=
lambda data: (
152 data.get(
"progress")
is not None
153 and data.get(
"state") != PrinterState.IDLE.value
156 PrusaLinkSensorEntityDescription[JobInfo](
158 translation_key=
"filename",
159 value_fn=
lambda data: cast(str, data[
"file"][
"display_name"]),
160 available_fn=
lambda data: (
161 data.get(
"file")
is not None
162 and data.get(
"state") != PrinterState.IDLE.value
165 PrusaLinkSensorEntityDescription[JobInfo](
167 translation_key=
"print_start",
168 device_class=SensorDeviceClass.TIMESTAMP,
169 value_fn=ignore_variance(
173 available_fn=
lambda data: (
174 data.get(
"time_printing")
is not None
175 and data.get(
"state") != PrinterState.IDLE.value
178 PrusaLinkSensorEntityDescription[JobInfo](
180 translation_key=
"print_finish",
181 device_class=SensorDeviceClass.TIMESTAMP,
182 value_fn=ignore_variance(
186 available_fn=
lambda data: (
187 data.get(
"time_remaining")
is not None
188 and data.get(
"state") != PrinterState.IDLE.value
193 PrusaLinkSensorEntityDescription[PrinterInfo](
194 key=
"info.nozzle_diameter",
195 translation_key=
"nozzle_diameter",
196 native_unit_of_measurement=UnitOfLength.MILLIMETERS,
197 device_class=SensorDeviceClass.DISTANCE,
198 value_fn=
lambda data: cast(str, data[
"nozzle_diameter"]),
199 entity_registry_enabled_default=
False,
208 async_add_entities: AddEntitiesCallback,
210 """Set up PrusaLink sensor based on a config entry."""
211 coordinators: dict[str, PrusaLinkUpdateCoordinator] = hass.data[DOMAIN][
215 entities: list[PrusaLinkEntity] = []
217 for coordinator_type, sensors
in SENSORS.items():
218 coordinator = coordinators[coordinator_type]
221 for sensor_description
in sensors
228 """Defines a PrusaLink sensor."""
230 entity_description: PrusaLinkSensorEntityDescription
234 coordinator: PrusaLinkUpdateCoordinator,
235 description: PrusaLinkSensorEntityDescription,
237 """Initialize a PrusaLink sensor entity."""
238 super().
__init__(coordinator=coordinator)
240 self.
_attr_unique_id_attr_unique_id = f
"{coordinator.config_entry.entry_id}_{description.key}"
244 """Return the state of the sensor."""
249 """Return if sensor is available."""
251 self.coordinator.data
datetime|StateType native_value(self)
None __init__(self, PrusaLinkUpdateCoordinator coordinator, PrusaLinkSensorEntityDescription description)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)