diff --git a/.coveragerc b/.coveragerc index 3196003a95a8..8f67671a5a2c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -122,6 +122,9 @@ omit = homeassistant/components/mochad.py homeassistant/components/*/mochad.py + homeassistant/components/zabbix.py + homeassistant/components/*/zabbix.py + homeassistant/components/alarm_control_panel/alarmdotcom.py homeassistant/components/alarm_control_panel/concord232.py homeassistant/components/alarm_control_panel/nx584.py diff --git a/homeassistant/components/sensor/zabbix.py b/homeassistant/components/sensor/zabbix.py new file mode 100644 index 000000000000..6c3d0a3d653a --- /dev/null +++ b/homeassistant/components/sensor/zabbix.py @@ -0,0 +1,174 @@ +""" +Support for Zabbix Sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.zabbix/ +""" +import logging +import voluptuous as vol + +from homeassistant.helpers.entity import Entity +import homeassistant.components.zabbix as zabbix +from homeassistant.components.sensor import PLATFORM_SCHEMA +import homeassistant.helpers.config_validation as cv + + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['zabbix'] + +_CONF_TRIGGERS = "triggers" +_CONF_HOSTIDS = "hostids" +_CONF_INDIVIDUAL = "individual" +_CONF_NAME = "name" + +_ZABBIX_ID_LIST_SCHEMA = vol.Schema([int]) +_ZABBIX_TRIGGER_SCHEMA = vol.Schema({ + vol.Optional(_CONF_HOSTIDS, default=[]): _ZABBIX_ID_LIST_SCHEMA, + vol.Optional(_CONF_INDIVIDUAL, default=False): cv.boolean(True), + vol.Optional(_CONF_NAME, default=None): cv.string, +}) + +# SCAN_INTERVAL = 30 +# +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(_CONF_TRIGGERS): vol.Any(_ZABBIX_TRIGGER_SCHEMA, None) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Zabbix sensor platform.""" + sensors = [] + + zapi = hass.data[zabbix.DOMAIN] + if not zapi: + _LOGGER.error("zapi is None. Zabbix component hasn't been loaded?") + return False + + _LOGGER.info("Connected to Zabbix API Version %s", + zapi.api_version()) + + trigger_conf = config.get(_CONF_TRIGGERS) + # The following code seems overly complex. Need to think about this... + if trigger_conf: + hostids = trigger_conf.get(_CONF_HOSTIDS) + individual = trigger_conf.get(_CONF_INDIVIDUAL) + name = trigger_conf.get(_CONF_NAME) + + if individual: + # Individual sensor per host + if not hostids: + # We need hostids + _LOGGER.error("If using 'individual', must specify hostids") + return False + + for hostid in hostids: + _LOGGER.debug("Creating Zabbix Sensor: " + str(hostid)) + sensor = ZabbixSingleHostTriggerCountSensor(zapi, + [hostid], + name) + sensors.append(sensor) + else: + if not hostids: + # Single sensor that provides the total count of triggers. + _LOGGER.debug("Creating Zabbix Sensor") + sensor = ZabbixTriggerCountSensor(zapi, name) + else: + # Single sensor that sums total issues for all hosts + _LOGGER.debug("Creating Zabbix Sensor group: " + str(hostids)) + sensor = ZabbixMultipleHostTriggerCountSensor(zapi, + hostids, + name) + sensors.append(sensor) + else: + # Single sensor that provides the total count of triggers. + _LOGGER.debug("Creating Zabbix Sensor") + sensor = ZabbixTriggerCountSensor(zapi) + sensors.append(sensor) + + add_devices(sensors) + + +class ZabbixTriggerCountSensor(Entity): + """Get the active trigger count for all Zabbix monitored hosts.""" + + def __init__(self, zApi, name="Zabbix"): + """Initiate Zabbix sensor.""" + self._name = name + self._zapi = zApi + self._state = None + self._attributes = {} + + @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 unit_of_measurement(self): + """Return the units of measurement.""" + return 'issues' + + def _call_zabbix_api(self): + return self._zapi.trigger.get(output="extend", + only_true=1, + monitored=1, + filter={"value": 1}) + + def update(self): + """Update the sensor.""" + _LOGGER.debug("Updating ZabbixTriggerCountSensor: " + str(self._name)) + triggers = self._call_zabbix_api() + self._state = len(triggers) + + @property + def device_state_attributes(self): + """Return the state attributes of the device.""" + return self._attributes + + +class ZabbixSingleHostTriggerCountSensor(ZabbixTriggerCountSensor): + """Get the active trigger count for a single Zabbix monitored host.""" + + def __init__(self, zApi, hostid, name=None): + """Initiate Zabbix sensor.""" + super().__init__(zApi, name) + self._hostid = hostid + if not name: + self._name = self._zapi.host.get(hostids=self._hostid, + output="extend")[0]["name"] + + self._attributes["Host ID"] = self._hostid + + def _call_zabbix_api(self): + return self._zapi.trigger.get(hostids=self._hostid, + output="extend", + only_true=1, + monitored=1, + filter={"value": 1}) + + +class ZabbixMultipleHostTriggerCountSensor(ZabbixTriggerCountSensor): + """Get the active trigger count for specified Zabbix monitored hosts.""" + + def __init__(self, zApi, hostids, name=None): + """Initiate Zabbix sensor.""" + super().__init__(zApi, name) + self._hostids = hostids + if not name: + host_names = self._zapi.host.get(hostids=self._hostids, + output="extend") + self._name = " ".join(name["name"] for name in host_names) + self._attributes["Host IDs"] = self._hostids + + def _call_zabbix_api(self): + return self._zapi.trigger.get(hostids=self._hostids, + output="extend", + only_true=1, + monitored=1, + filter={"value": 1}) diff --git a/homeassistant/components/zabbix.py b/homeassistant/components/zabbix.py new file mode 100644 index 000000000000..3418bad6c9c0 --- /dev/null +++ b/homeassistant/components/zabbix.py @@ -0,0 +1,60 @@ +""" +Support for Zabbix. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/zabbix/ +""" +import logging +from urllib.parse import urljoin + +import voluptuous as vol + +from homeassistant.const import ( + CONF_PATH, CONF_HOST, CONF_SSL, CONF_PASSWORD, CONF_USERNAME) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['pyzabbix==0.7.4'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_SSL = False +DEFAULT_PATH = "zabbix" + +DOMAIN = 'zabbix' + + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, + vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string, + vol.Optional(CONF_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD): cv.string + }) +}, extra=vol.ALLOW_EXTRA) + + +def setup(hass, config): + """Set up the Zabbix component.""" + from pyzabbix import ZabbixAPI, ZabbixAPIException + + conf = config[DOMAIN] + if conf[CONF_SSL]: + schema = 'https' + else: + schema = 'http' + + url = urljoin('{}://{}'.format(schema, conf[CONF_HOST]), conf[CONF_PATH]) + username = conf.get(CONF_USERNAME, None) + password = conf.get(CONF_PASSWORD, None) + + zapi = ZabbixAPI(url) + try: + zapi.login(username, password) + _LOGGER.info("Connected to Zabbix API Version %s", zapi.api_version()) + except ZabbixAPIException: + _LOGGER.error("Unable to login to the Zabbix API") + return False + + hass.data[DOMAIN] = zapi + return True diff --git a/requirements_all.txt b/requirements_all.txt index 1ebabd8d9e18..d13833efe183 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -542,6 +542,9 @@ pywemo==0.4.9 # homeassistant.components.light.yeelight pyyeelight==1.0-beta +# homeassistant.components.zabbix +pyzabbix==0.7.4 + # homeassistant.components.climate.radiotherm radiotherm==1.2