1 """Details about printers which are connected to CUPS."""
3 from __future__
import annotations
5 from datetime
import timedelta
10 import voluptuous
as vol
13 PLATFORM_SCHEMA
as SENSOR_PLATFORM_SCHEMA,
23 _LOGGER = logging.getLogger(__name__)
25 ATTR_MARKER_TYPE =
"marker_type"
26 ATTR_MARKER_LOW_LEVEL =
"marker_low_level"
27 ATTR_MARKER_HIGH_LEVEL =
"marker_high_level"
28 ATTR_PRINTER_NAME =
"printer_name"
29 ATTR_DEVICE_URI =
"device_uri"
30 ATTR_PRINTER_INFO =
"printer_info"
31 ATTR_PRINTER_IS_SHARED =
"printer_is_shared"
32 ATTR_PRINTER_LOCATION =
"printer_location"
33 ATTR_PRINTER_MODEL =
"printer_model"
34 ATTR_PRINTER_STATE_MESSAGE =
"printer_state_message"
35 ATTR_PRINTER_STATE_REASON =
"printer_state_reason"
36 ATTR_PRINTER_TYPE =
"printer_type"
37 ATTR_PRINTER_URI_SUPPORTED =
"printer_uri_supported"
39 CONF_PRINTERS =
"printers"
40 CONF_IS_CUPS_SERVER =
"is_cups_server"
42 DEFAULT_HOST =
"127.0.0.1"
44 DEFAULT_IS_CUPS_SERVER =
True
46 ICON_PRINTER =
"mdi:printer"
47 ICON_MARKER =
"mdi:water"
51 PRINTER_STATES = {3:
"idle", 4:
"printing", 5:
"stopped"}
53 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
55 vol.Required(CONF_PRINTERS): vol.All(cv.ensure_list, [cv.string]),
56 vol.Optional(CONF_IS_CUPS_SERVER, default=DEFAULT_IS_CUPS_SERVER): cv.boolean,
57 vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
58 vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
66 add_entities: AddEntitiesCallback,
67 discovery_info: DiscoveryInfoType |
None =
None,
69 """Set up the CUPS sensor."""
70 host: str = config[CONF_HOST]
71 port: int = config[CONF_PORT]
72 printers: list[str] = config[CONF_PRINTERS]
73 is_cups: bool = config[CONF_IS_CUPS_SERVER]
78 if data.available
is False:
79 _LOGGER.error(
"Unable to connect to CUPS server: %s:%s", host, port)
80 raise PlatformNotReady
81 assert data.printers
is not None
83 dev: list[SensorEntity] = []
84 for printer
in printers:
85 if printer
not in data.printers:
86 _LOGGER.error(
"Printer is not present: %s", printer)
90 if "marker-names" in data.attributes[printer]:
93 for marker
in data.attributes[printer][
"marker-names"]
99 data =
CupsData(host, port, printers)
101 if data.available
is False:
102 _LOGGER.error(
"Unable to connect to IPP printer: %s:%s", host, port)
103 raise PlatformNotReady
106 for printer
in printers:
109 if "marker-names" in data.attributes[printer]:
110 for marker
in data.attributes[printer][
"marker-names"]:
117 """Representation of a CUPS sensor."""
119 _attr_icon = ICON_PRINTER
121 def __init__(self, data: CupsData, printer_name: str) ->
None:
122 """Initialize the CUPS sensor."""
125 self.
_printer_printer: dict[str, Any] |
None =
None
130 """Return the name of the entity."""
131 return self.
_name_name
135 """Return the state of the sensor."""
139 key = self.
_printer_printer[
"printer-state"]
140 return PRINTER_STATES.get(key, key)
144 """Return the state attributes of the sensor."""
149 ATTR_DEVICE_URI: self.
_printer_printer[
"device-uri"],
150 ATTR_PRINTER_INFO: self.
_printer_printer[
"printer-info"],
151 ATTR_PRINTER_IS_SHARED: self.
_printer_printer[
"printer-is-shared"],
152 ATTR_PRINTER_LOCATION: self.
_printer_printer[
"printer-location"],
153 ATTR_PRINTER_MODEL: self.
_printer_printer[
"printer-make-and-model"],
154 ATTR_PRINTER_STATE_MESSAGE: self.
_printer_printer[
"printer-state-message"],
155 ATTR_PRINTER_STATE_REASON: self.
_printer_printer[
"printer-state-reasons"],
156 ATTR_PRINTER_TYPE: self.
_printer_printer[
"printer-type"],
157 ATTR_PRINTER_URI_SUPPORTED: self.
_printer_printer[
"printer-uri-supported"],
161 """Get the latest data and updates the states."""
163 assert self.
datadata.printers
is not None
169 """Implementation of the IPPSensor.
171 This sensor represents the status of the printer.
174 _attr_icon = ICON_PRINTER
176 def __init__(self, data: CupsData, printer_name: str) ->
None:
177 """Initialize the sensor."""
185 """Return the name of the sensor."""
186 return self.
_attributes_attributes[
"printer-make-and-model"]
190 """Return the state of the sensor."""
195 return PRINTER_STATES.get(key, key)
199 """Return the state attributes of the sensor."""
203 state_attributes = {}
206 state_attributes[ATTR_PRINTER_INFO] = self.
_attributes_attributes[
"printer-info"]
208 if "printer-location" in self.
_attributes_attributes:
209 state_attributes[ATTR_PRINTER_LOCATION] = self.
_attributes_attributes[
213 if "printer-state-message" in self.
_attributes_attributes:
214 state_attributes[ATTR_PRINTER_STATE_MESSAGE] = self.
_attributes_attributes[
215 "printer-state-message"
218 if "printer-state-reasons" in self.
_attributes_attributes:
219 state_attributes[ATTR_PRINTER_STATE_REASON] = self.
_attributes_attributes[
220 "printer-state-reasons"
223 if "printer-uri-supported" in self.
_attributes_attributes:
224 state_attributes[ATTR_PRINTER_URI_SUPPORTED] = self.
_attributes_attributes[
225 "printer-uri-supported"
228 return state_attributes
231 """Fetch new state data for the sensor."""
238 """Implementation of the MarkerSensor.
240 This sensor represents the percentage of ink or toner.
243 _attr_icon = ICON_MARKER
244 _attr_native_unit_of_measurement = PERCENTAGE
246 def __init__(self, data: CupsData, printer: str, name: str, is_cups: bool) ->
None:
247 """Initialize the sensor."""
251 self.
_index_index = data.attributes[printer][
"marker-names"].index(name)
253 self.
_attributes_attributes: dict[str, Any] |
None =
None
257 """Return the state of the sensor."""
265 """Return the state attributes of the sensor."""
270 if isinstance(high_level, list):
271 high_level = high_level[self.
_index_index]
274 if isinstance(low_level, list):
275 low_level = low_level[self.
_index_index]
278 if isinstance(marker_types, list):
279 marker_types = marker_types[self.
_index_index]
282 printer_name = self.
_printer_printer
284 printer_name = self.
_attributes_attributes[self.
_printer_printer][
"printer-make-and-model"]
287 ATTR_MARKER_HIGH_LEVEL: high_level,
288 ATTR_MARKER_LOW_LEVEL: low_level,
289 ATTR_MARKER_TYPE: marker_types,
290 ATTR_PRINTER_NAME: printer_name,
294 """Update the state of the sensor."""
300 """Get the latest data from CUPS and update the state."""
302 def __init__(self, host: str, port: int, ipp_printers: list[str] |
None) ->
None:
303 """Initialize the data object."""
308 self.
printersprinters: dict[str, dict[str, Any]] |
None =
None
309 self.attributes: dict[str, Any] = {}
313 """Get the latest data from CUPS."""
314 cups = importlib.import_module(
"cups")
317 conn = cups.Connection(host=self.
_host_host, port=self.
_port_port)
320 assert self.
printersprinters
is not None
321 for printer
in self.
printersprinters:
322 self.attributes[printer] = conn.getPrinterAttributes(name=printer)
326 self.attributes[ipp_printer] = conn.getPrinterAttributes(
327 uri=f
"ipp://{self._host}:{self._port}/{ipp_printer}"
None __init__(self, str host, int port, list[str]|None ipp_printers)
def extra_state_attributes(self)
None __init__(self, CupsData data, str printer_name)
def extra_state_attributes(self)
None __init__(self, CupsData data, str printer_name)
def extra_state_attributes(self)
None __init__(self, CupsData data, str printer, str name, bool is_cups)
str|UndefinedType|None name(self)
web.Response get(self, web.Request request, str config_key)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
def add_entities(account, async_add_entities, tracked)