Zabbix мониторинг температуры через Arduino

Zabbix мониторинг температуры через Arduino

Необходимо следить за температурой в серверной.
И получать своевременные оповещения если вдруг сломался кондиционер или что-то еще
Так как есть Zabbix, то и решено прикрутить все к заббиксу
Остался вопрос чем снимать показания. Изначально был выбор между raspberry pi и arduino, по по случайности сломался станок на котором был arduino, его и возьмем.

В итоге осталось купить датчики и все собрать

Решим какие показания и откуда будем снимать

Есть 2 серверных шкафа, кондиционер, само помещение серверной и на этапе сборки добавился датчик влаги, на случай затопления помещения
Были куплены:

  1. 2 датчика DHT11 для шкафов. Температурный диапазон от 0 до 50
  2. 2 датчика DHT22 для помещения и кондиционера. Температурный диапазон от -40 до 125
  3. Датчик влажности MH-Rain Sensor (не уверен что это его модель, но поиск по картинкам его показывает)

За основу взята Arduino Uno оставшаяся от станка

Схема

Следующим этапом необходимо нарисовать схему подключения всех датчиков
Дополнительно было решено сделать визуальную систему оповещения в виде светодиодом
А именно, когда идет опрос датчиков, пробегает огонёк.
Если датчик показывает предупреждение (температура или вода), то лампочка горит
Еще нужны резисторы
10 Ком - для датчиков DHT. Есть в продаже уже готовые платы с этим резистором, но у меня куплены просто датчики
Резистор для каждого светодиода 150 Ом. Иначе если их подключать напрямую к Arduino они быстро перегорят.
Резистор для светодиодов рассчитывается по принципу:

  1. R=(Vs-Vl)/I
  2. (5-2,2)/0,02=140 (резистор есть на 150 Ом. его и возьмем)

Рисуем схему на сайте https://easyeda.com/
Вход на сайт через Google аккаунт
Zabbix мониторинг температуры через Arduino

Дальше можно все спаивать. Но так как у меня есть домашняя Arduino Uno из набора матрешки, то мне удобно было все собрать на макетной плате. Отдельно проверить работу всех датчиков, так как раньше я с этим никогда не работал.
Фото сборки без датчика воды, так как он изначально не планировался и был добавлен в конце. Еще перегорел один светодиод и был заменен на первый попавшийся. Это все было на время отладки и не критично.Но примерная суть происходящего понятна

Программирование Arduino

Так как с Arduino я особо не работал то код написан как есть.
Его можно сильно оптимизировать, и вообще сделать для себя.
Следует помнить что каждый раз при установки соединения по COM порту Arduino перезагружается.
В интернете есть статьи как физически это решить. Но делать я этого не решил.
Из гуманных способов, можно использовать arduino usb to serial adapter. Но его надо покупать, и дополнительно подключать. Я решил использовать родной порт, тем более что был 5 метровый провод типа USB A - USB B
Поэтому в коде есть задержки на старте для ожидания полной загрузки Arduino, иначе сразу при подключении считать данные не выйдет.
Качаем arduino ide c официального сайта https://www.arduino.cc/en/Main/Software
Система Ubuntu 18.04. Качаем версию Linux 64 bits
Распаковываем и запускаем файл arduino
Понадобятся установить две дополнительные библиотеки Скетч - Подключить библиотеку - Управлять библиотеками
DHT sensor library - для датчиков
ArduinoThread - для параллельных процессов

#include <ThreadController.h>
#include <Thread.h>
#include <StaticThreadController.h>
#include <DHT.h>

// Объявляем светодиоды
#define LED_BUILTIN 13
#define DATA1_LED 12
#define DATA2_LED 11
#define DATA3_LED 10
#define DATA4_LED 9
#define DATA5_LED 8
#define TMIN 10
#define TMAX 25

int temp1 = 0;
int temp2 = 0;
int temp3 = 0;
int temp4 = 0;

boolean water = false;

Thread SysLed = Thread();
Thread DataRead = Thread();

// Объявляем датчики температуры
DHT data1(2, DHT11);
DHT data2(3, DHT11);
DHT data3(4, DHT22);
DHT data4(5, DHT22);

// Объявляем датчик воды
int data5 = 6;

void setup() {
    
    // Вывод светодиодов
    for(int i = 13; i >= 8; i--) { pinMode(i, OUTPUT); }
        
    data1.begin();
    data2.begin();
    data3.begin();
    data4.begin();

    // Запускам чтение дачиков DHT и одупляем красиво для подключения
    digitalWrite(LED_BUILTIN, LOW);delay(500);
    digitalWrite(LED_BUILTIN, HIGH);delay(500);
        
    for(int i = 13; i >= 8; i--) { digitalWrite(i, 1);delay(100); }
    delay(1000);
    for(int i = 13; i >= 8; i--) { digitalWrite(i, 0);delay(100); }    
    delay(1000);

    // Потоки вызова функций. Светодиод. Данные.
    SysLed.onRun(ledBlink);
    SysLed.setInterval(1000); // Каждую секунду моргаем
    DataRead.onRun(dread);
    DataRead.setInterval(10000); // Каждые 10 секунд читаем показания

    // Прочитаем данные на старте
    dread();

    Serial.begin(9600);
}

void loop() {  
    if (SysLed.shouldRun())
      SysLed.run();
    if (DataRead.shouldRun())
      DataRead.run();

    cread();
}

// Считываем данные и кажем светодиодами
void dread(){  
  temp1 = data1.readTemperature();
  digitalWrite(DATA1_LED, !digitalRead(DATA1_LED));delay(30);digitalWrite(DATA1_LED, !digitalRead(DATA1_LED));
  if ( temp1 >= TMAX || temp1 <= TMIN ) digitalWrite(DATA1_LED, HIGH); else digitalWrite(DATA1_LED, LOW);
  temp2 = data2.readTemperature();
  digitalWrite(DATA2_LED, !digitalRead(DATA2_LED));delay(30);digitalWrite(DATA2_LED, !digitalRead(DATA2_LED));
  if ( temp2 >= TMAX || temp2 <= TMIN ) digitalWrite(DATA2_LED, HIGH); else digitalWrite(DATA2_LED, LOW);
  temp3 = data3.readTemperature();
  digitalWrite(DATA3_LED, !digitalRead(DATA3_LED));delay(30);digitalWrite(DATA3_LED, !digitalRead(DATA3_LED));
  if ( temp3 >= TMAX || temp3 <= TMIN ) digitalWrite(DATA3_LED, HIGH); else digitalWrite(DATA3_LED, LOW);
  temp4 = data4.readTemperature();
  digitalWrite(DATA4_LED, !digitalRead(DATA4_LED));delay(30);digitalWrite(DATA4_LED, !digitalRead(DATA4_LED));
  if ( temp4 >= TMAX || temp4 <= TMIN ) digitalWrite(DATA4_LED, HIGH); else digitalWrite(DATA4_LED, LOW);
  water = !(digitalRead(data5));delay(300);
  digitalWrite(DATA5_LED, !digitalRead(DATA5_LED));delay(30);digitalWrite(DATA5_LED, !digitalRead(DATA5_LED));
  if (water) digitalWrite(DATA5_LED, HIGH); else digitalWrite(DATA5_LED, LOW);
}

// Функция моргания ожидания
void ledBlink() {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(200); 
}

// Функция обработки COM порта
void cread() {

  int t = 0; // Температура. Можно float для 00.00
  
  // Читаем ввод COM порта
  if (Serial.available() > 0) {
    int val = Serial.read();
      if (val=='1') {
        t = temp1;
        Serial.print("Temp_1: ");Serial.println(t);        
      }
      if (val=='2') {
        t = temp2;
        Serial.print("Temp_2: ");Serial.println(t);
      }
      if (val=='3') {
        t = temp4;
        Serial.print("Temp_3: ");Serial.println(t);        
      }
      if (val=='4') {
        t = temp4;
        Serial.print("Temp_4: ");Serial.println(t);        
      }
      if (val=='5') {
        Serial.print("Water: ");Serial.println(water);        
      }
  }
}

Проверка

Заливаем код в плату Arduino и отправляем цифры от 1 до 5
Можно все сразу и в любом порядке
Если на выходе получаем ответ, то все в порядке и можно собирать и запаивать

Temp_1: 24
Temp_2: 24
Temp_3: 25
Temp_4: 25
Water: 0

Считываем данные

Общение с COM портом сначала думал написать на bash. Но он оказался не приспособлен для этого.
Поэтому пришлось немного изучить язык python
Ком порт может быть вида ACM. Его можно посмотреть в среде Arduino IDE
В Ubuntu все для работы ставиться просто

apt install python3 -y
apt install python3-serial -y
nano server_temp.py
#!/usr/bin/python3.6
import serial
import time
import sys

ser = serial.Serial()
ser.port = "/dev/ttyACM0"
ser.baudrate = 9600

try:
	ser.open()

except Exception:
	# print("PORT ERROR")
	sys.exit()

if ser.isOpen():
	ser.flushInput()
	ser.flushOutput()
	while True:
		time.sleep(15)
		# Датчик 1
		ser.write(b'1')
		data_1 = ser.readline().decode('utf-8')
		# Датчик 2
		ser.write(b'2')
		data_2 = ser.readline().decode('utf-8')
		# Датчик 3
		ser.write(b'3')
		data_3 = ser.readline().decode('utf-8')
		# Датчик 4
		ser.write(b'4')
		data_4 = ser.readline().decode('utf-8')
		# Датчик 5
		ser.write(b'5')
		data_5 = ser.readline().decode('utf-8')
		break
	ser.close()

sys.stdout.write(data_1);sys.stdout.flush();
sys.stdout.write(data_2);sys.stdout.flush();
sys.stdout.write(data_3);sys.stdout.flush();
sys.stdout.write(data_4);sys.stdout.flush();
sys.stdout.write(data_5);sys.stdout.flush();

Запускаем скрипт. И если все хорошо, то видим полученные данные

chmod +x server_temp.py 
./server_temp.py 
Temp_1: 25
Temp_2: 24
Temp_3: 25
Temp_4: 25
Water: 1

Zabbix Server

Теперь необходимо все что мы собрали отнести в серверную, развесить датчики и подключить к серверу Zabbix по USB плату Arduino
Сервер Zabbix установлен на Debian GNU/Linux 9.4 (stretch) x86_64
Когда все готово необходимо проверить скрипт
Ставим python. В отличии от Ubuntu, несмотря на то что в репозитарии есть python-serial просто так он работать не захотел. Пришлось ставить pip и подгружать через него
Так же версия python оказалась 3.5. Поэтому в начале скрипта необходимо сменить строчку на путь #!/usr/bin/python3.5

apt install python -y
apt install python-serial -y
apt install python3-pip -y
pip3 install pyserial

Запускаем скрипт и смотрим результаты датчиков. Если они поступают то все хорошо. На этот этап ушло много времени. Так как оказались ошибки в коде, отходили датчики и прочее. Но в итоге все исправлено и все заработало.

Добавим задание в cron, чтобы выполнял скрипт каждые 5 минут, а результат записывал в текстовый файл по пути /home/virtual/script/temp.txt

crontab -e
*/5 * * * * /home/virtual/script/server_temp.py > /home/virtual/script/temp.txt

Теперь необходимо добавить в zabbix agent новые переменные для отображения.

nano /etc/zabbix/zabbix_agentd.conf
UserParameter=temp1[*],cat /home/virtual/script/temp.txt | grep Temp_1 | cut -d " " -f2
UserParameter=temp2[*],cat /home/virtual/script/temp.txt | grep Temp_2 | cut -d " " -f2
UserParameter=temp3[*],cat /home/virtual/script/temp.txt | grep Temp_3 | cut -d " " -f2
UserParameter=temp4[*],cat /home/virtual/script/temp.txt | grep Temp_4 | cut -d " " -f2
UserParameter=water[*],cat /home/virtual/script/temp.txt | grep Water | cut -d " " -f2
service zabbix-agent restart

Zabbix отображение

Теперь необходимо зайти в Zabbix и создать новый шаблон, который потом будет применен для сервера к которому подключен Arduino
В моем случае это сам Zabbix сервер
Описывать процесс слишком долго, поэтому будет много картинок с этапами создания шаблона, элементов данных, триггеров и графиков

Итог

Как итог, теперь можно наблюдать температуру в серверной, и в случае если температура где либо превысит 25 градусов или упадет ниже 0 придет оповещение на почту
Данные отображаются прямо на карте
Вывод данных на график {Zabbix server:temp1.last(0)} (соответственно temp от 1 до 4)
Ну и красивые графики

PS:

Статья большая и объемная
Мог что упустить, недосказать или напутать
Пишите пожалуйста свои вопросы или где я был неправ

pps: Позже, если не забуду, то сфотографирую итоговый вариант

Arduino Zabbix

Новая статья про мониторинг температуры по сети

One comment

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *