IoTゲートウェイからCPU温度をツイートさせてみた話


マイクロサーバ OpenBlocks IoT BX1 の電源が突然切れることがあった。
屋外に設置しているため、放熱が間に合わずにCPUが熱暴走した可能性もあるので、CPUの温度を定期的に Twitter でツイートさせてみたという話。

予備知識

OpenBlocks IoT BX1とは

SoCベースのAtomプロセッサ Intel Edison を搭載し、Raspberry Pi のようなシングルボードコンピュータとしての役割も果たすIoTゲートウェイである。
デュアルコアCPU(500MHz×2)、1GBのRAM、4GBのFlashROMを備え、USBの5V給電でもLinuxがサクサク動く。
無線通信は、Wi-FiBluetoothBLE通信モジュール内蔵)、3G SIMに対応する。
有線はBX1コネクタを介し、USBRS-232CRS-485GPIO(汎用入出力)、Ethernet等に対応する。

▲ 標準SIM(miniSIM)サイズのSIMカードを装着できる。

CPUの熱暴走とは

CPUは高負荷になると電圧を高めて動作周波数を引き上げる。これが発熱の原因。
ただし現在のCPUにはフェイルセーフ(保護機構)があるので発熱による損傷の心配は無い。CPU温度が上がり続けると、クロック信号の供給を間引くスロットリング状態になり、自動的に温度を下げようとするのだ。スロットリングをしても冷却が間に合わなければCPUは停止する。これはシャットダウンのような安全な停止ではなく、強制的に電源が切れてしまうのでログには何も残らない。当然、作業中のデータは失われる。

CPU温度は70℃を超えると危険、高くても80℃までと言われている。

設定方法

BX1のアクセスポイントに接続

OpenBlocksのWi-FiにはクライアントモードAPモードがあり、クライアントモードでは既存Wi-Fiに接続、APモードではOpenBlocks自らがアクセスポイントとなる。
Bluetooth経由で受けたセンサーデータをクラウドのサーバに送信するため、普段はAPモードでモバイル回線(3G)に接続しているが、開発/メンテナンス時は通信料金節約のため、クライアントモードで既存Wi-Fiからインターネットに接続する。

ブラウザからBX1のアクセスポイントとなるURLにアクセスし、WebUIからネットワーク設定を変更する。

BX1のコンソールにログイン

Wi-Fiネットワークのssh接続、もしくは有線シリアルポート接続でBX1にログインする。
BX1は標準で、製造元のぷらっとホーム社が Debian GNU/Linux 7(Wheezy) をインストールしている。

# cat /etc/debian_version
7.8
# cat /etc/issue
Debian GNU/Linux 7 \n \l

なお、緊急時の起動OSとして、インテルがEdisonに標準で搭載する Yocto Linux(組み込み系Linux)も入っている。

準備

Twitter API を呼ぶにはPythonのパッケージを使うのがお手軽なのだが、パッケージ管理ツールpipapt-getではインストールできない。WheezyがEOL(サポート終了)でリポジトリが参照できなくなっているからだ。

これは失敗する
# apt-get install python-pip

/etc/apt/sources.listarchive.debian.orgに書き替えても良いのだが、今回は環境をあまり変えたくなかったので、

# wget https://bootstrap.pypa.io/get-pip.py
# python get-pip.py

# pip --version
pip 19.2.1 from /usr/local/lib/python2.7/dist-packages/pip (python 2.7)

で直接インストールした。

これでpipが使えるようになったので、REST APIrequestsOAuth認証requests-oauthlibを導入する。

# pip install requests requests-oauthlib

Twitter API限定で使うなら、それ用に特化したtweepyとかTwitterAPIの方が使い易いかもしれない。

スクリプトの作成


という流れになる。
モバイル回線の接続/切断は、ぷらっとホーム社が提供しているシェルスクリプトをそのまま使う。

ツイートするだけのPythonスクリプト

スクリプト実行時に渡された引数をそのままツイートし、ステータスコードを表示して終了するだけだ。200なら正常終了である。
認証情報に渡すAPIキーの取得方法は、@kazupen2018さんの記事、新しくなったTwitterAPIの発行・申請方法を参照して欲しい。
ツイートAPIの仕様は http://westplain.sakuraweb.com/translate/twitter/Documentation/REST-APIs/Public-API/POST-statuses-update.cgi で和訳が公開されている。

tweet.py
import json
from requests_oauthlib import OAuth1Session
import sys

API_KEY = "XXXXXXXXXX"
API_SECRET_KEY = "XXXXXXXXXX"
ACCESS_TOKEN = "XXXXXXXXXX"
ACCESS_TOKEN_SECRET = "XXXXXXXXXX"

twitter = OAuth1Session(API_KEY, API_SECRET_KEY, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
res = twitter.post("https://api.twitter.com/1.1/statuses/update.json", params = { "status" : sys.argv[1] })
print(res.status_code)

CPU温度を取得しPythonスクリプトに渡す

lm-sensorsというツールで取得しても良いのだが、今回は余計なものを入れたくないのでsysfs経由で取得した。
BX1では/sys/devices/platform/coretemp.0にある。単位はセルシウス度(摂氏)。1000で除すること。

post.sh
#!/bin/bash
/var/webui/scripts/mobile_control.sh con 1  # モバイル回線(3G)の接続
sleep 3
TM=`date "+%H:%M"`
X0Y2=`awk '{ printf "%3.3f", $0 / 1000 }' < /sys/devices/platform/coretemp.0/temp2_input`
X0Y3=`awk '{ printf "%3.3f", $0 / 1000 }' < /sys/devices/platform/coretemp.0/temp3_input`
/usr/bin/python `dirname $0`/tweet.py "$TM///$X0Y2/$X0Y3"
/var/webui/scripts/mobile_control.sh coff 1  # モバイル回線(3G)の切断

時刻も同時にツイートしているが、これは「同じツイートを連続で投稿できない」という仕様への対策だ。

自動実行

cronで30分ごとに実行するよう登録した。

crontab
22,52 * * * * /home/mindwood/post.sh > /dev/null 2>&1

実行結果

Twitterから確認。温度が2つ出力されるのはデュアルCPUだからだ。