From db23320659a711637b5164fbe6ae6db15cc48e48 Mon Sep 17 00:00:00 2001 From: Dale Higgs Date: Wed, 6 Jul 2016 20:25:57 -0500 Subject: [PATCH] Add names, units and icons to APCUPSd Sensor (#2443) * Add names, units and icons to APCUPSd Sensor * Fix farcy errors * Attempt fix of errors * Remove "type:" from configuration * Remove duplicate "mdi:" prefix --- homeassistant/components/sensor/apcupsd.py | 140 +++++++++++++++++---- 1 file changed, 113 insertions(+), 27 deletions(-) diff --git a/homeassistant/components/sensor/apcupsd.py b/homeassistant/components/sensor/apcupsd.py index b625e22691c..4ae82cba602 100644 --- a/homeassistant/components/sensor/apcupsd.py +++ b/homeassistant/components/sensor/apcupsd.py @@ -11,33 +11,109 @@ from homeassistant.const import TEMP_CELSIUS from homeassistant.helpers.entity import Entity DEPENDENCIES = [apcupsd.DOMAIN] -DEFAULT_NAME = "UPS Status" + +SENSOR_PREFIX = 'UPS ' +SENSOR_TYPES = { + 'alarmdel': ['Alarm Delay', '', 'mdi:alarm'], + 'ambtemp': ['Ambient Temperature', '', 'mdi:thermometer'], + 'apc': ['Status Data', '', 'mdi:information-outline'], + 'apcmodel': ['Model', '', 'mdi:information-outline'], + 'badbatts': ['Bad Batteries', '', 'mdi:information-outline'], + 'battdate': ['Battery Replaced', '', 'mdi:calendar-clock'], + 'battstat': ['Battery Status', '', 'mdi:information-outline'], + 'battv': ['Battery Voltage', 'V', 'mdi:flash'], + 'bcharge': ['Battery', '%', 'mdi:battery'], + 'cable': ['Cable Type', '', 'mdi:ethernet-cable'], + 'cumonbatt': ['Total Time on Battery', '', 'mdi:timer'], + 'date': ['Status Date', '', 'mdi:calendar-clock'], + 'dipsw': ['Dip Switch Settings', '', 'mdi:information-outline'], + 'dlowbatt': ['Low Battery Signal', '', 'mdi:clock-alert'], + 'driver': ['Driver', '', 'mdi:information-outline'], + 'dshutd': ['Shutdown Delay', '', 'mdi:timer'], + 'dwake': ['Wake Delay', '', 'mdi:timer'], + 'endapc': ['Date and Time', '', 'mdi:calendar-clock'], + 'extbatts': ['External Batteries', '', 'mdi:information-outline'], + 'firmware': ['Firmware Version', '', 'mdi:information-outline'], + 'hitrans': ['Transfer High', 'V', 'mdi:flash'], + 'hostname': ['Hostname', '', 'mdi:information-outline'], + 'humidity': ['Ambient Humidity', '%', 'mdi:water-percent'], + 'itemp': ['Internal Temperature', TEMP_CELSIUS, 'mdi:thermometer'], + 'lastxfer': ['Last Transfer', '', 'mdi:transfer'], + 'linefail': ['Input Voltage Status', '', 'mdi:information-outline'], + 'linefreq': ['Line Frequency', 'Hz', 'mdi:information-outline'], + 'linev': ['Input Voltage', 'V', 'mdi:flash'], + 'loadpct': ['Load', '%', 'mdi:gauge'], + 'lotrans': ['Transfer Low', 'V', 'mdi:flash'], + 'mandate': ['Manufacture Date', '', 'mdi:calendar'], + 'masterupd': ['Master Update', '', 'mdi:information-outline'], + 'maxlinev': ['Input Voltage High', 'V', 'mdi:flash'], + 'maxtime': ['Battery Timeout', '', 'mdi:timer-off'], + 'mbattchg': ['Battery Shutdown', '%', 'mdi:battery-alert'], + 'minlinev': ['Input Voltage Low', 'V', 'mdi:flash'], + 'mintimel': ['Shutdown Time', '', 'mdi:timer'], + 'model': ['Model', '', 'mdi:information-outline'], + 'nombattv': ['Battery Nominal Voltage', 'V', 'mdi:flash'], + 'nominv': ['Nominal Input Voltage', 'V', 'mdi:flash'], + 'nomoutv': ['Nominal Output Voltage', 'V', 'mdi:flash'], + 'nompower': ['Nominal Output Power', 'W', 'mdi:flash'], + 'numxfers': ['Transfer Count', '', 'mdi:counter'], + 'outputv': ['Output Voltage', 'V', 'mdi:flash'], + 'reg1': ['Register 1 Fault', '', 'mdi:information-outline'], + 'reg2': ['Register 2 Fault', '', 'mdi:information-outline'], + 'reg3': ['Register 3 Fault', '', 'mdi:information-outline'], + 'retpct': ['Restore Requirement', '%', 'mdi:battery-alert'], + 'selftest': ['Last Self Test', '', 'mdi:calendar-clock'], + 'sense': ['Sensitivity', '', 'mdi:information-outline'], + 'serialno': ['Serial Number', '', 'mdi:information-outline'], + 'starttime': ['Startup Time', '', 'mdi:calendar-clock'], + 'statflag': ['Status Flag', '', 'mdi:information-outline'], + 'status': ['Status', '', 'mdi:information-outline'], + 'stesti': ['Self Test Interval', '', 'mdi:information-outline'], + 'timeleft': ['Time Left', '', 'mdi:clock-alert'], + 'tonbatt': ['Time on Battery', '', 'mdi:timer'], + 'upsmode': ['Mode', '', 'mdi:information-outline'], + 'upsname': ['Name', '', 'mdi:information-outline'], + 'version': ['Daemon Info', '', 'mdi:information-outline'], + 'xoffbat': ['Transfer from Battery', '', 'mdi:transfer'], + 'xoffbatt': ['Transfer from Battery', '', 'mdi:transfer'], + 'xonbatt': ['Transfer to Battery', '', 'mdi:transfer'], +} + SPECIFIC_UNITS = { - "ITEMP": TEMP_CELSIUS + 'ITEMP': TEMP_CELSIUS +} +INFERRED_UNITS = { + ' Minutes': 'min', + ' Seconds': 'sec', + ' Percent': '%', + ' Volts': 'V', + ' Watts': 'W', + ' Hz': 'Hz', + ' C': TEMP_CELSIUS, } _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_entities, discovery_info=None): - """Setup the APCUPSd sensor.""" - typ = config.get(apcupsd.CONF_TYPE) - if typ is None: - _LOGGER.error( - "You must include a '%s' when configuring an APCUPSd sensor.", - apcupsd.CONF_TYPE) - return False - typ = typ.upper() + """Setup the APCUPSd sensors.""" + entities = [] - if typ not in apcupsd.DATA.status: - _LOGGER.error( - "Specified '%s' of '%s' does not appear in the APCUPSd status " - "output.", apcupsd.CONF_TYPE, typ) - return False + for resource in config['resources']: + sensor_type = resource.lower() - add_entities(( - Sensor(config, apcupsd.DATA, unit=SPECIFIC_UNITS.get(typ)), - )) + if sensor_type not in SENSOR_TYPES: + SENSOR_TYPES[sensor_type] = [ + sensor_type.title(), '', 'mdi:information-outline'] + + if sensor_type.upper() not in apcupsd.DATA.status: + _LOGGER.warning( + 'Sensor type: "%s" does not appear in the APCUPSd status ' + 'output.', sensor_type) + + entities.append(APCUPSdSensor(apcupsd.DATA, sensor_type)) + + add_entities(entities) def infer_unit(value): @@ -49,25 +125,31 @@ def infer_unit(value): from apcaccess.status import ALL_UNITS for unit in ALL_UNITS: if value.endswith(unit): - return value[:-len(unit)], unit + return value[:-len(unit)], INFERRED_UNITS.get(unit, unit.strip()) return value, None -class Sensor(Entity): +class APCUPSdSensor(Entity): """Representation of a sensor entity for APCUPSd status values.""" - def __init__(self, config, data, unit=None): + def __init__(self, data, sensor_type): """Initialize the sensor.""" - self._config = config - self._unit = unit self._data = data + self.type = sensor_type + self._name = SENSOR_PREFIX + SENSOR_TYPES[sensor_type][0] + self._unit = SENSOR_TYPES[sensor_type][1] self._inferred_unit = None self.update() @property def name(self): """Return the name of the UPS sensor.""" - return self._config.get("name", DEFAULT_NAME) + return self._name + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return SENSOR_TYPES[self.type][2] @property def state(self): @@ -77,11 +159,15 @@ class Sensor(Entity): @property def unit_of_measurement(self): """Return the unit of measurement of this entity, if any.""" - if self._unit is None: + if not self._unit: return self._inferred_unit return self._unit def update(self): """Get the latest status and use it to update our sensor state.""" - key = self._config[apcupsd.CONF_TYPE].upper() - self._state, self._inferred_unit = infer_unit(self._data.status[key]) + if self.type.upper() not in self._data.status: + self._state = None + self._inferred_unit = None + else: + self._state, self._inferred_unit = infer_unit( + self._data.status[self.type.upper()])