昨年の秋から冬にかけては、IoT用のマイコン関係の仕事が中心となっていました。(並行してWeb関係のインフラやJavaScript周りのお仕事もポツポツありましたが)
その間に当ブログのWordPressも5.0にアップデートし、新しいエディタGutenbergの操作に慣れない状態のまま久々の記事を書いております。
昨年末のお仕事では、合わせると100台くらいあるセンサー用のマイコンの動作状況を監視したいという趣旨で、Zabbixというオープンソースの監視システムを導入する案件がたまたま重なりました。
Zabbixについては、顧問先で管理しているサーバーを監視する目的で以前から社内でも導入しており、サーバー自体の生死やWebサーバー(Apache, Nginx等)、データベースサーバー(MySQL, MariaDB等)など重要サービスの生死の監視、サービスが停止した際の自動再起動、CPUやネットワークの負荷の監視などに利用していましたので、導入経験はありましたが、今まで監視していたのはLinuxサーバーばかり。
果たしてマイコンの監視に使えるのかというのは(その時点の自分には)未知数で、結構チャレンジングなお話でした。
LinuxサーバーをZabbixで監視する場合、
- Zabbixエージェントという監視先サーバーで動作するプログラムを導入する
- pingによるシンプルな生死チェック
という方法がまずは考えられます。
昨年秋の案件で監視するマイコンは、ものによってRaspberry Piベースだったり、ESP-WROOM-32ベースだったりとまちまち。
(ちなみに上の写真でSuicaの上に置いてあるのがRaspberry Pi 3、ほぼサイズは一緒です。こんな小さいマイコンでも立派にLinuxが楽々動きます)
Raspberry Piはマイコンと言いながらも立派なLinux PCですので、Zabbixエージェントを導入することも可能なんですが(Raspberry Pi用のLinuxであるRaspbian用のZabbixリポジトリも最新版の4.0では用意されているので導入も容易)、Arduinoで開発しているESP-WROOM-32ではZabbixエージェントの導入はもちろん不可能。
なおかつ、消費電力を抑えるために、5分に1回とか1時間に1回、数秒間だけ起動して、後は超低消費電力モードで待機するDeepSleepモードを多用していたりするものですから、スリープ状態のときにはpingにすら反応しない。
第3の手法として、
- zabbix_senderコマンドで監視先からZabbixサーバーに情報を送る
という手段を見つけましたが、これとてESPマイコン用のzabbix_senderコマンドプログラムがあるわけでもない。
詰んだかな…と思った時に、こちらの記事に助けられました。
ESP-WROOM-02からZabbixサーバーにZabbix senderプロトコルでデータを送信する
なるほど、zabbix_senderコマンドというのは、単純に決まったプロトコルに従ってデータをネットワークを通して送信するためだけの単純なコマンドだったわけです。
つまり、プロトコルに従えばコマンドを使わなくても、純粋にTCP通信するプログラムを用意してあげれば、Zabbixサーバーにデータを送信できるということになります。
上記ページのコードを解析すると、
- ZabbixサーバーのTCP 10051番ポートに対してデータを送信する
- 送信するデータのヘッダー部分の最初の5バイトは「ZBXD」という4文字と0x01
- 次いで、データ本体(ペイロード)のバイト数を8バイトのリトルエンディアンで送る
- その次にペイロードとして所定の形式のJSONデータを送る
という単純な送信プロトコルになります。
上記ページのコードを参考にさせていただいて、マイコンが一定時間ごとに起動する際に、「生きてるよ〜」という情報と、その他必要な情報(バッテリーの電圧など)をZabbixサーバーに送信して、Zabbixサーバー側ではZabbixトラッパーで受け取る仕組みで、ESPマイコンの生死を監視させることに成功しました。
センサーの生死の判定は、一定時間を超えてもデータが送られてこないということで障害として判定し、バッテリー電圧は一定の閾値を下回った場合に障害と判定していました。
しばらく運用してわかったのが、バッテリー電圧が閾値近辺で値が上下する場合、頻繁に障害と障害からの復旧というレポートを繰り返して鬱陶しいこと。
例えば閾値が3.00Vの場合、電圧変動があって2.98Vに落ちたかと思えば次回は3.02Vに上がった、なんて細かな変動を起こすと、そのたびに障害と復旧それぞれの通知がスマホでピコピコ鳴って鬱陶しいことこの上ない。
これなんとかならないかな…と思っていましたが、これも解決方法はありました。
障害として判定する閾値とは別に、障害から復旧したとみなす閾値も別に指定することができるということを学びました。(トリガー条件式(復旧条件))
これを使うと、電圧が一度でも3.00Vを下回ると、電圧低下の障害として認識するが、障害から復旧したとみなすには、電圧が3.20Vを上回る必要がある、という設定をすることができます。
こうしておけば、確実にバッテリーを交換したときにしか復旧としてみなさないようにでき、頻繁にスマホにピコピコ通知がくることもなくなるということになります。
今回はかなり対象読者が限定されるマニアックな記事になったかと思いますが、どなたかのご参考になれば幸いです。