Мониторинг температуры Raspberry Pi + zabbix

Введение

Задача: мониторинг температуры в серверной и на улице, а также сохранение статистики и рисование графиков.

Для решения задачи нам понадобится:

Подготовка Raspberry Pi

Для начала нужно установить ОС на флеш-карту, как это сделать подробно описано тут. После того, как система установлена и загружается нужно ее подготовить для работы. Во-первых, настраивает локальную сеть, дату, время, часовой пояс и т.д. Во-вторых в файл /etc/modules добавляем модули необходимые для работы температурных датчиков и дисплея:

i2c-dev
w1-gpio
w1-therm

Подключение датчиков и дисплея

Для подключения температурных датчиков нам понадобится трехжильный кабель(или более), отлично подойдет четырехжильная витая пара. У датчика три пина: земля, пин по которому передаются данные и плюс питания:

Датчики подключаются парралельно на один кабель. Протягиваем кабель от места установки Raspberry через те места, где мы хотим повесить датчики. После чего в конце линии вешаем датчик, подключив его к трем жилам кабеля(запоминаем цвета жил к каким подключили пины датчика) и соответственно по ходу линии делаем любое кол-во разрезов и врезаем туда датчики на те же цвета(не перепутать, а то можно спалить датчики). Также в любом месте между пином данных и пином +3,3в надо поставить один резистор 4.7кОм, я установил его в корпусе, но можно в любом месте на линии, где удобно. Наглядная сехма подключения датчика на макетной плате(для тестов) ниже:

Итак, датчик(и) подключен(ы), вышеуказанные модули ядра загружены, после этого в каталоге /sys/bus/w1/devices/ должен появиться список ваших датчиков, у каждого свой аппаратный номер:

# ls -1 /sys/bus/w1/devices
28-0000045ef9b4
28-0000045f1c62
28-0000046022cb
w1_bus_master1

В моем случае 3 датчика, пробуем теперь считать показания(заниает 1 секунду):

# cat /sys/bus/w1/devices/28-0000045ef9b4/w1_slave
a6 00 4b 46 7f ff 0a 10 cb : crc=cb YES
a6 00 4b 46 7f ff 0a 10 cb t=10375

Вот в таком виде датчик дает показания, чтобы получить температуру в градусах нужно разделить на 1000:

10375 / 1000 = 10.375 С

Если все работает, переходим к подлючению дисплея. Схема подключения пинов дисплея к пинам GPIO показаны ниже(4х битный режим):

Если дисплей подключен правильно, то уже должна загореться подсветка. Далее нужно установить в системе библиотеку Wiring Pi для Си, которая позволит нам работать с дисплеем. Установка очень простая, распаковываем архив и запускаем скрипт build:

# tar xfz wiringPi-98bcb20.tar.gz
# cd wiringPi-98bcb20
# ./build

Установка завершена, проверим:

# gpio -v
# gpio readall

Теперь проверим работоспособность дисплея, скомпилируем и запустим эту программу(источник указан в списке литературы), которая выведет сообщение на экран:

#include <stdio.h>  //стандартная библиотека ввода-вывода
#include <wiringPi.h>  //библиотека из пакета wiringPi
#include <lcd.h>  //библиотека из пакета wiringPi

int main (void)
{
 printf ("Raspberry Pi LCD test\n") ;
 //Инициализация порта GPIO
 if(wiringPiSetup ()==-1)
 {
  printf ("GPIO Setup failed!\n") ;
 }
 
 int fd;
 printf ("Start LCD initialization...\n") ;
 //Инициализация LCD
 fd = lcdInit (4,20,4, 11,10, 1,0,2,3,0,0,0,0);
 
 if(fd==-1)
 {
  printf ("Initialization failed\n") ;
 }
 else
 {
  printf ("GO!\n");
 
  //Очистка дислпея
  lcdClear(fd);
   
  //Перевод каретки на первую позицию первой строки
  lcdPosition (fd,0,0);
   
  //Вывод форматированного текста
  lcdPrintf(fd, "Hello Pi");
 
  //Перевод каретки на вторую строку и вывод текста
  lcdPosition (fd,0,1);
  lcdPrintf(fd, " World!");
 
  //Перевод каретки на третью строку и вывод текста
  lcdPosition (fd,0,2);
  lcdPrintf(fd, "25-01-2014");
 
  //Перевод каретки на четвертую строку и вывод текста
  lcdPosition (fd,0,3);
  lcdPrintf(fd, "Happy New Year))))");
 }
 return 0;
}

Компилируем и запускаем:

# gcc -Wall -o test test.c -lwiringPi -lwiringPiDev
# ./test  

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

Снятие показаний

Если бы я использовал показания термодатчиков только для zabbix, то можно было бы снимать их непосредственно zabbix-агентом, но я еще захотел выводить эти показания на дисплей, соответственно, чтобы не было две программы, которые одновременно пытаются считать показания, я сделал скрипт, который через cron каждую минуту опрашивает датчики и сохраняет их показания, после чего эти данные также раз в минуту выводятся на дисплей и считываются zabbix-агентом. Так как в качестве устройства хранения данных используется флеш-карта, то было бы крайне не желательно писать на нее каждую минуту, пусть и небольшие кусочки данных, думаю, долго она не выдержала бы. Поэтому для этих целей в системе был создан ram-диск размером 10МБ и уже на него будут сохранятся показания датчиков.

Итак, создаем каталог /mnt/tmpfs и в /etc/fstab прописываем стоку:

tmpfs   /mnt/tmpfs         tmpfs   nodev,nosuid,size=10M          0  0

Теперь после перезагрузки у нас появится небольшая файловая система в оперативной памяти.

И наконец создадим скрипт /opt/scripts/gen_temp.sh(у меня три датчика):

#!/bin/bash

cat /sys/bus/w1/devices/28-0000045ef9b4/w1_slave | grep t= | head -1 | awk '{print substr($10,3)/1000; }' > /mnt/tmpfs/0000045ef9b4

cat /sys/bus/w1/devices/28-0000046022cb/w1_slave | grep t= | head -1 | awk '{print substr($10,3)/1000; }' > /mnt/tmpfs/0000046022cb

cat /sys/bus/w1/devices/28-0000045f1c62/w1_slave | grep t= | head -1 | awk '{print substr($10,3)/1000; }' > /mnt/tmpfs/0000045f1c62

В результате выполнения которого в каталоге /mnt/tmpfs появятся файлы с показаниями датчиков в формате float.

В скрипте нужно заменить ID моих датчиков на ваши (28-0000045ef9b4 и т.д.)

Осталось добавить строку в /etc/crontab и перезапустить cron:

  • * * * * root /opt/scripts/gen_temp.sh

# /etc/init.d/cron restart

На данном этапе у нас показания датчиков считываются каждую минуту и сохраняются в файл. Теперь надо написать программу, которая будет считывать эти файлы и выводить показания на экран. Вот пример моей программы с тремя датчиками display.c:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <lcd.h>
#include <unistd.h>

int main (void)
{
 FILE * fp;
 char * line = NULL;
 size_t len = 0;
 char display[81];
 float temp_s1;
 float temp_s2;
 float temp_out;

 printf ("Raspberry Pi LCD test\n") ;
 //Инициализация порта GPIO
 if(wiringPiSetup ()==-1)
 {
  printf ("GPIO Setup failed!\n") ;
 }

 int fd;
 printf ("Start LCD initialization...\n") ;
 //Инициализация LCD
 fd = lcdInit (4,20,4, 11,10, 1,0,2,3,0,0,0,0);

 if(fd==-1)
 {
  printf ("Initialization failed\n") ;
 }
 else
 {
  printf ("GO!\n");

  //Чтение температуры
  fp = fopen("/mnt/tmpfs/0000046022cb", "r");
  if (fp == NULL)
      exit(EXIT_FAILURE);
  getline(&line, &len, fp);
  temp_s1 = strtof(line, NULL);
  close(fd);

  fp = fopen("/mnt/tmpfs/0000045ef9b4", "r");
  if (fp == NULL)
      exit(EXIT_FAILURE);
  getline(&line, &len, fp);
  temp_s2 = strtof(line, NULL);
  close(fd);

  fp = fopen("/mnt/tmpfs/0000045f1c62", "r");
  if (fp == NULL)
      exit(EXIT_FAILURE);
  getline(&line, &len, fp);
  temp_out = strtof(line, NULL);
  close(fd);

  //Очистка дислпея
  lcdClear(fd);

  //Перевод каретки на первую позицию первой строки
  lcdPosition (fd,0,0);

  //Формируем строку
  sprintf(display, "Pe\xBD\xE3""ep\xBD""a\xC7 \xE0""1: %06.2fPe\xBD\xE3""ep\xBD""a\xC7 \xE0""2: %06.2f\xA9\xBB\xB8\xE5""a       : %06.2f                    ", temp_s1, temp_s2, temp_out);

  lcdPrintf(fd, display);
}
 return 0;
}

Эта программа инициализирует дисплей, очищает его, считывает показания датчиков из файлов, формирует строку длиной 80 символов(дисплей выводит по 20 символов на строке) и выводит ее на дисплей.

Скомпилируем ее и запустим:

# gcc -Wall -o display display.c -lwiringPi -lwiringPiDev
# ./display

В результате чего на дисплее появятся показания с трех датчиков(в моем случае).

По поводу кирилицы: нельзя просто так взять и написать на русском языке, из-за кодировок дисплей выведет полную ерунду. Чтобы выводить русские символы нужно писать их в hex-формате, т.е. например \xFF. Таблицу самих же символов и их коды можно поглядеть в официальной документации к дисплею на странице 8 или на рисунке ниже. Если вы хотите смешивать латиницу и кирилицу(как сделал я), то после кода кирилического символа нужно добавить две кавычки »» и дальше любое кол-во латинских букв или цифр

Если все отработало корректно, то осталось добавить скомпилированную програму для автовыполнения в скрипт /opt/scripts/gen_temp.sh (в конец):

/opt/scripts/display

Zabbix-агент

К этому моменту у нас уже показания с датчиков снимаются, на дисплей выводятся, осталось настроить zabbix. Подходящих бинарников для Raspberry Pi нет, поэтому придется собрать из исходников. Качаем сорцы, распаковываем, компилируем и устанавливаем:

# ./configure --prefix=/usr/local/zabbix_agent --enable-agent
# make install
# useradd zabbix
# mkdir /var/run/zabbix
# mkdir /var/log/zabbix
# chown zabbix /var/run/zabbix
# chown zabbix /var/log/zabbix  

Если все прошло успешно, редактируем конфигурационный файл /usr/local/zabbix_agent/etc/zabbix_agentd.conf и приводим его к такому виду:

PidFile=/var/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=5
DebugLevel=0
Server=address.of.zabbix.server

ListenIP=X.X.X.X
Hostname=rfarm-raspberrypi

ServerActive=address.of.zabbix.server
HostnameItem=system.hostname

Timeout=10

UserParameter=custom.temp.rfarm.sensor1,/bin/cat /mnt/tmpfs/0000046022cb
UserParameter=custom.temp.rfarm.sensor2,/bin/cat /mnt/tmpfs/0000045ef9b4
UserParameter=custom.temp.outside.sensor1,/bin/cat /mnt/tmpfs/0000045f1c62

Тут главное указать адрес вашего zabbix-сервера в параметрах Server и ServerActive, IP-адрес на котором агент будет ждать подключения ListenIP и задать имя агента Hostname. И самое главное - задать параметры пользователя UserParameter с помощью которых агент будет считывать показания.

Теперь протестируем наши параметры, что они корректно считываются:

# /usr/local/zabbix_agent/sbin/zabbix_agentd -t custom.temp.rfarm.sensor1
custom.temp.rfarm.sensor1                     [t|17.812]

# /usr/local/zabbix_agent/sbin/zabbix_agentd -t custom.temp.rfarm.sensor2
custom.temp.rfarm.sensor2                     [t|11.812]

# /usr/local/zabbix_agent/sbin/zabbix_agentd -t custom.temp.outside.sensor1
custom.temp.outside.sensor1                   [t|-5.125]

Все нормально, осталось добавить агента в автозагрузку, проще всего добавить в /etc/rc.local такую строку:

/usr/local/zabbix_agent/sbin/zabbix_agentd -c /usr/local/zabbix_agent/etc/zabbix_agentd.conf

Zabbix-сервер

Ну и осталось создать хост и прописать для него итемы и графики в веб-интерфейсе.

Создаем хост(наш raspberry pi):

По желанию добавляем ему шаблон «zabbix-агент», чтобы отслеживать состояние хоста:

На каждый датчик создаем свой item(элемент, который будет коллекционировать данные), для каждого датчика у нас заранее на стороне zabbix-агента прописаны наши собственные параметры, ниже пример создания итема:

В итоге у меня получилось три итема, по одному на каждый датчик:

И в конце создаем любое кол-во графиков, какое нужно, хоть по отельному на каждый итем, хоть один для всех сразу. На примере ниже создается один график, на котором будут рисоваться показания всех датчиков:

На этом все.

Заключение

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

Список использованной литературы

temp_mon.txt · Последние изменения: 2014/02/06 16:44 — metallic
 
Recent changes RSS feed