Дополнение B. Как применять Zabbix в качестве вашего контроллера в MQTT

Перевод блогов Instructions how-to use Zabbix as your Controller with MQTT, part 1 и Instructions how-to use Zabbix as your Controller with MQTT, part 2 (Auto-Discovery of Sensors) Jonas Paulin (@jpaulin).

Замечание: с изменениями от 2017-01-22. Был изменён формат ключа в элементах Zabbix с тем, чтобы соответствовать Auto-Discovery и автоматическому созданию датчиков и узлов. Item-key = child-id. См. Часть 2. Автоматическое обнаружение датчиков

Я хотел испытать Zabbix в качестве Контроллера, установить его в своём Raspberry Pi и заставить его работать с MySensors. Вот история моего опыта.

Часть 1. Инструкция как применять Zabbix в качестве вашего контроллера в MQTT

  Введение

Zabbix является мощной системой мониторинга с открытым исходным кодом, применяемой для отслеживания состояния ИТ, центров телекоммуникационных данных и данных сетевых сред. Он привносит множество разнообразных функций, является очень гибким, имеет мощный Форум и огромную документацию.Он может интегрироваться посредством zabbix.api, zabbix-sender или при помощи своего протокола обнаружения на нижнем уровне, Zabbix LLD (Low Level Discovery), помимо прочего наполнения. Существуют различные библиотеки для разнообразных языков программирования с целью интеграции во внешние системы и программное обеспечение. Взгляните на его веб страницы на www.zabbix.org и www.zabbix.com. {Прим. пер.: также см.наш перевод отдельных глав второго издания Полного руководства Zabbix Андреа Далле Ваккье.}

До недавнего времени Zabbix спокойно пребывал на моём Raspberry Pi 2 совместно с моей интеграцией MySensors.

У меня он работает с брокером MQTT, шлюзом MQTT и некоторыми датчиками. На самом деле он работает с контроллером Domoticz выполняя регистрацию с тех же самых датчиков, которые установлены в том же самом Raspberry.

Вот пара снимков экрана моей установки, показывающие в работе датчики температуры и потребления энергии.

 

Рисунок B-1



 

Рисунок B-2



 

Рисунок B-3



 

Рисунок B-4



  Процедура установки. Брокер MQTT

Для начала моему Raspberry требуется иметь запущенным некий брокер {сервер} MQTT для захвата и распространения сообщений MQTT, в данном случае от клиента шлюза MQTT MySensors. Я полагаю, что Mosquitto является наилучшим выбором. Для установки брокера Mosquitto MQTT придерживайтесь следующей инструкции или же напрямую исполните следующие команды в своём Raspberry Pi:


sudo apt-get update
sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients
		

  Инструкции для установки zabbix в Raspberry Pi, с применением MySQL в качестве базы данных

Для Zabbix требуется запущенной некая база данных. В нашей установке в качестве базы данных выбрана MySQL. Имеется два необходимых со стороны Zabbix пакета чтобы всё заработало, zabbix-server-mysql и zabbix-frontend-php. Также рекомендуется установить zabbix-agent на ваш Raspberry. Затем Zabbix может автоматически выполнять мониторинг производительности Raspberry Pi через этого zabbix-agent совместно с предварительно установленными шаблонами.

Если вы установите Zabbix напрямую через apt-get install, получаемая вами версия будет достаточно древней (zabbix 2.x) и у меня возникли проблемы в попытках заставить её работать. В моём случае приводимая далее веб страница позволила установить Zabbix v3.0. Вот руководство Zabbix 3.0.

Если у вас ещё не установлен mysql сделайте это для своего Raspberry:


sudo apt-get install mysql-server mysql-client
		

  Установка Zabbix 3.0

Воспользуйтесь данной пошаговой инструкцией для установки Zabbix в вашем Raspberry Pi. Она установит Zabbix 3.0.

Теперь у вас должны иметься установленными в вашем Raspberry Pi:

  • zabbix-server-mysql

  • zabbix-frontend-php

  • zabbix-agent

Вы можете проверить это выполнив теперь доступ к Zabbix через веб- браузер с указанием IP адреса Raspberry Pi, вы должны обнаружить следующий экран:

 

Рисунок B-5



Введите для User Admin, а для Password zabbix. Позднее вы сможете заменить эти регистрационные данные.

  Концепции установка Zabbix

Дополнительно нам понадобится установить пакет zabbix-sender чтобы иметь возможность отправлять сообщения MQTT из сценария в сервер Zabbix. В своём Raspberry Pi наберите:


cd ~
cd zabbix3-rpi-master
sudo dpkg –i zabbix-sender_3.0.*-1+jessie_armhf.deb
		

  Установка zabbix-sender

Чтобы переправлять сообщения MQTT из брокера MQTT в Zabbix я написал небольшой сценарий Python. Напомню, что формат MQTT с MySensors представлен в виде "topic/a/b/c/d/e", однако Zabbix не допускает символ / (прямой косой черты) в виде некоего "ключа элемента" и следовательно его требуется преобразовать в "topic.a.b.c.d.e".

В Zabbix я установил некую группу хостов с названием "MySensors". В эту группу хостов добавляются узлы датчиков (хосты). Для тех хостов, которые добавляются в качестве дочерних датчиков (элементов) ниже приводится формат MQTT MySensors:


MY_MQTT_TOPIC_PREFIX/SENSOR-NODE-ID/SENSOR-CHILD-ID/CMD-TYPE/ACK-FLAG/SUB-TYPE
 	   
  • hostgroup = "MySensors"

  • host = MY_MQTT_TOPIC_PREFIX + "." + MY_NODE_ID

    т.е. mygateway1-out.5

  • item = CHILD_ID + "." + CMD-TYPE + "." + "ACK-FLAG" + "." + SUB-TYPE

    т.е. 1.1.0.0 (Child Id = 1, Cmdtype = set, Ack = 0, Subtype = V_TEMP)

Элемены Zabbix следует установить в тип "zabbix trapper". Вы найдёте эти элементы по -item-, -host-, -item-. Улавливатель (trapper) Zabbix выполняет ожидание сообщений, отправляемых от "zabbix-sender", которые мы и собираемся применять здесь.

Имейте в виду, никакое автоматическое назначение узлов Узлам датчиков от Контроллера не будет работать в данной установке Zabbix. Следовательно, ввам предварительно требуется установить Node_ID в сценарии arduino MySensor, то есть:


#define MY_NODE_ID   1
		

  Установка Zabbix

  • Определите группу хостов и присвойте ей название:

     

    Рисунок B-6



  • Определите немного хостов (узлов датчиков). Название хоста должно иметь точное соответствие с названием темы вашего шлюза MQTT, а идентификаторы узла разделяются точкой (MY_MQTT_TOPIC_PREFIX + "." + MY_NODE_ID). В нашем примере я применяю "domoticz.in.MyMQTT.11" в своём узле = 11.

     

    Рисунок B-7



  • Определите некоторые элементы (потомки) для своих узлов датчиков. Присвойте им название по своему выбору. Выберите Type = Zabbix trapper. Ключом для каждого элемента является Child-Id, взятый из сообщения MQTT MySensors. В данном случае Child-Id = 1. Замечание редакции 2017-01.22: Ключ для элементов был изменён на то, чтобы применять только Child-Id для удовлетворения интеграции с Auto-Discovery. подробнее...

     

    Рисунок B-8



  Zabbix-sender

Имеется доступным для исполнения файл, zabbix_sender, который вы теперь можете непосредственно проверить из командной строки Raspberry. Попробуйте отправить некий элемент, который был предварительно настроен в Zabbix выполнив такую команду:


zabbix_sender -v -z localhost -s domoticz.in.MyMQTT.11 -k 1 -o 10.5
		

Отклик на неё должен выглядеть примерно так:


info from server: "processed: 1; failed: 0; total: 1; seconds spent: 0.000176"
sent: 1; skipped: 0; total: 1
		

Если получены failed = 0, sent = 1, в нашей установке всё хорошо.

Теперь вы должны видеть поднятый Zabbix. Просмотрите Zabbix, в Monitoring выберите Latest Data. Вы должны обнаружить некое событие с температурой 10.5 °C, зарегистрированной для node = 11, Child = 1, то есть "domoticz.in.MyMQTT.11" с элементом ключа = "1" и полученной полезной нагрузкой = 10.5. Замечание редакции 2017-01-22: формат ключа изменён на Child-Id для удовлетворения интеграции с Auto-Discovery. подробнее...

  Установка zabbix-sender

Наш сценарий Python применяет две библиотеки, которые требуется для начала выгрузить: библиотеку клиента Mosquito и paho-mqtt.


pip install paho-mqtt
		

Библиотеки, которые применяет zabbix-sender/ zabbix-api www.zabbix.org/wiki/Docs/api/libraries / github.com/blacked/py-zabbix


pip install py-zabbix
		

Подготовьте сценарий с названием mqtt_zabbix.py в предпочитаемом вами редакторе, например, vi или nano.


nano mqtt_zabbix.py
		

Вставьте приводимый ниже текст сценария и сохраните его в этом фйле. Запустите в качестве примера этот сценарий в своей командной строке в фоновом режиме в качестве демона. Данный сценарий будет сохранять выводы stdout и stderr в текстовом файле zabbix.log:


python -u mqtt_zabbix.py > zabbix.log 2>&1 &
		

Ваш файл zabbix.logзапоминает отправленные события MQTT с временным штампом и получаемый от zabbix-sender, которые полезны для отладки.

Сценарий Python


import paho.mqtt.client as mqtt
import time
from  pyzabbix import ZabbixMetric, ZabbixSender

topic_sub = "domoticz/in/MyMQTT/"

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe(topic_sub+"+/+/+/+/+")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    msg.topic = msg.topic.replace("/", ".")

    myNode = msg.topic[:msg.topic.find(".", len(topic_sub)+1)]
    myItem = msg.topic[len(myNode)+1:]
    mySplit = myItem.split('.')  # split topic to indexed list

    if mySplit[1] == '1':        # type = set
        myItem = mySplit[0]      # change item to child-id

    metrics = [ZabbixMetric(myNode, myItem, msg.payload)]
    result = ZabbixSender(use_config=True).send(metrics)

    print(time.strftime("%c")+" "+str(result)+" : "+myNode+" "+myItem+" "+str(msg.payload))


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("localhost", 1883, 60)
		

В этом сценарии чтобы изменить формат MQTT с topic/a/b/c/d/e на topic.a.b.c.d.e, требуемый со стороны Zabbix, применяется вот ракая строка Python:


msg.topic = msg.topic.replace("/", ".")
		

Эти две строки имеют дело с отправкой событий MQTT в Zabbix:


metrics = [ZabbixMetric(myNode, myItem, msg.payload)]
result = ZabbixSender(use_config=True).send(metrics)
		

В Zabbix можно добавить триггеры для генерации предупреждения из полученных событий датчика MQTT. Оповещения могут также отправляться, например, через SMS, электронную почту или сценарий (но это выходит за пределы данной статьи).Следующим шагом будет создание узлов датчиков (хостов) и его потомков (элементов), путём подготовки некоторых Шаблонов в Zabbix вместе с zabbix.api или zabbix LLD. А также ознакомьтесь, как отправлять сообщения от Zabbix к реле и рычагам MySensor, а также для автономных действий в потоке.

Наслаждайтесь и получайте удовольствие!

Часть 2. Автоматическое обнаружение датчиков

Здесь приводится дополнительный сценарий созданный в Python для реализации Auto-Discovery и автоматического создания датчиков и узлов в Zabbix. Он применяет Zabbix-API для автоматических проверки и создания группы хостов, хостов и элементов, в случае если они новые, и представляет в ваш Контроллер (после включения соответствующих узлов датчиков). Этот сценарий исполняется в моём RPI, в котором также установлены Mosquitto и Zabbix.

Описание сценария

Данный сценарий подключается к брокеру Mosquitto и осуществляет ожидание обмена MQTT из сетевой среды MySensors.

  1. Вначале он проверяет наличие Zabbix-hostgroup с названием "MySensors". Если её нет, она автоматически создаётся.

  2. Когда представляется через MQTT некий новый датчик, автоматически создаётся некий хост Zabbix, добавляется в имеющуюся группу хостов, а сам этот хост именуется с префиксом темы + Node-ID.

  3. Когда создаётся некий новый потомок (Child), представляемый как элемент Zabbix, добавляется соответствующий хост и задаётся название темы представления. Значение ключа в элементе Zabbix устанавливается в значение Child-Id. Данное название элемента позднее может быть изменено на что- то более предпочтительное для вас.

Запустите этот сценарий в фоновом режиме, как это было сделано в части 1. Наш первый сценарий передаёт данные в Zabbix. А также этот сценарий обрабатывает автоматическое создание необходимых датчиков.

Сценарий Python


import paho.mqtt.client as mqtt
import time
from  pyzabbix import ZabbixMetric, ZabbixSender
from zabbix.api import ZabbixAPI


# Create ZabbixAPI class instance
zapi = ZabbixAPI(url='http://localhost/zabbix/', user='Admin', password='zabbix')

# Moquitto Topic Prefix
topic_sub = "domoticz/in/MyMQTT/"

# Name of Zabbix hostgroup
hostGroup = 'MySensors'

# Create hostgroup, if missing
result = zapi.do_request('hostgroup.get', {'filter': {'name': [hostGroup]}})
if [name['name'] for name in result['result']] == []:
     zapi.hostgroup.create(name=hostGroup)
     result = zapi.do_request('hostgroup.get', {'filter': {'name': [hostGroup]}})
     print(time.strftime("%c")+" Hostgroup created: "+hostGroup+" : "+str(result))      # log hostgroup creation

# Get hostgroup-id
groupId = [name['groupid'] for name in result['result']]


# Mosquitto: the callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Mosquitto: subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe(topic_sub+"+/+/+/+/+")

# Mosquitto: the callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    msg.topic = msg.topic.replace("/", ".")

    myNode  = msg.topic[:msg.topic.find(".", len(topic_sub)+1)]
    myItem  = msg.topic[len(myNode)+1:]
    mySplit = myItem.split('.')


    # Check if host (node) exist, or create new host.
    # 255 = child, 0 = presentation, 17 = S_ARDUINO_NODE
    if myItem == '255.0.0.17':
        result = zapi.do_request('host.get', {'filter':{'host':[myNode]}})
        if [host['host'] for host in result['result']] == []:                           # new node sensor, create host
            result = zapi.do_request('host.create', {'host': myNode, 'interfaces': [{'type': 1, 'main': 1, 'useip': 1, 'ip': '127.0.0.1', 'dns': '', 'port': '10050'}], 'groups': [{'groupid': groupId[0]}]})
            print(time.strftime("%c")+" Host created: "+myNode+" : "+str(result))       # log host creation

            # create item I_BATTERY_LEVEL
            result = zapi.do_request('host.get', {'filter':{'host':[myNode]}})
            hostId = [item['hostid'] for item in result['result']]
            result = zapi.do_request('item.create', {'hostid': hostId[0], 'value_type': '0','type': '2', 'name': 'I_BATTERY_LEVEL', ' key_': '255.3.0.0'})
            print(time.strftime("%c")+" Item created: I_BATTERY_LEVEL : "+str(result))  # log item creation

    if mySplit[1] == '0':        # command = presentation
        if mySplit[0] != '255':  # child = 255, don't create item
            result = zapi.do_request('item.get', {'host': myNode, 'filter': {'key_':[mySplit[0]]}})
            if [host['key_'] for host in result['result']] == []:                       # new child, create item
                result = zapi.do_request('host.get', {'filter':{'host':[myNode]}})
                hostId = [item['hostid'] for item in result['result']]
                result = zapi.do_request('item.create', {'hostid': hostId[0], 'value_type': '0','type': '2', 'name': myItem, 'key_': mySplit[0]})
                print(time.strftime("%c")+" Item created: "+myItem+" : "+str(result))   # log item creation




# Mosquitto: client start-up.
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect("localhost", 1883, 60)


# Mosquitto: blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
client.loop_forever()
		

Выполните этот сценарий в фоновом режиме в качестве демона и выводы отправляйте в файл zabbix_cnfg.log


python -u mqtt_zabbix_api.py > zabbix_cnfg.log 2>&1 &
		

Я достаточный новичок в написании сценариев на Python, поэтому возможно, что код не такой элегантный. Но он отлично работает для моих целей. И это замечательно!