* Remove unnecessary exception re-wraps * Preserve exception chains on re-raise We slap "from cause" to almost all possible cases here. In some cases it could conceivably be better to do "from None" if we really want to hide the cause. However those should be in the minority, and "from cause" should be an improvement over the corresponding raise without a "from" in all cases anyway. The only case where we raise from None here is in plex, where the exception for an original invalid SSL cert is not the root cause for failure to validate a newly fetched one. Follow local convention on exception variable names if there is a consistent one, otherwise `err` to match with majority of codebase. * Fix mistaken re-wrap in homematicip_cloud/hap.py Missed the difference between HmipConnectionError and HmipcConnectionError. * Do not hide original error on plex new cert validation error Original is not the cause for the new one, but showing old in the traceback is useful nevertheless.
194 lines
6.2 KiB
Python
194 lines
6.2 KiB
Python
"""Support for information from HP iLO sensors."""
|
|
from datetime import timedelta
|
|
import logging
|
|
|
|
import hpilo
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
|
from homeassistant.const import (
|
|
CONF_HOST,
|
|
CONF_MONITORED_VARIABLES,
|
|
CONF_NAME,
|
|
CONF_PASSWORD,
|
|
CONF_PORT,
|
|
CONF_SENSOR_TYPE,
|
|
CONF_UNIT_OF_MEASUREMENT,
|
|
CONF_USERNAME,
|
|
CONF_VALUE_TEMPLATE,
|
|
)
|
|
import homeassistant.helpers.config_validation as cv
|
|
from homeassistant.helpers.entity import Entity
|
|
from homeassistant.util import Throttle
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DEFAULT_NAME = "HP ILO"
|
|
DEFAULT_PORT = 443
|
|
|
|
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=300)
|
|
|
|
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=[]): vol.All(
|
|
cv.ensure_list,
|
|
[
|
|
vol.Schema(
|
|
{
|
|
vol.Required(CONF_NAME): cv.string,
|
|
vol.Required(CONF_SENSOR_TYPE): vol.All(
|
|
cv.string, vol.In(SENSOR_TYPES)
|
|
),
|
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
|
}
|
|
)
|
|
],
|
|
),
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
|
}
|
|
)
|
|
|
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
"""Set up the HP iLO sensors."""
|
|
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)
|
|
|
|
# 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
|
|
|
|
# Initialize and add all of the sensors.
|
|
devices = []
|
|
for monitored_variable in monitored_variables:
|
|
new_device = HpIloSensor(
|
|
hass=hass,
|
|
hp_ilo_data=hp_ilo_data,
|
|
sensor_name=f"{config.get(CONF_NAME)} {monitored_variable[CONF_NAME]}",
|
|
sensor_type=monitored_variable[CONF_SENSOR_TYPE],
|
|
sensor_value_template=monitored_variable.get(CONF_VALUE_TEMPLATE),
|
|
unit_of_measurement=monitored_variable.get(CONF_UNIT_OF_MEASUREMENT),
|
|
)
|
|
devices.append(new_device)
|
|
|
|
add_entities(devices, True)
|
|
|
|
|
|
class HpIloSensor(Entity):
|
|
"""Representation of a HP iLO sensor."""
|
|
|
|
def __init__(
|
|
self,
|
|
hass,
|
|
hp_ilo_data,
|
|
sensor_type,
|
|
sensor_name,
|
|
sensor_value_template,
|
|
unit_of_measurement,
|
|
):
|
|
"""Initialize the HP iLO sensor."""
|
|
self._hass = hass
|
|
self._name = sensor_name
|
|
self._unit_of_measurement = unit_of_measurement
|
|
self._ilo_function = SENSOR_TYPES[sensor_type][1]
|
|
self.hp_ilo_data = hp_ilo_data
|
|
|
|
if sensor_value_template is not None:
|
|
sensor_value_template.hass = hass
|
|
self._sensor_value_template = sensor_value_template
|
|
|
|
self._state = None
|
|
self._state_attributes = None
|
|
|
|
_LOGGER.debug("Created HP iLO sensor %r", self)
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the name of the sensor."""
|
|
return self._name
|
|
|
|
@property
|
|
def unit_of_measurement(self):
|
|
"""Return the unit of measurement of the sensor."""
|
|
return self._unit_of_measurement
|
|
|
|
@property
|
|
def state(self):
|
|
"""Return the state of the sensor."""
|
|
return self._state
|
|
|
|
@property
|
|
def device_state_attributes(self):
|
|
"""Return the device state attributes."""
|
|
return self._state_attributes
|
|
|
|
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)()
|
|
|
|
if self._sensor_value_template is not None:
|
|
ilo_data = self._sensor_value_template.render(ilo_data=ilo_data)
|
|
|
|
self._state = ilo_data
|
|
|
|
|
|
class HpIloData:
|
|
"""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."""
|
|
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(f"Unable to init HP ILO, {error}") from error
|