ESP8266(ESP-WROOM-02)からZabbixに対してRESTで温湿度データを送信する


はじめに

Zabbixを使って自分で定義したメトリクス値を収集したい場合、通常は対象ホストにzabbix_agentdをインストールするか、zabbix_senderを使ってzabbix_serverに対してデータを送る必要があります。

しかし物理センサーの値を収集するためArduinoのようなマイコンを使う場合、zabbix_agentdやzabbix_senderを直接動かすことは出来ません。そのような場合はraspberry PiのようなLinuxBoxとシリアルで繋ぎ、raspberry Piをゲートウェイとしてzabbix_serverへ連携しますが、そのような構成は配置場所毎にゲートウェイが必要となりコストが嵩みがちです。

そのため今回は、ZabbixAPIでは用意されていないメトリクスデータをHTTPで受信するRESTインターフェースを新たに作り、ESP8266(ESP-WROOM-02)に接続した温湿度センサーのデータをWifi経由で直接収集したいと思います。

使うもの

スイッチサイエンス ESP-WROOM-02開発ボード
温湿度センサモジュール AM2320
ミニブレッドボード
ジャンパーコード

接続は下記のページを参考にしました。
AM2320をArduinoで使う

Zabbix側設定

スクリプト配置

RESTインターフェースといっても超手抜きなbashスクリプトのCGIでパラメータを受け取って、zabbix_senderに渡しているだけです。
Zabbixサーバの「/user/share/zabbix」の下に適当にフォルダを作ってスクリプトを配置し、CGIを実行出来るようにします。

/usr/share/zabbix/rest
├── .htaccess
└── setdata.cgi

setdata.cgi
#!/bin/bash
serverHost="localhost"
serverPort="10051"
tagetHost="$1"
tagetKey="$2"
value="$3"

zabbix_sender -z "$serverHost" -p "$serverPort" -s "$tagetHost" -k "$tagetKey" -o "$value" > /dev/null 2>&1

if [ $? -eq 0 ]; then
   echo "Content-Type: text/html"
   echo "Status: 200 OK"
   echo ""
   echo "success"
else 
   echo "Content-Type: text/html"
   echo "Status: 500 ERROR"
   echo ""
   echo "error"
fi
.htaccess
Options +ExecCGI
AddType text/html cgi
AddHandler cgi-script cgi

今回はやってませんが、オープンな環境で使うならBASIC認証+TLS暗号化くらいは実施したほうがよいでしょう。

Zabbixアイテム設定

1. ホストに「sensor_node001」を追加。
2. 温度用アイテムを追加

名前 温度
タイプ Zabbixトラッパー
キー sensor.dh22.temp
データ型 数値(浮動小数点)
単位

3. 同様に湿度用のアイテムを作る

名前 湿度
タイプ Zabbixトラッパー
キー sensor.dh22.humi
データ型 数値(浮動小数点)
単位 %

テスト

$ curl -v http://localhost/zabbix/rest/setdata.cgi?sensor_node001+sensor.dh22.temp+25.1

ESP-WROOM-02側設定

以下のページを参考にarduinoスケッチを作成し、ESP-WROOM-02に書き込みました。

参考ページ

ESP-WROOM-02 開発ボードの使い方をザッと紹介
ESP-WROOM-02 Arduino互換ボードでサクッとHTTP通信できたよ
マイコンとセンサーで温度と湿度を測ってみよう

dataUpload.uno
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <DHT.h>

const char* ssid = "AccessPointName";
const char* password  = "hogehoge";

#define DHTTYPE DHT22
#define DHTPIN 4
DHT dht(DHTPIN, DHTTYPE);

void requestURI() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.print("\ttemperature:"); Serial.print(t);
  Serial.print("\thumidity:"); Serial.print(h);
  Serial.print("\n");

  HTTPClient http;
  String url = "http://zabbix-server_IP/zabbix/rest/setdata.cgi?";

  String url_temp ="";
  url_temp += String(url);
  url_temp += String("sensor_node001+");
  url_temp += String("sensor.dh22.temp+");
  url_temp += String(t);

  String url_humi ="";
  url_humi += String(url);
  url_temp += String("sensor_node001+");
  url_humi += String("sensor.dh22.humi+");
  url_humi += String(h);

  http.begin(url_temp);
  int httpCode_t = http.GET();
  http.end();

  http.begin(url_humi);
  int httpCode_h = http.GET();
  http.end();

}

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println("booted!");

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  WiFi.mode(WIFI_STA);
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  if(WiFi.status() == WL_CONNECTED) {
    requestURI();
  } else {
    Serial.println("Wifi not connected");
  }
  delay(60000);

}

収集したデータ

このような感じでESP-WROOM-02から1分おきに送られてくるデータを取得し、温湿度データを可視化することができました。

さいごに

Zabbix側にRESTインターフェースを用意することで、zabbix_agentdやzabbix_senderを導入できない端末からも直接データ収集ができるようになりました。またHTTP(s)しか通信が許可されていないような環境でも、わざわざポートを空けることなくデータの収集が出来るようになるのではないでしょうか。今回はRESTでしたがMQTTで受信できるようにしても面白そうです。

尚、当初はZabbixにデータ受信用のインターフェースがないため他のプロダクトを使うつもりでいました。最終的に温度・湿度と人感センサー、ジオフェンス、IR-Kit等を組み合わせてエアコンや電灯等の家電制御を行いたかったのですが、複合イベント処理(Complex Event Processing) 的なことが出来ないようなので断念しました。

Zabbixのアイテム、トリガー、アクション設定は兎角むずかしいと言われがちですが、他の監視系プロダクトでは単一メトリクスに対する閾値設定・アラート通知しかできず、複数メトリクスに対してCEP的な処理をプログラムを書かずに実現できるものは少ないようです。今後はZabbixの持つ柔軟で高度な機能をうまく使いこなしてデータの収集・可視化だけでなく、分析・制御まで繋げていきたいと思っています。