ワクチン接種後の発熱を見るのにIOT体温計を作った
モデルナの2回目接種は、副反応がキツいらしい。それで何度も体温を測るのは面倒だし、どうせなら連続したデータで変動を見たいので、IoT体温計を作り、データ記録を自動化することにした。
まずマイコンボードだが、LCD付きの「TTGO T-Display」に決定。今回は自宅に在庫があったのでこれにしたのだが、計測データはどうせクラウドにアップするので、LCDは無くても構わないだろう(購入時価格は1,699円)。
温度センサーは、スイッチサイエンスで「LM35DZ」(190円)と「LM75B」(385円)を購入。LM35DZはアナログ出力だが、温度に対する電圧が10.0mV/℃とリニアで使いやすい。室温での精度も±0.25℃と悪くない。LM75Bのような電子基板を肌に貼り付けるのもちょっと不安なので、まずはこのLM35DZで実装を試してみた。
が、プログラムを動かしてみると、どうも計測値がおかしい。調べてみたら、ESP32のアナログ入力には、0V付近で不感帯があり、使い方によっては精度に問題が出るらしい。今回はそれで10℃以上の誤差が出てしまったので、このままだと厳しい。実測値との補正値を入れるという手で誤魔化すのも考えたのだが、どうもスッキリしないので、とりあえずLM75Bも試してみることにした。
LM75BはI2C接続なので、I/O部分で誤差が生じることはない。一方、計測レンジは-55℃~+125℃とかなり広いものの、体温計という用途としてはオーバースペック。精度は±2℃と、ちょっと気になる大きさだ。ただ、今回は温度の変動が分かればいいと思っていたので、とりあえずこちらを使うことに決めた(時間もないので)。
コードは以下の通り。体温は毎秒計測し、平均値を10分ごとにサーバーに送信している。サーバーはいつも通り、無料で簡単に使えるAmbientにした。
#include <TFT_eSPI.h>#include "Ambient.h" #include <Wire.h> #define LM75B_address 0x48 #define temp_reg 0x00 #define REPORTING_PERIOD_MS 600*1000 //データ送信間隔(ms) WiFiClient client; const char* ssid = "xxxxxxxxxxx"; //Wi-Fi APのSSID const char* password = "xxxxxxxxxxx"; //Wi-Fi APのパスワード Ambient ambient; unsigned int channelId = xxxxxxxxxxx; // AmbientのチャネルID const char* writeKey = "xxxxxxxxxxx"; // ライトキー float sum_temp=0.0; int cnt=0; uint32_t tsLastReport=0; TFT_eSPI tft = TFT_eSPI(); void setup() { //画面初期化 tft.begin(); tft.setRotation(1); tft.setTextSize(4); //Wi-Fi初期化 WiFi.begin(ssid, password); //Wi-Fi APに接続 while (WiFi.status() != WL_CONNECTED) { //Wi-Fi AP接続待ち delay(100); } ambient.begin(channelId, writeKey, &client); //Ambientを初期化 //I2C接続 Wire.begin(); Wire.beginTransmission(LM75B_address); Wire.write(temp_reg); Wire.endTransmission(); //デバッグ用 //Serial.begin(115200); } float read_temp1(){ signed int temp_data = 0; //LM75Bの温度レジスタの値用変数 float temp = 0.0; //温度用変数 Wire.requestFrom(LM75B_address,2); while(Wire.available()){ temp_data |= (Wire.read() << 8); //温度レジスタの上位8bit取得 temp_data |= Wire.read(); //温度レジスタの下位8bit取得(有効3bit) } temp = (temp_data >> 5) * 0.125; //レジスタの値を温度情報に変換 //Serial.println(temp); return temp; } void loop() { float temp; temp = read_temp1(); tft.fillScreen(TFT_BLACK); tft.setCursor(0, 0); tft.setTextColor(TFT_WHITE); tft.print("Temp:"); tft.println(); tft.print(temp); tft.print(" deg"); cnt++; sum_temp += temp; //データ送信処理 if (millis() - tsLastReport > REPORTING_PERIOD_MS) { tsLastReport += REPORTING_PERIOD_MS; ambient.set(1, sum_temp/(float)cnt); ambient.send(); cnt = 0; sum_temp = 0.0; } delay(1000); }
参照用の平常時データとして、まず接種前日のデータを計測した。このときのデータは以下の通りだ。
私の平熱は37℃前後なのだが、通常の体温計で計測したデータと比較してみると、1℃くらい低く出ていることが分かった。センサーは体表に貼り付けるだけなので、どうしても脇の下で挟んで計測する方法に比べると、数値が低く出るのは納得できる。エアコンの設定温度や、扇風機の当たり具合によっても変動が生じる可能性があるが、これはまあ仕方ないだろう。
そしてモデルナ2回目接種当日のグラフがこれだ。接種時刻は13時半くらいなのだが、Tシャツの中から電線が伸びているおっさんなんて怪しすぎて無用のトラブルに巻き込まれる恐れがあるため、センサーは外して出かけ、帰宅後に計測を再開した。多少の上下はあるものの、上昇トレンドにあるのが見える。
センサーが剥がれる可能性もあったものの、この夜はダメ元でセンサーを貼り付けたまま就寝。あまり寝返りを打たないよう注意しながら寝た結果、朝までの計測に成功した。このときの結果がこれだ。
就寝中に、39℃前後まで上昇していたことが分かる。普通の体温計で計測してもそのくらいだったので、これはおそらく、寒気がして布団の中に潜り込んでいたため、センサー周囲の気温も体温近くまで上がり、温度低下が少なかったからではないだろうか。7時前後に大きく体温が下がっているが、これは体が布団から出たのかもしれない。
しかしセンサーを付けっぱなしで寝たため、その場所がかぶれてしまい、ここで一旦計測を中断。ここからは普通の体温計で計測していたのだが、ずっと39℃前後で頭痛も出てきたため、15時くらいに解熱剤を服用した。センサーを貼り付ける場所を変えて、ここから計測も再開。
そこから18時くらいまでは上昇しているように見えるが、19時くらいにガクッと下がり、そのままキープ。解熱剤の効果も切れているだろうから、このあたりでワクチン副反応による発熱が終わったということかもしれない。
このIoT体温計、もし私がコロナに感染し、自宅療養とかになったらうまく使える可能性もあるだろうが、肌がかぶれてしまうのと、寝づらい点は大きな課題だ。解決方法は、もし自宅療養になったらまたそのときに考えよう。