diff --git a/.coveragerc b/.coveragerc index d1ead447856d583fd194c71d6c18e09c2eb9e86d..cd86d001e37a17fcd5bd27ae7acfaead0d344f29 100644 --- a/.coveragerc +++ b/.coveragerc @@ -240,6 +240,7 @@ omit = homeassistant/components/sensor/bom.py homeassistant/components/sensor/coinmarketcap.py homeassistant/components/sensor/cpuspeed.py + homeassistant/components/sensor/cups.py homeassistant/components/sensor/currencylayer.py homeassistant/components/sensor/darksky.py homeassistant/components/sensor/deutsche_bahn.py diff --git a/homeassistant/components/sensor/cups.py b/homeassistant/components/sensor/cups.py new file mode 100644 index 0000000000000000000000000000000000000000..1ad26e85261470870f508fa1d7026b5f5c052fed --- /dev/null +++ b/homeassistant/components/sensor/cups.py @@ -0,0 +1,149 @@ +""" +Details about printers which are connected to CUPS. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.cups/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import CONF_HOST, CONF_PORT +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +REQUIREMENTS = ['pycups==1.9.73'] + +_LOGGER = logging.getLogger(__name__) + +ATTR_DEVICE_URI = 'device_uri' +ATTR_PRINTER_INFO = 'printer_info' +ATTR_PRINTER_IS_SHARED = 'printer_is_shared' +ATTR_PRINTER_LOCATION = 'printer_location' +ATTR_PRINTER_MODEL = 'printer_model' +ATTR_PRINTER_STATE_MESSAGE = 'printer_state_message' +ATTR_PRINTER_STATE_REASON = 'printer_state_reason' +ATTR_PRINTER_TYPE = 'printer_type' +ATTR_PRINTER_URI_SUPPORTED = 'printer_uri_supported' + +CONF_PRINTERS = 'printers' + +DEFAULT_HOST = '127.0.0.1' +DEFAULT_PORT = 631 + +ICON = 'mdi:printer' + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) + +PRINTER_STATES = { + 3: 'idle', + 4: 'printing', + 5: 'stopped', +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_PRINTERS): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the CUPS sensor.""" + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + printers = config.get(CONF_PRINTERS) + + try: + data = CupsData(host, port) + data.update() + except RuntimeError: + _LOGGER.error("Unable to connect to CUPS server: %s:%s", host, port) + return False + + dev = [] + for printer in printers: + if printer in data.printers: + dev.append(CupsSensor(data, printer)) + else: + _LOGGER.error("Printer is not present: %s", printer) + continue + + add_devices(dev) + + +class CupsSensor(Entity): + """Representation of a CUPS sensor.""" + + def __init__(self, data, printer): + """Initialize the CUPS sensor.""" + self.data = data + self._name = printer + self._printer = None + self.update() + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + if self._printer is not None: + try: + return next(v for k, v in PRINTER_STATES.items() + if self._printer['printer-state'] == k) + except StopIteration: + return self._printer['printer-state'] + + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return ICON + + @property + def device_state_attributes(self): + """Return the state attributes of the sensor.""" + if self._printer is not None: + return { + ATTR_DEVICE_URI: self._printer['device-uri'], + ATTR_PRINTER_INFO: self._printer['printer-info'], + ATTR_PRINTER_IS_SHARED: self._printer['printer-is-shared'], + ATTR_PRINTER_LOCATION: self._printer['printer-location'], + ATTR_PRINTER_MODEL: self._printer['printer-make-and-model'], + ATTR_PRINTER_STATE_MESSAGE: + self._printer['printer-state-message'], + ATTR_PRINTER_STATE_REASON: + self._printer['printer-state-reasons'], + ATTR_PRINTER_TYPE: self._printer['printer-type'], + ATTR_PRINTER_URI_SUPPORTED: + self._printer['printer-uri-supported'], + } + + def update(self): + """Get the latest data and updates the states.""" + self.data.update() + self._printer = self.data.printers.get(self._name) + + +# pylint: disable=import-error +class CupsData(object): + """Get the latest data from CUPS and update the state.""" + + def __init__(self, host, port): + """Initialize the data object.""" + self._host = host + self._port = port + self.printers = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from CUPS.""" + from cups import Connection + + conn = Connection(host=self._host, port=self._port) + self.printers = conn.getPrinters() diff --git a/requirements_all.txt b/requirements_all.txt index 6b02b09d95cbf9ba67fb6120fc4cd7eb4b3d3f3c..af5519f1d15322e174c64523add0e4a04bbaac11 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -351,6 +351,9 @@ pychromecast==0.7.6 # homeassistant.components.media_player.cmus pycmus==0.1.0 +# homeassistant.components.sensor.cups +# pycups==1.9.73 + # homeassistant.components.envisalink # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index a5a25e7bab435ba3982abeead277497021f1ca10..e16ee5996de34d3091c933b380742a6c7bcc05af 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -17,6 +17,7 @@ COMMENT_REQUIREMENTS = ( 'gattlib', 'pyuserinput', 'evdev', + 'pycups', ) IGNORE_PACKAGES = (