#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2017             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.
#
# SNMP Infos
# .1.3.6.1.2.1.1 System description
# .1.3.6.1.4.1.35491.30.2.0 No of Sensors - max. 100
# .1.3.6.1.4.1.35491.30.3 Sensor Group1
#
# 11 values per sensor
# .1.3.6.1.4.1.35491.30.3.1.1.0 Sensor 1 ID
# .1.3.6.1.4.1.35491.30.3.1.2.0 Sensor 1 value
# .1.3.6.1.4.1.35491.30.3.1.3.0 Sensor 1 unit
# .1.3.6.1.4.1.35491.30.3.1.4.0 Sensor 1 valueint -> value *1000, without comma
# .1.3.6.1.4.1.35491.30.3.1.5.0 Sensor 1 name
# .1.3.6.1.4.1.35491.30.3.1.6.0 Sensor 1 alarmint
#                                        -1 = no value (also digi-input and output)
#                                         1 = lower critical alarm or green area (on digi-input)
#                                         2 = lower warning
#                                         3 = normal
#                                         4 = upper warning
#                                         5 = upper critical or red area (on digi-input)
# .1.3.6.1.4.1.35491.30.3.1.7.0 Sensor 1 LoLimitAlarmInt
# .1.3.6.1.4.1.35491.30.3.1.8.0 Sensor 1 LoLimitWarnInt
# .1.3.6.1.4.1.35491.30.3.1.9.0 Sensor 1 HiLimitWarnInt
# .1.3.6.1.4.1.35491.30.3.1.10.0 Sensor 1 HiLimitAlarmInt
# .1.3.6.1.4.1.35491.30.3.1.11.0 Sensor 1 HysterInt
#
# .1.3.6.1.4.1.35491.30.3.2.1.0 Sensor 2 ID
# .
# .
# .
# Here a List of known sensors
# sensors_ids = {
#    20: ("digital", "Schloss"),
#    22: ("digital", "Relaisadapter AC"),
#    23: ("digital", "Digitalausgang"),
#    24: ("digital", "Steckdosenleiste"),
#    38: ("digital", "Transponderleser"),
#    39: ("digital", "Tastatur"),
#    50: ("analog",  "Temperatursensor"),
#    51: ("digital", "Digitaleingang"),
#    60: ("analog",  "Feuchtesensor"),
#    61: ("digital", "Netzspannungs Messadapter"),
#    62: ("digital", "Sauerstoffsensor"),
#    63: ("analog",  "Analogsensor"),
#    64: ("digital", "Wechselstromzaehler"),
#    70: ("digital", "Zugangssensor (Tuerkontakt)"),
#    71: ("digital", "Erschuetterungssensor"),
#    72: ("digital", "Rauchmelder"),
#    80: ("digital", "LHX 20 RS232"),
# }
# also only one sensor group is supported with this plugin!


def parse_security_master(info):
    supported_sensors = {
        50: "temp",
        60: "humidity",
        72: "smoke",
    }

    parsed = {}
    for value in supported_sensors.itervalues():
        parsed[value] = {}

    for oid, sensor in info[0]:
        if ".5.0" not in str(oid):
            continue

        sensor_num = saveint(oid.split(".")[0])
        service_name = "%d %s" % (sensor_num, sensor)
        num = oid.split(".")[0]
        value, sensor_id, warn_low, warn_high, crit_low, crit_high, alarm = (None,) * 7

        for oid_second, sensor_second in info[0]:
            if num + ".1.0" == oid_second:
                sensor_id = saveint(sensor_second[0].encode('hex'))
            elif num + ".2.0" ==  oid_second:
                try:
                    value = float(sensor_second)
                except ValueError:
                    pass
            elif num + ".6.0" == oid_second:
                try:
                    alarm = int(sensor_second)
                except ValueError:
                    alarm = -1
            elif num + ".7.0" == oid_second:
                crit_low = savefloat(saveint(sensor_second) / 1000.)
            elif num + ".8.0" == oid_second:
                warn_low = savefloat(saveint(sensor_second) / 1000.)
            elif num + ".9.0" == oid_second:
                warn_high = savefloat(saveint(sensor_second) / 1000.)
            elif num + ".10.0" == oid_second:
                crit_high = savefloat(saveint(sensor_second) / 1000.)

        if sensor_id in supported_sensors.keys():
            parsed[supported_sensors[sensor_id]][service_name] = {
                'name':       sensor,
                'value':      value,
                'id':         sensor_id,
                'levels_low': (warn_low, crit_low),
                'levels':     (warn_high, crit_high),
                'alarm':      alarm,
            }

    return parsed


def inventory_security_master_sensors(parsed, sensor_type):
    for sensor in parsed[sensor_type]:
        yield sensor, {}


def check_security_master(item, _no_params, parsed):
    sensor = parsed['smoke'].get(item)
    if not sensor:
        return 3, "Sensor no found in SNMP output"

    if sensor['alarm'] == 99:
        return 3, "Smoke Sensor is not ready or bus element removed"

    value = sensor['value']
    if value == 0:
        status, msg = 0, "No Smoke"
    elif value == 1:
        status, msg = 2, "Smoke detected"
    else:
        status, msg = 3, "No Value for Sensor"

    return status, msg


check_info["security_master"] = {
    'parse_function':          parse_security_master,
    'check_function':          check_security_master,
    'inventory_function':      lambda parsed: inventory_security_master_sensors(parsed, "smoke"),
    'service_description':     'Sensor %s',
    'snmp_info':               [('.1.3.6.1.4.1.35491.30', [OID_END,'3']),],
    'snmp_scan_function':      lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith("1.3.6.1.4.1.35491"),
    'has_perfdata':            False,
}


#   .--humidity------------------------------------------------------------.
#   |              _                     _     _ _ _                       |
#   |             | |__  _   _ _ __ ___ (_) __| (_) |_ _   _               |
#   |             | '_ \| | | | '_ ` _ \| |/ _` | | __| | | |              |
#   |             | | | | |_| | | | | | | | (_| | | |_| |_| |              |
#   |             |_| |_|\__,_|_| |_| |_|_|\__,_|_|\__|\__, |              |
#   |                                                  |___/               |
#   '----------------------------------------------------------------------'


def check_security_master_humidity(item, params, parsed):
    sensor = parsed['humidity'].get(item)
    if not sensor:
        return 3, "Sensor not found in SNMP output"

    if sensor['alarm'] is not None and sensor['alarm'] > -1:
        if not params.get("levels"):
            params['levels'] = sensor.get('levels')

        if not params.get("levels_lower"):
            params['levels_lower'] = sensor.get('levels_low')

    return check_humidity(sensor['value'], params)


check_info["security_master.humidity"] = {
    'inventory_function':       lambda parsed: inventory_security_master_sensors(parsed, "humidity"),
    'check_function':           check_security_master_humidity,
    'service_description':      'Sensor %s',
    'has_perfdata':             True,
    'group':                    'humidity',
    'includes':                 ['humidity.include'],
}


#   .--temp----------------------------------------------------------------.
#   |                       _                                              |
#   |                      | |_ ___ _ __ ___  _ __                         |
#   |                      | __/ _ \ '_ ` _ \| '_ \                        |
#   |                      | ||  __/ | | | | | |_) |                       |
#   |                       \__\___|_| |_| |_| .__/                        |
#   |                                        |_|                           |
#   '----------------------------------------------------------------------'


factory_settings['security_master_temp_default_levels'] = {
    "device_levels_handling": "worst",   # this variable is required, in order to define,
                                         # which status limits are used, also 'levels' are
                                         # added via WATO, if needed
}


def check_security_master_temperature(item, params, parsed):
    sensor = parsed['temp'].get(item)
    if not sensor:
        return 3, "Sensor not found in SNMP output"

    sensor_value = sensor['value']
    if sensor_value is None:
        return 3, "Sensor value is not in SNMP-WALK"

    return check_temperature(reading=sensor_value,
                             unique_name=item,
                             params=params,
                             dev_unit="c",
                             dev_levels=sensor['levels'],
                             dev_levels_lower=sensor['levels_low'])


check_info['security_master.temp'] = {
    'inventory_function':       lambda parsed: inventory_security_master_sensors(parsed, "temp"),
    'check_function':           check_security_master_temperature,
    'service_description':      'Sensor %s',
    'has_perfdata':             True,
    'group':                    'temperature',
    'includes':                 ['temperature.include'],
    'default_levels_variable':  'security_master_temp_default_levels',
}
