#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2018             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.


def parse_ra32e_sensors(info):
    def type_of(sensor):
        def values_until(x):
            return all(sensor[:x]) and not any(sensor[x:])

        if values_until(2):
            return 'temp'
        elif values_until(3):
            return 'temp/active'
        elif values_until(4):
            return 'temp/analog'
        elif values_until(5):
            return 'temp/humidity'
        else:
            return 'unknown'

    parsed = {
        'temperature': {},
        'humidity': {},
        'voltage': {},
        'power': {},
    }

    internal, sensors = info

    for type, item, value in zip(['temperature', 'humidity', 'temperature'],
                                        ['Internal', 'Internal', 'Heat Index'],
                                        internal[0]):
        if value:
            parsed[type][item] = float(value) / 100.0

    for sensor in sensors:
        oid_end, sensor_data = sensor[0], sensor[1:]

        name = 'Sensor %d' % int(oid_end.split('.')[0])
        type = type_of(sensor_data)

        # uses the format of elphase.include for power and voltage
        if type == 'temp':
            temperature, _, _, _, _ = sensor_data
            parsed['temperature'][name] = float(temperature) / 100.0
        elif type == 'temp/active':
            temperature, _, power_state, _, _ = sensor_data
            parsed['temperature'][name] = float(temperature) / 100.0

            power_status_map = {
                '1': (0, 'power detected'),
                '0': (2, 'no power detected')
            }
            parsed['power'][name] = {'device_state': power_status_map.get(power_state)}
        elif type == 'temp/analog':
            temperature, _, voltage, _, _ = sensor_data
            parsed['temperature'][name] = float(temperature) / 100.0
            parsed['voltage'][name] = {'voltage': (int(voltage), None)}
        elif type == 'temp/humidity':
            temperature, _, humidity, _, heatindex = sensor_data
            parsed['temperature'][name] = float(temperature) / 100.0
            parsed['humidity'][name] = float(humidity) / 100.0
            parsed['temperature'][name.replace('Sensor', 'Heat Index')] = float(heatindex) / 100.0

    return parsed


def inventory_ra32e_sensors(parsed, quantity):
    for name in parsed[quantity]:
        yield name, {}


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


factory_settings["ra32e_sensors_temperature_defaultlevels"] = {
    "levels": (30.0, 35.0),
}


def check_ra32e_sensors(item, params, parsed):
    temperature = parsed['temperature'].get(item)
    if temperature is None:
        return 3, 'no data for sensor'

    unique_name = 'ra32e_temp_%s' % item.lower().replace(' ', '')
    return check_temperature(temperature, params, unique_name)


check_info["ra32e_sensors"] = {
    'parse_function': parse_ra32e_sensors,
    'inventory_function': lambda x: inventory_ra32e_sensors(x, 'temperature'),
    'check_function': check_ra32e_sensors,
    'service_description': 'Temperature %s',
    'snmp_info': [  # ROOMALERT32E-MIB
        ('.1.3.6.1.4.1.20916.1.8.1.1', [
            '1.2',  # internal-tempc
            '2.1',  # internal-humidity
            '4.2',  # internal-heat-indexC
        ]),
        ('.1.3.6.1.4.1.20916.1.8.1.2', [
                '1',  # digital-sen1
                '2',  # digital-sen2
                '3',  # digital-sen3
                '4',  # digital-sen4
                '5',  # digital-sen5
                '6',  # digital-sen6
                '7',  # digital-sen7
                '8',  # digital-sen8
            ], [
                # Note:
                # The output depends on the kind of sensor and a sensor only outputs relevant values.
                # The following sensors are mentioned in the MIB from the 13th September 2017:
                #
                # sensor            | values
                # ---------------------------------
                # Temperature       | 1, 2
                # Temp/Active Power | 1, 2, 3
                # Temp/Analog       | 1, 2, 3, 4
                # Temp/Humidity     | 1, 2, 3, 4, 5
                #
                OID_END,
                '1',  # digital-sen[1-8]-1 --> Temperature, Temp/Humidity, Temp/Analog, Temp/Active Power: temperature in Celsius
                '2',  # digital-sen[1-8]-2 --> Temperature, Temp/Humidity, Temp/Analog, Temp/Active Power: temperature in Fahrenheit
                '3',  # digital-sen[1-8]-3 --> Temp/Humidity: %RH - Temp/Analog: voltage - Temp/Active Power: power state (1=power detected, 0=no power detected)
                '4',  # digital-sen[1-8]-4 --> Temp/Humidity: heat index Fahrenheit - Temp/Analog: custom reading
                '5',  # digital-sen[1-8]-5 --> Temp/Humidity: heat index Celsius
        ]),
    ],
    'snmp_scan_function': lambda oid: "1.3.6.1.4.1.20916.1.8" in oid(".1.3.6.1.2.1.1.2.0"),
    'has_perfdata': True,
    'includes': ['temperature.include', 'humidity.include', 'elphase.include'],
    'group': 'temperature',
    'default_levels_variable': 'ra32e_temp_defaultlevels',
}


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


factory_settings["ra32e_sensors_humidity_defaultlevels"] = {
    "levels": (70.0, 80.0),
}


def check_ra32e_humidity_sensors(item, params, parsed):
    humidity = parsed['humidity'].get(item)
    if humidity is None:
        return 3, 'no data for sensor'

    return check_humidity(humidity, params)


check_info["ra32e_sensors.humidity"] = {
    'inventory_function': lambda x: inventory_ra32e_sensors(x, 'humidity'),
    'check_function': check_ra32e_humidity_sensors,
    'service_description': 'Humidity %s',
    'has_perfdata': True,
    'group': 'humidity',
    'default_levels_variable': 'ra32e_humidity_defaultlevels',
}


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


factory_settings["ra32e_sensors_voltage_defaultlevels"] = {
    'voltage': (210, 180),
}


def check_ra32e_sensors_voltage(item, params, parsed):
    return next(check_elphase(item, params, parsed['voltage']))


check_info["ra32e_sensors.voltage"] = {
    'inventory_function': lambda x: inventory_ra32e_sensors(x, 'voltage'),
    'check_function': check_ra32e_sensors_voltage,
    'service_description': 'Voltage %s',
    'has_perfdata': True,
    'group': 'ups_outphase',
    'default_levels_variable': 'ra32e_sensors_voltage_defaultlevels',
}


#.
#   .--Power---------------------------------------------------------------.
#   |                     ____                                             |
#   |                    |  _ \ _____      _____ _ __                      |
#   |                    | |_) / _ \ \ /\ / / _ \ '__|                     |
#   |                    |  __/ (_) \ V  V /  __/ |                        |
#   |                    |_|   \___/ \_/\_/ \___|_|                        |
#   |                                                                      |
#   '----------------------------------------------------------------------'


def check_ra32e_power_sensors(item, params, parsed):
    return next(check_elphase(item, params, parsed['power']))


check_info["ra32e_sensors.power"] = {
    'inventory_function': lambda x: inventory_ra32e_sensors(x, 'power'),
    'check_function': check_ra32e_power_sensors,
    'service_description': 'Power State %s',
    'group': 'ups_outphase',
}
