編集履歴一覧に戻る
SJKのアイコン画像

SJK が 2024年05月24日12時06分45秒 に編集

コメント無し

本文の変更

# 概要 メディカル・バイオ系の研究室には必ずあるフリーザーやディープフリーザー。特に、ディープフリーザーの温度上昇は今までの研究資産を失う可能性が有ります。それ故、巷では様々なメーカーからフリーザーの遠隔監視・警報システムが販売されていますが、それなりの価格がします。 そこで本記事では、比較的低価格(~6,500円)で簡易の温度遠隔監視・警報システムを構築しました。

-

- (注)記事の最後にAtomS3 LiteとUnit-KmeterISOユニットを使ったはんだ付けの必のない(しかも安い~5,000円)バージョンも追記しました。

+

- **(注)記事の最後にAtomS3 LiteとUnit-KmeterISOユニットを使ったはんだ付け(しかも安い~4,500円)バージョンも追記しました。**

# 使用したモジュール - [M5Atom lite (M5STACK-C008)](https://www.switch-science.com/products/6262) - [ATOMICプロトキット (M5STACK-A077)](https://www.switch-science.com/products/6345) - [K型熱電対プローブ](https://akizukidenshi.com/catalog/g/g100306/) - [Amazon](https://www.amazon.co.jp/gp/product/B0BRFPH1C1/)などでも購入できます - [MAX31855使用 K型熱電対アンプモジュール](https://akizukidenshi.com/catalog/g/g108218/) - [Amazon](https://www.amazon.co.jp/dp/B0CNKKRT46/)などでも購入できます # 開発環境 Arduino IDE v2.2.1 - 追加のボード: - M5Stack -> M5Atom https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json --- - 追加ライブラリ: - M5Atomライブラリ https://github.com/m5stack/M5Atom - Adafruit_MAX31855ライブラリ https://github.com/Seeed-Studio/Seeed_MAX31850K - ThingSpeakライブラリ https://github.com/mathworks/thingspeak-arduino # 実装したこと K型熱電対+熱電対アンプモジュールで温度を計測し、M5AtomLiteでwifiで3分ごとにThingSpeakに温度データを送信・蓄積し、設定温度以上で警報をLineNotifyで通知するシステムを構築した。同時に、ThingSpeakが一定時間データを受信しなかったときの警報と毎日の定時連絡機能も付加した。 # ThingSpeakの初期設定 - [ThingSpeak](https://thingspeak.com/)のページを開いて新しいアカウントを作成。Sign Upをクリック。ユーザID・メールアドレス・タイムゾーン・パスワードを設定しCreate Accountボタンをクリック。 - チャンネルの作成。チャンネルにはデータ・場所・状態を登録できる(8個まで)。今回は2個(庫内温度・モジュール温度)のセンサデータを書き込むためのチャンネルを作成。 1. メニューバーの Channels > MyChannels をクリック。 1. New Channel ボタンをクリック。 1. 以下の情報を入力。 1. Name;(チャンネルの名前) 1. Field1; Temp(フィード1の名前) 1. Field2: AmbTemp(フィード2の名前) 1. Make Public(一般公開しても良いならチェック) 1. Save Channel ボタンで保存 - 書き込み用のAPIキーの取得とチャンネルID スケッチにはチャンネルIDとAPIキーが必要なので、 1. メニューバーの Channels > MyChannels をクリックして、先ほど作成したチャンネルを開く。 1. Channel ID と書かれた7桁の数字がチャンネルID。 1. API Keys をクリックして Write API Key と書かれた英数字の文字列が書き込み用のAPIキー。 上記2つをメモしておく # 結線 - アンプモジュールに付属のターミナルブロック(熱電対接続部)をはんだ付けします。 - ATOMICプロトキットの上半分に熱電対アンプモジュールをはめ込みますので、プロトキット付属の基盤の上部をニッパーなどで切り離します。 - 下図のように結線します。点線部は基板下で配線。 ![キャプションを入力できます](https://camo.elchika.com/cf75caf2c37c118bc37a264d8899e33091895941/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f30306230666163622d656565642d346530302d623331372d666161386431306365643666/)

-

- 熱電対の黄色のコネクタを外し、金属線をむき出しにしてアンプモジュールのターミナルブロックに繋げます。極性がありますので、コネクタを外すときにどちらがラス(+)でどちらがマイナス(-)だったか分かるようにした方が後々楽です。もし分からなくなったら、中身の被覆に赤糸ある方がプラスです。

+

- 熱電対の黄色のコネクタを外し、金属線をむき出しにしてアンプモジュールのターミナルブロックに繋げます。極性がありますので、コネクタを外すときにどちらがラス(+)でどちらがマイナス(-)だったか分かるようにした方が後々楽です。もし分からなくなったら、中身の被覆に赤糸ある方がプラスです。

![キャプションを入力できます](https://camo.elchika.com/723967f6fd1cf276c9ed2d45f9e8d0be2c33b960/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f66303534343932642d633062342d343663612d396430332d353763616337643565353031/) # プログラム - Arduino IDEの[インストール方法](https://docs.m5stack.com/en/arduino/arduino_ide)や[マイコンボードの追加](https://docs.m5stack.com/en/arduino/arduino_board)、[ライブラリの追加](https://docs.m5stack.com/en/arduino/arduino_library)、[Atom Liteへのスケッチの書き込み方法](https://docs.m5stack.com/en/arduino/m5core/program)等は[ネット上](https://www.marutsu.co.jp/pc/static/large_order/arduino_IDE_220208)にあふれていますので、各自でお願いします。 - 下記、M5atom_MAX31855_SPI_ThingSpeak.inoの WiFi設定部分 `const char ssid[] = "your_SSID";` `const char pass[] = "your_password";` と ThingSpeak設定部分 `const unsigned long myChannelNumber = your_Ch_##;` `const char * myWriteAPIKey = "your_API_Key";` を各自の環境に書き換えてAtom Liteに書き込みます。 ```arduino:M5atom_MAX31855_SPI_ThingSpeak.ino #include <M5Atom.h> #include <ThingSpeak.h> #include <SPI.h> #include "WiFi.h" #include <Adafruit_MAX31855.h> // Wifi設定(Wifi環境に合わせて変更) const char ssid[] = "your_SSID"; const char pass[] = "your_password"; // ネットワーク設定(必要ならネットワーク環境に合わせて変更) // IPAddress ip(192, 168, 100, 100); // IPAddress gateway(192, 168, 100, 1); // IPAddress subnet(255, 255, 255, 0); // ThingSpeak設定(チャンネルIDと書き込み用APIキーを変更) const unsigned long myChannelNumber = your_Ch_##; const char * myWriteAPIKey = "your_API_Key"; // ThingSpeak接続用 WiFiClient client; // MAX31855のソフトウエアSPIのIOピン番号を指定 // M5Atom lite用 #define MAXDO 23 #define MAXCS 19 #define MAXCLK 22 // initialize the Thermocouple Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO); void setup() { M5.begin(true, false, true); // 起動メッセージ出力 //Serial.begin(9600); //Serial.println("Hello M5atom!"); // 温度データ取得 float temperature = thermocouple.readCelsius() - 14; //測定値-14℃, 適宜変更 float int_temperature = thermocouple.readInternal(); //温度取得に失敗したら再起動 if (isnan(temperature)) { ESP.restart(); } //LED制御 if (temperature < -65) { M5.dis.drawpix(0, 0x00ff00); // green } else { M5.dis.drawpix(0, 0xff0000); // red } // ステーションモードに設定 WiFi.mode(WIFI_STA); // IPアドレス設定 // WiFi.config(ip, gateway, subnet); // 接続開始(繋がるまで40回繰り返す) int lpcnt = 0 ; WiFi.disconnect(true, true); delay(500); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) {

-

M5.dis.drawpix(0, 0x00ff00); // green

+

M5.dis.drawpix(0, 800080); // purple

delay(2 * 1000); M5.dis.clear(); //LED消灯 delay(3 * 1000); lpcnt += 1 ; if (lpcnt > 40) { ESP.restart(); } } // センサーデータアップロード開始 ThingSpeak.begin(client); M5.dis.drawpix(0, 0x0000ff); // blue // フィードに値を設定 ThingSpeak.setField(1, temperature); ThingSpeak.setField(2, int_temperature); // ThingSpeakに送信 //Serial.println(); //Serial.print("Write fields..."); int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); // Check the return code if (x == 200) { //Serial.println("done"); M5.dis.clear(); //LED消灯 delay(1000); //これ入れないとLED消えないでdeepsleepする // 2.5 min のディープスリープタイマー設定(usec) esp_sleep_enable_timer_wakeup(150 * 1000 * 1000); // GPIO39(M5atomのHOMEボタン)がLOWになったらディープスリープから復帰 pinMode(GPIO_NUM_39, INPUT_PULLUP); esp_sleep_enable_ext0_wakeup(GPIO_NUM_39, LOW); // ディープスリープ esp_deep_sleep_start(); } else { ESP.restart(); } } void loop () { } ``` # 確認 - ここまでできたら、ThingSpeakのMyChannelのウェブページを開くと熱電対で読み取った温度データが見れるはずです。 # 設置 - 裸の熱電対をそのまま超低温冷凍庫に入れると、霜がついて正確な温度計測ができないので下図のように1.5mLチューブの蓋に穴を開けて熱電対を差し込んだものを超低温冷凍庫に設置します。 ![キャプションを入力できます](https://camo.elchika.com/e693ba7ff6ae6e701a850152441cce96529bb29b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f63366532663362382d386262652d346334362d393162392d616539623365333666393735/) - 設置方法は、フリーザー購入時であれば取り込み口から、すでに稼働中であれば扉の隙間から奥に差し込みます。 - 冷凍庫の表示温度と値がずれている場合には `float temperature = thermocouple.readCelsius() - 14` の補正値の値を変更してプログラムを再度書き込みます。 # LINE Notifyの設定 異常検知や定時連絡をLINEで受け取るための[LINE Notify](https://notify-bot.line.me/ja/)の設定をします。 やるべきことは、LINE Notifyアカウントと友達になって、アクセストークンを発行することです。 [LINE Notifyの初め方](https://zenn.dev/protoout/articles/18-line-notify-setup)等を参照してやってみてください。 (注)このアクセストークンは二度と表示されないので、必ずメモしてください。再発行するとトークン番号が変わります。 # ThingSpeakでのイベントトリガーとThingHTTPの設定 ## 温度が閾値を超えたときの設定(ThingHTTP) - ThingSpeakページ上部の「Apps」プルダウンから「ThingHTTP」を選びます。 - 緑色の「New ThingHTTP」ボタンを押します。 Name: 適当な名前を入れます URL: https://notify-api.line.me/api/notify Method: POST Content Type: application/x-www-form-urlencoded HTTP Version: 1.1 Headers (Name: Authorization Headers (Value: Bearer your_LINE Notify_token (Bearer[半角スペース]先ほど発行されたLINE Notifyのアクセストークン)

-

Body: message=に続きここに書いた内容がそのままLINE Notifyに通知されます。%%で挟まれた部分は置き換えキーでメッセージ送信時の[データを引数](https://jp.mathworks.com/help/thingspeak/thinghttp-app.html#bu6qune_sep_bvtzy2y-5)にできます。

+

Body: message=に続きここに書いた内容がそのままLINE Notifyに通知されます。%%で挟まれた部分は置き換えキーでメッセージ送信時の[データを引数](https://jp.mathworks.com/help/thingspeak/thinghttp-app.html#bu6qune_sep_bvtzy2y-5)にできます。日本語でもOK。

![キャプションを入力できます](https://camo.elchika.com/174e89811cdcbdf3874e3c37bf2720a735869edf/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f33636232383865322d336138652d343033332d393034312d396361393536356661636138/) - 入力が終わったら、「Save ThingHTTP」ボタンを押して保存します。 ## 温度が閾値を超えたときの設定(React) - ThingSpeakページ上部の「Apps」プルダウンから「React」を選びます。 - 緑色の「New React」ボタンを押します。 React Name: 適当な名前を入れます Condition Type: Numeric Test Frequency: On Data Insertion Condition (If channel: 温度検知したいChannelを選びます Condition (field: 温度検知したいfield番号を選びます Condition (field: is greater than Condition (field: これ以上で知らせて欲しい温度(私は-65℃にしています) Action: ThingHTTP   then perform ThingHTTP: 先ほど作成したThingHTTPを指定します。 Options: Run action only the first time the condition is met(上記設定した閾値を超えたら1回だけ通知がきます) ![キャプションを入力できます](https://camo.elchika.com/8ad33ef385dce688973f0bbd130f2ef1d9f7b9f8/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f65666432633837652d303462612d343131632d613936312d343937366439313862333663/) - 入力が終わったら、「Save React」ボタンを押して保存します。 - ここまでで、温度異常時の通知設定は終了です。 ## 定時連絡設定(ThingHTTP) - ThingSpeakページ上部の「Apps」プルダウンから「ThingHTTP」を選びます。 - 緑色の「New ThingHTTP」ボタンを押します。 - 「Body」部分以外は温度異常時の設定と変わりません。 Body: 定時連絡用のメッセージを記入します。 ![例](https://camo.elchika.com/e81c0374b03932f855b9fef6a69d3600c2ff57de/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f36373731383039632d646337612d343064322d613237302d346637616334333437326264/) ## 定時連絡設定(TimeControl) - ThingSpeakページ上部の「Apps」プルダウンから「TimeControl」を選びます。 - 緑色の「New TimeControl」ボタンを押します。 Name: 適当な名前を入れます Frequency: Recurring Recurrence: Day Time: 好みの時刻(例えば、10:00 pm) Action: ThingHTTP   then perform ThingHTTP: 先ほど作成したThingHTTPを指定します。 - 入力が終わったら、「Save TimeControl」ボタンを押して保存します。 - ここまでで、定時連絡の通知設定は終了です。 ## ThingSpeakへのデータ不達時の通知設定(ThingHTTP) - ThingSpeakページ上部の「Apps」プルダウンから「ThingHTTP」を選びます。 - 緑色の「New ThingHTTP」ボタンを押します。 - 「Body」部分以外は温度異常時の設定と変わりません。 Body: データ不達連絡用のメッセージを記入します。 ## ThingSpeakへのデータ不達時の通知設定(React) - ThingSpeakページ上部の「Apps」プルダウンから「React」を選びます。 - 緑色の「New React」ボタンを押します。 React Name: 適当な名前を入れます Condition Type: No Data Check Test Frequency: Every 10 minutes(好みでどうぞ) Condition (If channel: データ不達検知したいChannelを選びます Condition (has not been updated for: 15min(データ不達時間, 好みでどうぞ) Action: ThingHTTP   then perform ThingHTTP: 先ほど作成したThingHTTPを指定します。 Options: Run action only the first time the condition is met ## LINE Notifyに通知が来るかの確認 - ThingSpeakページ上部の「Apps」プルダウンから「ThingHTTP」を選びます。 - 通知テストをしたいThingHTTPの「View」ボタンを押します。 - 右上部に四角で囲まれたGETから始まるhttps://....(下図)がありますので、GETを**含めず**「https:」以下をコピーしてブラウザで開くと設定した通知が送られて、ブラウザには「{"status":200,"message":"ok"}」と表示されるはずです。 ![キャプションを入力できます](https://camo.elchika.com/4341636922609355904c99797c502c0844b27968/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f61303536346236612d613131362d346238372d383066612d383564333364363264333933/) # 実際に使ってみて コロナ禍が始まりラボに頻繁に行けなくなった時期の2020年4月からシステムの稼働を始めました、2024年1月に超低温冷凍庫が故障し、アラーム発報のおかげで中身を迅速に移し替えることができました。現在は、新しい超低温冷凍庫で順調に稼働しています。 # 追記 この記事を書きながらM5Stack社のページを閲覧してたら、MAX31855モジュールに熱電対のソケットが付いたUnitを見つけました。M5Stack社の製品は開発の回転が早く当該ユニットがEOPになる可能性もありますが、煩わしいはんだ付けが必要ないので需要はあると思いESP32マイコンも最新のAtomS3 Liteに変更したバージョンを以下に記します。(変更が必要な部分のみ追記しました) # (追記版)使用したモジュール - [AtomS3 lite (M5STACK-C124)](https://www.switch-science.com/products/8778) - [Unit-KmeterISO (M5STACK-U133-V11)](https://www.switch-science.com/products/9007) - [K型熱電対プローブ](https://akizukidenshi.com/catalog/g/g100306/)

-

- [Amazon](https://www.amazon.co.jp/gp/product/B0BRFPH1C1/)などでも購入できます

+

- Unit-KmeterISO付属の緑色被覆の熱電対(メーカースペック, -50℃~250℃)でも測れます。 - [Amazon](https://www.amazon.co.jp/gp/product/B0BRFPH1C1/)などでも購入できます

# (追記版)開発環境 Arduino IDE v2.3.2 - 追加のボード: - M5Stack -> M5AtomS3 https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json --- - 追加ライブラリ: - M5AtomS3ライブラリ https://github.com/m5stack/M5AtomS3 - M5Unit-KMeterISOライブラリ https://github.com/m5stack/M5Unit-KMeterISO - ThingSpeakライブラリ https://github.com/mathworks/thingspeak-arduino # (追記版)結線 - Unit-KmeterISOに付属のGroveケーブル(黒赤黄白のケーブル)でAtomS3 LiteのGroveポートとUnit-KmeterISOのGroveポートを接続します。(ノッチがあるので挿し間違いは無いです) - Unit-KmeterISOの熱電対ソケットに熱電対を挿し込みます。(+が細くて-が太いです) ![キャプションを入力できます](https://camo.elchika.com/94a7df505aabb484a69af823ce4f6d6bc4a74250/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35386366623661372d613337392d343635322d383130622d6464656637363663303337632f32626638623535652d626534652d343461362d623765622d653637326662353136383331/) # (追記版)プログラム - 下記、AtomS3_KmeterISO_ThingSpeak.inoの WiFi設定部分 `const char ssid[] = "your_SSID";` `const char pass[] = "your_password";` と ThingSpeak設定部分 `const unsigned long myChannelNumber = your_Ch_##;` `const char * myWriteAPIKey = "your_API_Key";` を各自の環境に書き換えてAtomS3 Liteに書き込みます。 ```arduino:AtomS3_KmeterISO_ThingSpeak.ino #include <M5AtomS3.h> #include <ThingSpeak.h> #include "WiFi.h"

-

#include "M5UnitKmeterISO.h"

+

#include <M5UnitKmeterISO.h>

-

// 起床間隔 // const unsigned long WAKEUP_INTERVAL = 3 * 60 * 1000 * 1000; // 3分

// Wifi設定(Wifi環境に合わせて変更) const char ssid[] = "your_SSID"; const char pass[] = "your_password";

-

// ネットワーク設定(ネットワーク環境に合わせて変更)

+

// ネットワーク設定(固定IP用, ネットワーク環境に合わせて変更)

// IPAddress ip(192, 168, 100, 100); // IPAddress gateway(192, 168, 100, 1); // IPAddress subnet(255, 255, 255, 0); // ThingSpeak設定(チャンネルIDと書き込み用APIキーを変更) const unsigned long myChannelNumber = your_Ch_##; const char* myWriteAPIKey = "your_API_Key"; // ThingSpeak接続用 WiFiClient client; //KmeterISOユニットと通信 M5UnitKmeterISO kmeter; void setup() { AtomS3.begin(true); // Init M5AtomS3Lite. AtomS3.dis.setBrightness(50); // Serial.begin(115200);

+

//Unit KmeterISOの接続確認

while (!kmeter.begin(&Wire, KMETER_DEFAULT_ADDR, 2, 1, 100000L)) { //Serial.println("Unit KmeterISO not found"); AtomS3.dis.drawpix(0XFFFFFF); // white AtomS3.update(); } AtomS3.dis.clear(); //LED消灯 // 温度データ取得 float temperature = (kmeter.getCelsiusTempValue() / 100) - 12; //測定値-12℃, 適宜変更 float int_temperature = kmeter.getInternalCelsiusTempValue() / 100; //温度取得に失敗したら再起動 if (isnan(temperature)) { ESP.restart(); }

-

//LED制御

+

//LED(-65C以上なら赤, 以下なら緑)

if (temperature < -65) { AtomS3.dis.drawpix(0x00ff00); // green AtomS3.update(); } else { AtomS3.dis.drawpix(0xff0000); // red AtomS3.update(); } // ステーションモードに設定 WiFi.mode(WIFI_STA);

-

// IPアドレス設定

+

// IPアドレス設定(固定IP用)

// WiFi.config(ip, gateway, subnet);

-

// 接続開始

+

// WiFi接続開始

int lpcnt = 0; WiFi.disconnect(true, true); delay(500); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) {

-

AtomS3.dis.drawpix(0x00ff00); // green

+

AtomS3.dis.drawpix(800080); // purple

delay(2 * 1000); AtomS3.update(); AtomS3.dis.clear(); //LED消灯 delay(3 * 1000); lpcnt += 1; if (lpcnt > 40) { ESP.restart(); } } // センサーデータアップロード開始 ThingSpeak.begin(client); AtomS3.dis.drawpix(0x0000ff); // blue AtomS3.update();

-

// フィードに値を設定

+

// フィードに値を設定

ThingSpeak.setField(1, temperature); ThingSpeak.setField(2, int_temperature); // ThingSpeakに送信 //Serial.println(); //Serial.print("Write fields..."); int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); // Check the return code if (x == 200) { //Serial.println("done"); AtomS3.dis.clear(); //LED消灯 AtomS3.update(); //これ入れないとLED消えないでdeepsleepする // 2.5 min のディープスリープタイマー設定(usec) esp_sleep_enable_timer_wakeup(150 * 1000 * 1000); // ディープスリープ esp_deep_sleep_start(); } else { ESP.restart(); } } void loop() { } ``` - 冷凍庫の表示温度と値がずれている場合には `float temperature = (kmeter.getCelsiusTempValue() / 100) - 12` の補正値の値を変更してプログラムを再度書き込みます。