diff --git a/.coveragerc b/.coveragerc index 530d7832d81..922698f72ab 100644 --- a/.coveragerc +++ b/.coveragerc @@ -206,6 +206,7 @@ omit = homeassistant/components/sensor/google_travel_time.py homeassistant/components/sensor/gpsd.py homeassistant/components/sensor/gtfs.py + homeassistant/components/sensor/hp_ilo.py homeassistant/components/sensor/imap.py homeassistant/components/sensor/lastfm.py homeassistant/components/sensor/loopenergy.py diff --git a/homeassistant/components/sensor/hp_ilo.py b/homeassistant/components/sensor/hp_ilo.py new file mode 100644 index 00000000000..49586e45d50 --- /dev/null +++ b/homeassistant/components/sensor/hp_ilo.py @@ -0,0 +1,170 @@ +""" +Support for information from HP ILO sensors. + +This allows monitoring of HP server information +""" +import logging +from datetime import timedelta + +import voluptuous as vol +from homeassistant.const import ( + CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD, CONF_NAME, + CONF_MONITORED_VARIABLES, + STATE_ON, STATE_OFF) +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['python-hpilo==3.8'] +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'HP ILO' +DEFAULT_PORT = 443 + +# Each sensor is defined as follows: 'Descriptive name', 'python-ilo function' +SENSOR_TYPES = { + 'server_name': ['Server Name', 'get_server_name'], + 'server_fqdn': ['Server FQDN', 'get_server_fqdn'], + 'server_host_data': ['Server Host Data', 'get_host_data'], + 'server_oa_info': ['Server Onboard Administrator Info', 'get_oa_info'], + 'server_power_status': ['Server Power state', 'get_host_power_status'], + 'server_power_readings': ['Server Power readings', 'get_power_readings'], + 'server_power_on_time': ['Server Power On time', + 'get_server_power_on_time'], + 'server_asset_tag': ['Server Asset Tag', 'get_asset_tag'], + 'server_uid_status': ['Server UID light', 'get_uid_status'], + 'server_health': ['Server Health', 'get_embedded_health'], + 'network_settings': ['Network Settings', 'get_network_settings'] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_MONITORED_VARIABLES, default=['server_name']): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.positive_int, +}) + +# Return cached results if last scan was less then this time ago. +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=300) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the HP ILO sensor.""" + hostname = config.get(CONF_HOST) + port = config.get(CONF_PORT) + login = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + monitored_variables = config.get(CONF_MONITORED_VARIABLES) + name = config.get(CONF_NAME) + + # Create a data fetcher to support all of the configured sensors. Then make + # the first call to init the data and confirm we can connect. + try: + hp_ilo_data = HpIloData(hostname, port, login, password) + except ValueError as error: + _LOGGER.error(error) + return False + + # Initialize and add all of the sensors. + devices = [] + for ilo_type in monitored_variables: + new_device = HpIloSensor(hp_ilo_data=hp_ilo_data, + sensor_type=SENSOR_TYPES.get(ilo_type), + client_name=name) + devices.append(new_device) + + add_devices(devices) + + +class HpIloSensor(Entity): + """Represents an HP ILO sensor.""" + + def __init__(self, hp_ilo_data, sensor_type, client_name): + """Initialize the sensor.""" + self._name = '{} {}'.format(client_name, sensor_type[0]) + self._ilo_function = sensor_type[1] + self.client_name = client_name + self.hp_ilo_data = hp_ilo_data + + self._state = None + self._data = None + + self.update() + + _LOGGER.debug("Created HP ILO sensor %r", self) + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def state_attributes(self): + """Return the state attributes.""" + return self._data + + def update(self): + """Get the latest data from HP ILO and updates the states.""" + # Call the API for new data. Each sensor will re-trigger this + # same exact call, but that's fine. Results should be cached for + # a short period of time to prevent hitting API limits. + self.hp_ilo_data.update() + ilo_data = getattr(self.hp_ilo_data.data, self._ilo_function)() + + # Store the data received from the ILO API + if isinstance(ilo_data, dict): + self._data = ilo_data + else: + self._data = {'value': ilo_data} + + # If the data received is an integer or string, store it as + # the sensor state + if isinstance(ilo_data, (str, bytes)): + states = [STATE_ON, STATE_OFF] + try: + index_element = states.index(str(ilo_data).lower()) + self._state = states[index_element] + except ValueError: + self._state = ilo_data + elif isinstance(ilo_data, (int, float)): + self._state = ilo_data + + +# pylint: disable=too-few-public-methods +class HpIloData(object): + """Gets the latest data from HP ILO.""" + + def __init__(self, host, port, login, password): + """Initialize the data object.""" + self._host = host + self._port = port + self._login = login + self._password = password + + self.data = None + + self.update() + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from HP ILO.""" + import hpilo + + try: + self.data = hpilo.Ilo(hostname=self._host, + login=self._login, + password=self._password, + port=self._port) + except (hpilo.IloError, hpilo.IloCommunicationError, + hpilo.IloLoginFailed) as error: + raise ValueError("Unable to init HP ILO. - %s", error) diff --git a/homeassistant/const.py b/homeassistant/const.py index 50055c98706..65ff03b5276 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -40,6 +40,7 @@ CONF_ICON = 'icon' CONF_LATITUDE = 'latitude' CONF_LONGITUDE = 'longitude' CONF_MONITORED_CONDITIONS = 'monitored_conditions' +CONF_MONITORED_VARIABLES = 'monitored_variables' CONF_NAME = 'name' CONF_OFFSET = 'offset' CONF_OPTIMISTIC = 'optimistic' diff --git a/requirements_all.txt b/requirements_all.txt index d4612f5c024..8d342853f21 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -336,6 +336,9 @@ pysnmp==4.3.2 # homeassistant.components.sensor.forecast python-forecastio==1.3.4 +# homeassistant.components.sensor.hp_ilo +python-hpilo==3.8 + # homeassistant.components.lirc # python-lirc==1.2.1