""" Support gathering system information of hosts which are running netdata. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.netdata/ """ from datetime import timedelta import logging import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( CONF_HOST, CONF_ICON, CONF_NAME, CONF_PORT, CONF_RESOURCES) from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle REQUIREMENTS = ['netdata==0.1.2'] _LOGGER = logging.getLogger(__name__) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) CONF_DATA_GROUP = 'data_group' CONF_ELEMENT = 'element' DEFAULT_HOST = 'localhost' DEFAULT_NAME = 'Netdata' DEFAULT_PORT = 19999 DEFAULT_ICON = 'mdi:desktop-classic' RESOURCE_SCHEMA = vol.Any({ vol.Required(CONF_DATA_GROUP): cv.string, vol.Required(CONF_ELEMENT): cv.string, vol.Optional(CONF_ICON, default=DEFAULT_ICON): cv.icon, }) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Required(CONF_RESOURCES): vol.Schema({cv.string: RESOURCE_SCHEMA}), }) async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): """Set up the Netdata sensor.""" from netdata import Netdata name = config.get(CONF_NAME) host = config.get(CONF_HOST) port = config.get(CONF_PORT) resources = config.get(CONF_RESOURCES) session = async_get_clientsession(hass) netdata = NetdataData(Netdata(host, hass.loop, session, port=port)) await netdata.async_update() if netdata.api.metrics is None: raise PlatformNotReady dev = [] for entry, data in resources.items(): icon = data[CONF_ICON] sensor = data[CONF_DATA_GROUP] element = data[CONF_ELEMENT] sensor_name = entry try: resource_data = netdata.api.metrics[sensor] unit = '%' if resource_data['units'] == 'percentage' else \ resource_data['units'] except KeyError: _LOGGER.error("Sensor is not available: %s", sensor) continue dev.append(NetdataSensor( netdata, name, sensor, sensor_name, element, icon, unit)) async_add_entities(dev, True) class NetdataSensor(Entity): """Implementation of a Netdata sensor.""" def __init__( self, netdata, name, sensor, sensor_name, element, icon, unit): """Initialize the Netdata sensor.""" self.netdata = netdata self._state = None self._sensor = sensor self._element = element self._sensor_name = self._sensor if sensor_name is None else \ sensor_name self._name = name self._icon = icon self._unit_of_measurement = unit @property def name(self): """Return the name of the sensor.""" return '{} {}'.format(self._name, self._sensor_name) @property def unit_of_measurement(self): """Return the unit the value is expressed in.""" return self._unit_of_measurement @property def icon(self): """Return the icon to use in the frontend, if any.""" return self._icon @property def state(self): """Return the state of the resources.""" return self._state @property def available(self): """Could the resource be accessed during the last update call.""" return self.netdata.available async def async_update(self): """Get the latest data from Netdata REST API.""" await self.netdata.async_update() resource_data = self.netdata.api.metrics.get(self._sensor) self._state = round( resource_data['dimensions'][self._element]['value'], 2) class NetdataData: """The class for handling the data retrieval.""" def __init__(self, api): """Initialize the data object.""" self.api = api self.available = True @Throttle(MIN_TIME_BETWEEN_UPDATES) async def async_update(self): """Get the latest data from the Netdata REST API.""" from netdata.exceptions import NetdataError try: await self.api.get_allmetrics() self.available = True except NetdataError: _LOGGER.error("Unable to retrieve data from Netdata") self.available = False