ゴール設定
うちのワンコはトイプードルの「しえる」って言います。犬を飼っている皆さんは、真夏の暑い日に万が一、エアコンが故障したり、停止したままだったり、室内でも熱中症になりそうなくらい暑くなっていたらどうしよう、と心配した事ありませんか? そこで、うちの「しえる(トイプ)」を真夏の暑さから守る為にアラート通知付き室温センサーを作ります。
やることは:
1-1. ラズパイの温度センサーで、部屋の温度を計測する。
1-2. Datadogで温度データを可視化する。
1-3. Datadogの温度データが閾値を超えたらアラート通知をメール送信する。
ラズパイの部品構成(1-wire, I2C)
2-1. Raspberry Pi3 A+
2-2. 温度センサー:[1-wire]インターフェースのDS18B20、温度だけ計測できる。
2-3. UVセンサー:[I2C]インターフェースのSI1145、UVインデックス/可視光/赤外線を計測できる。
快適温度は湿度にも影響するので、どうせI2C使うならM5stackで使った温湿度センサー(BHT12)も繋げちゃおう、と思ったのだが、ラズパイの[i2cdetect]コマンドで認識できたI2Cデバイスアドレス0x5cで取得できるデータは0xFFとか0xXXばかり。あちこちインターネットで解決策を探し回ったけれど、結局、相性が悪く正しくデータ検出できなかったので止む無く温度のみセンサー(DS18B20)を使うことにした。
スクリプトの構成(python, datadog-agent)
センサーから取得した温度データは、jsonファイル[図. data.json]を経由してDatadogエージェント[図. DD agent]に渡すことにした。最初、Datadogエージェントのカスタムメトリックから直接、センサーデータを取得しようとしたが、datadogエージェントでの自作pythonのimport処理が上手くモジュールを読み込んでくれなかったので、その追及を止めてpythonでのデータ取得[図. python get data]とdatadogエージェントの機能を分離した。
3-1. 自作スクリプト[i2c_write_json.py]と関連モジュール:センサーの値を取得してjsonファイルに出力する。
3-2. Datadogエージェント[~/.datadog-agent/bin/agent]:監視エージェントの本体シェルスクリプト。jsonファイルを読んでDatadog監視サーバーにデータを送信する。
温度データを取得(python)
インストールした関連モジュール4つ:
インストールコマンドを使っていないのでファイル名は変更しています(例:ディレクトリAdafruit_GPIOにあるI2C.pyファイルはAdafruit_GPIO_I2C.pyというファイル名で保存)。
▼ Adafruit関連:MIT: Copyright (c) 2014 Adafruit Industries
4-1. Adafruit_GPIO_I2C.py
4-2. Adafruit_GPIO_Platform.py
4-3. Adafruit_GPIO_PureIO_smbus.py
▼ SI1145関連:MIT: Copyright (c) 2014 Joe Gutting
4-4. SI1145.py
▼ 自作pythonスクリプト
4-5. i2c_write_json.py
#!/usr/bin/python
import time
import SI1145 as SI1145
import os
import commands
import json
sensor = SI1145.SI1145()
def getSensors( strSensor ):
VIS = sensor.readVisible()
IR = sensor.readIR()
UV = sensor.readUV() / 100.0
CPU = float(commands.getoutput("cat /sys/class/thermal/thermal_zone0/temp"))/1000
TEMP = "cat /sys/bus/w1/devices/28-031652ddc4ff/w1_slave"
TEMP = commands.getoutput( TEMP )
TEMP = float(TEMP[-5:])/1000
if( strSensor == "VIS" ):
return float(VIS)
elif( strSensor == "IR" ):
return float(IR)
elif( strSensor == "UV" ):
return float(UV)
elif( strSensor == "CPU" ):
return float(CPU)
elif( strSensor == "TEMP" ):
return float(TEMP)
else:
return int(0)
if __name__ == '__main__':
iotdata = { "VIS": getSensors("VIS"), \
"IR": getSensors("IR"), \
"UV": getSensors("UV"), \
"TEMP": getSensors("TEMP"), \
"CPU": getSensors("CPU") }
enc = json.dumps(iotdata)
print(enc)
with open('iotdata.json','w') as f:
json.dump(iotdata, f, ensure_ascii=False)
テスト(試してみる)
センサーの値の単位が合っているのか、イマイチ不安だけどとりあえず値を取得できてjsonファイルにも出力できている。
$ python i2c_write_json.py
{"VIS": 262.0, "IR": 255.0, "CPU": 47.236, "TEMP": 24.812, "UV": 0.01}
$ cat iotdata.json
{"VIS": 260.0, "IR": 256.0, "CPU": 47.236, "TEMP": 24.875, "UV": 0.02}
自動実行の設定
毎分、センサー値をjsonファイルに出力するように crontab -e で登録した。
*/1 * * * * python /home/pi/myProgram/i2c_write_json.py
データを可視化(datadog)
datadogエージェント一式に加えて、独自コンフィグ/独自チェックの3つを設定する。
ここでラズパイにdatadogエージェントをインストールするのだが、これがとっても大変だった。理由は、公式なサポートプラットフォームではないのでOSの[rasbian]を選べず[from source]からエージェントをインストールすることになるからだった。
やってみて失敗した事
- 公式サイト『Deploying the Agent on RaspberryPI』にある手順でうまくインストールできなかった。<>
- Debianでインストール:そもそもx64じゃなくてarm64だからCPUアーキテクチャが違う。
- Dockerをインストール:コンテナイメージ5GBをダウンロード後、コンテナが起動できず終了する。原因は追究できていない。<>
- 直接コンテナをpull: <> が在ったで試したけど同じくコンテナが起動できず終了。
- DockerコンテナイメージCentOSを起動して、centOS用datadogエージェントを入れようとした。ダメだった。
- [from source]からgo言語のビルドを実行:Agent v6, v5ともに、ものすごく時間かけたのにビルドに至らず断念。手順3の[invoke deps]にあるgoのpath周辺がどうしても進まなかった。<>
Datadogサポートに相談
-
私「(英語で)こんにちは。いろいろ3日間がんばったけれど、エージェントをインストールできなかった。対象外のOSかもしれないけれど、ラズパイで、アドバイスを頂けますか?」
-
サポート「(英語)arm64プラットフォームはこれでインストールしてみて(↓)」
DD_API_KEY=<myApiKey> sh -c "$(curl -L https://raw.githubusercontent.com/DataDog/dd-agent/nate_perkins-revert_pip_to_18.1/packaging/datadog-agent/source/setup_agent.sh)"
- 私「(英語で)大晦日なのに、素早い回答ありがとうござます! 無事に動きましたーっ! そしてHappy New Year 2020 !」 無料なのに12時間以内に回答があってDatadog社のサポート凄いです。
ラズパイにインストールしたDatadogエージェント
Datadoエージェントv5は自動起動しないので(v6以降は自動起動した)、ラズパイ再起動時に自動起動するように[/etc/rc.local]ファイルを設定すること。手動でDatadogエージェントの起動/再起動をするには[~/.datadog]ディレクトリに移動して、sudo権限でagentコマンドを実行する。
$ sudo /home/pi/myProgram/.datadog-agent/bin/agent start
$ cd ~/.datadog-agent
$ # エージェントを起動する(systemctl start xx 相当)
$ sudo bin/agent start
$ # エージェントの状態を確認する(systemctl status xx 相当)
$ sudo bin/agent info
$ # datadogチェックスクリプトが正しく動作しているかチェックできる
$ sudo bin/agent check <チェック名。例:apache, nginx>
▼ 独自の監視コンフィグ
監視間隔60秒のみ。
init_config:
instances:
- min_collection_interval: 60
▼ 独自の監視チェック
jsonファイルを読み込んで[self.gauge(監視名, 値, tag=[name:key])でdatadogサーバーに値を送信。[AgentCheck]モジュールをimportするのを忘れずに。監視名は'custom_'から始まる名前が推奨されている。versionは自分用の管理バージョン。
from datadog_checks.checks import AgentCheck
import json
__version__ = "0.0.4"
class KanoCheck(AgentCheck):
def check(self, instance):
f = open('/home/pi/myProgram/iotdata.json','r')
jsonData = json.load(f)
f.close()
self.gauge('custom_iot.vis', jsonData['VIS'], tags=['host:razpi3A'])
self.gauge('custom_iot.ir', jsonData['IR'], tags=['host:razpi3A'])
self.gauge('custom_iot.uv', jsonData['UV'], tags=['host:razpi3A'])
self.gauge('custom_iot.temp', jsonData['TEMP'], tags=['host:razpi3A'])
self.gauge('custom_iot.cputemp', jsonData['CPU'], tags=['host:razpi3A'])
self.gauge('custom_iot.debug', 1, tags=['host:razpi3A'])
モニタリング、アラート通知の設定
メトリックは自作したので、ここでは[custom_iot.temp]を選び、値が30[℃]を超えたらアラート通知のメールが送信されるように設定した。
試してみる(モニタリングする)
本番では「しえる」がいつも昼寝している部屋のソファーに近い場所に、温度センサーを設置する予定だが、UVセンサーもあるのでついでに窓際で太陽光も計測してみる。
Datadogダッシュボード
カッコイイですよね! 画像イメージファイルは、無料でお世話になっている[IBM Cloud ライトアカウント]のオブジェクトストレージに保存しておき、datadogダッシュボードの[image]タイルがURLを参照して表示しています。温度の計測はバッチリだ。なお、室内の温度が30℃以上に上昇するとメールが届くが、その時のアクションは、なるべく早く家に帰ってエアコンが故障していないか点検することだ。
UV指数が5とか6とか本当なのか? 今日は曇り時々晴れなので値が上下するのはなんとなく分かるけれど...。 気象庁によると1月の日本のUV指数は2程度のようだ。なお、15:15ごろ、センサーを部屋の中に移動するとUV指数が0.05前後を示すようになった。計算式間違っているのかな、後日調べよっと。
出典:気象庁ホームページ(https://www.jma.go.jp/jp/uv/)
まとめ
DatadogでRaspberry Piも監視できた。そしてRaspberry Piに接続した各種センサー(温度計/UVインデックス/可視光/赤外線)を独自のカスタムメトリックを作成してDatadogで見える化&アラート送信することができた。DatadogはSaaSなのでそれ自体の運用はベンダーに任せることができるので、データ通信は一方通行だが、ちょっとしたIoTならDatadogを使って可用性の高いIoT基盤としても活用できるのではないだろうか。
一ヶ月データを取得してみた。
室温データのグラフを使って様々な分析ができる。
まずは[スムーズ]化したグラフ。12月9日から1月19日までの傾向を見ると、一旦1月16日~18日まで室温が下降しているが、1ヶ月スパンでみると僅かに室温が上昇しているように見える。
次は[トレンド線]をグラフ化したら、やっぱり上昇していることが分かる。