UnifiedWater v1 - 完全なArduino水質センサーキット
必要なパーツと用品
| パーツ | 数量 | 備考 |
|---|---|---|
| Arduino MKR GSM 1400 | 1 | |
| Adafruit NeoPixel Ring: WS2812 5050 RGB LED | 1 | |
| GY21 温湿度センサー | 1 | |
| 濁度センサー (フォトトランジスタ出力) | 1 | |
| Adafruit 防水 DS18B20 デジタル温度センサー | 1 | |
| DFRobot Gravity: アナログ先端型pHセンサー/メーターキット | 1 | |
| SparkFun プッシュボタンスイッチ 12mm | 1 | |
| ジャンパーワイヤー (汎用) | 1 | |
| 抵抗 220Ω | 1 |
必要な工具と機械
- ハンダゴテ (汎用)
使用するアプリとオンラインサービス
- Arduino Web Editor
- SORACOM Air IoT Connectivity Platform
- SORACOM Harvest
- SORACOM Lagoon
プロジェクト概要
概要
河川は私たちの生存、貿易などに不可欠です。過去10年間で世界の水域汚染を減らすための大きな努力がなされてきました。汚染の源は河川です。人々は海に直接ゴミを捨てるのではなく、河川に捨てます。それらの河川が海や大洋に流れ込み、かつて河川に捨てられた歯ブラシが世界を巡って反対側の海岸に打ち上げられるのです。
汚染と闘う世界において、データは極めて重要です。企業やビジネスがグローバルプロジェクトで協力し、水質汚染を減らすことが容易であるべきです。これがUnifiedWaterの役割です。
河川の汚染度を知るために必要なデータを簡単に収集・分析できる、安価でスケーラブルなデバイス。WaterAidには企業向けと個人向けの2つのモードがあります。
複数のデバイスをストリームの異なる地点や異なる水域に配置し、同時に機能させることができます。これらのデバイスは一定間隔でデータを収集し、同じデータベースに送信。ボタン一つで監視対象の河川や湖の状況を確認できます。
携帯版デバイスも利用可能。個人がデバイスを携帯し、水質サンプルを採取したいときにボタンを押して30秒間水に浸すだけ。データはオンラインダッシュボードで確認できます。
水温、pH、湿度、大気温度、大気湿度を収集することで、WaterAidは河川汚染監視に必要な全センサーを搭載しています。
動画
画像

機能
WaterAidは、ユーザー(企業または個人)がデータを安全かつ正確に収集し、Soracomのクラウドですべてのデータを一箇所で可視化できるようにします。プロジェクトはフロントエンドとバックエンドで構成されます。
フロントエンド
フロントエンドはデータを収集してクラウドに送信する物理デバイスです。デバイスはモード1またはモード2に設定可能。モード1ではボタン押下で1セットのデータを記録(水域の定期的でない監視に有用)。モード2では定義された時間間隔で測定値を取得し、クラウドにプッシュします。
MKR GSMをフロントエンドに採用したのは、使いやすく信頼性が高く、GSM経由でSoracomにアクセスできるためです。デバイスがデータ収集時に実行する手順は以下の通り。


バッテリー
デバイスは複数の方法で給電可能。デバイス搭載のポートからLiPoバッテリー、モバイルバッテリー、またはVINポートから電池接続で給電できます。デバイスの稼働時間はバッテリー容量に大きく依存。測定間隔ではスリープモードに入って可能な限りエネルギーを節約します。
LEDリング
デバイスにはLEDリングも搭載され、現在の動作状態をユーザーにフィードバックします。リングには3つのモードがあります。
- 多色点灯: デバイスがセットアップ中またはデータ処理中
- 赤色点滅: 警告 - 通常はデバイスを水に入れる必要があることを示す(エラーの可能性も)
- 青または緑の進行: 現在サンプリング中 - 水に入れたままにする

サンプリング
デバイスの全センサーを水に浸してサンプリングします。センサーのウォームアップのため6秒の遅延後にサンプリング開始。ウォームアップ中もセンサーを水中に置くのがベストです。

データ処理
データはJSON文字列としてSoracomに送信されます。これによりすべてのキーに値が割り当てられ、バックエンドでの解釈が容易になります。ペイロード例:
{
"Latitude": 53.3474617,
"Longitude": -6.2514529,
"waterpH": 7.30,
"waterTurbidity": 94,
"waterTemp": 12.10,
"atmoTemp": 14.50,
"atmoHum": 82,
"deviceID": 1,
"deviceName": "device1",
"epoch": 1559392636,
"mode": 2
}
バックエンド
バックエンドはSoracomを指します。データはダッシュボードで収集・可視化。ダッシュボードはSoracom Lagoonで作成。

ダッシュボード
ダッシュボードはデバイスから収集したすべてのデータを集約。データ採取地点を地図上にプロットし、色で汚染度を表示。データは折れ線グラフとテーブルで表示されます。pHや濁度の値が異常な場合、メールでアラートを受信できます。

拡張性
デバイスは容易にスケール可能で、すべてのデータを同じダッシュボードで収集・可視化できます。複数デバイスがSoracomにデータをストリーミングし、ダッシュボードで可視化。デバイスの価格と構築・プログラミングの容易さにより、デバイス艦隊の運用が現実的です。Soracom Kryptonのようなツールで簡単にデバイス登録も可能。
各企業や個人がパーソナライズされたダッシュボードを持ち、自分のデバイスが収集したデータを可視化。将来的には人々が同じダッシュボードで協力し、データを共有できるようになることを期待しています。
メリット
- デバイスが非常に自立的であるため、運用コスト削減
- 容易にスケール可能 - 単独でも、数十台の艦隊でも動作
- 高速データ収集 - クラウドにプッシュしリアルタイム可視化
- 簡単な可視化 - オンラインダッシュボードでいつでもどこでもデータ確認
プロジェクトの構築
ステップ1: 必要な機器
水と大気に関連する多くのパラメータを監視するため、多くのセンサーが必要です。必要な材料リスト:
- Arduino MKR GSM
- 16個RGB LEDリング
- GY-21 温湿度モジュール
- 濁度センサー
- 防水温度センサー
- pHセンサーとモジュール
- プッシュボタン
- 抵抗 (220Ω)
- ジャンパーワイヤー

ステップ2: 回路接続
コンポーネントをハンダ付けで接続。理解しやすいようブレッドボードで配線図を示します。回路図は以下の通り。

MKR GSMの準備
センサーをハンダ付け後、SIMカード、GSMアンテナ、バッテリーをデバイスに取り付けます。ここではVINポートから単3電池2本で給電。手順は以下の通り。

ステップ3: コードの理解
プロジェクトのコードには4つの主要セクションがあります。
- センサーデータ収集
- 時刻と日付の取得
- データ処理
- データ送信
センサーデータ収集
Serial.println("Taking Sample");
Serial.println("________________________________________");
Serial.println("Taking Sample");
Serial.println(" OK - Warming Up");
delay(6000); // センサーキャリブレーション用遅延
colourLED(50);
Serial.println(" OK - Taking Sample");
Serial.print(" ");
for (int i = 0; i < 16; i++) {
if (mode == 1) {
strip.setPixelColor(i, strip.Color(0, 255, 0));
strip.show();
} else {
strip.setPixelColor(i, strip.Color(0, 0, 255));
strip.show();
}
// 複数回水質サンプルを取得 - センサーがそれほど精密でないため
waterTurbidity += getWaterTurbidity();
waterPh += getWaterPh();
if (i > 14) {
// 高精度センサーは1回だけサンプリング
waterTemperature = getWaterTemp();
atmoTemperature = getAtmoTemp();
atmoHumidity = getAtmoHumidity();
}
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println(" Success - Samples Taken");
for (int i = 0; i <= 16; i++) {
strip.setPixelColor(i, strip.Color(0, 0, 0));
strip.show();
delay(30);
}
Serial.println("________________________________________");
Serial.println("");
delay(500);
上記コードはまず6秒間センサーの水中キャリブレーションを待機。その後16回ループし、毎回LEDリングの新しいLEDが点灯。変動しやすいセンサーのデータを16回収集して平均を算出。高精度センサーは最終ループで1回だけ読み取ります。
時刻と日付の取得
void getCredentials() {
Serial.println(" [1/2] Time");
Serial.println(" OK - Getting Time from RTC");
currentEpoch = processTime();
colourLED(50);
Serial.println(" [2/2] Geolocation");
Serial.println(" OK - Getting Geolocation from GPRS");
while (!getLocation());
Serial.print(" Success - Geolocation is "); Serial.print(latitude, 7); Serial.print(", "); Serial.println(longitude, 7);
colourLED(50);
}
bool getLocation() {
if (location.available()) {
latitude = location.latitude();
longitude = location.longitude();
delay(500);
return true;
} else {
delay(500);
return false;
}
}
最初のループで認証情報を処理。時刻はオンボードRTCから取得(セットアップ時にGSMネットワークと同期済み)。位置情報はGPRSから取得。
データ処理
void processData() {
Serial.println(" OK - Getting Mean of Water pH and Turbidity");
waterPh = (waterPh / 16);
waterTurbidity = (waterTurbidity / 16);
Serial.println(" OK - Dumping Data to Serial");
Serial.println("");
Serial.print(" [Water] pH "); Serial.println(waterPh);
Serial.print(" [Water] Turbidity "); Serial.println(waterTurbidity);
Serial.print(" [Water] Temperature "); Serial.println(waterTemperature);
Serial.print(" [Atmo] Temperature "); Serial.println(atmoTemperature);
Serial.print(" [Atmo] Humidity "); Serial.println(atmoHumidity);
Serial.println("");
Serial.println(" Success - Data Processed");
colourLED(50);
}
String makeLine() {
Serial.println(" OK - Making String");
String dataReturned; dataReturned += "{"; dataReturned += " \n";
dataReturned += "\"Latitude\":" + String(latitude, 7); dataReturned += ", \n";
dataReturned += "\"Longitude\":" + String(longitude, 7); dataReturned += ", \n";
dataReturned += "\"waterpH\":" + String(waterPh); dataReturned += ", \n";
dataReturned += "\"waterTurbidity\":" + String(waterTurbidity); dataReturned += ", \n";
dataReturned += "\"waterTemp\":" + String(waterTemperature); dataReturned += ", \n";
dataReturned += "\"atmoTemp\":" + String(atmoTemperature); dataReturned += ", \n";
dataReturned += "\"atmoHum\":" + String(atmoHumidity); dataReturned += ", \n";
dataReturned += "\"deviceID\":" + String(deviceID); dataReturned += ", \n";
dataReturned += "\"deviceName\":\""; dataReturned += String("\""); dataReturned += String(deviceName); dataReturned += String("\""); dataReturned += ", \n";
dataReturned += "\"epoch\":" + String(currentEpoch); dataReturned += ", \n";
dataReturned += "\"mode\":" + String(mode); dataReturned += " \n";
dataReturned += "}";
Serial.println(" OK - Data is below");
Serial.println("");
Serial.println(dataReturned);
Serial.println("");
Serial.println(" Success - String is Ready");
colourLED(50);
return dataReturned;
}
processData() は変動しやすいセンサーのデータ平均を算出し、全データをシリアルモニタに出力。makeLine() は全データをSoracom送信用のJSON文字列にまとめます。すべての値がJSONバッファにパースされ、バックエンドへ送信準備完了。
データ送信
void parseData(String dataToSend) {
Serial.println(" OK - Setting Up Connection");
if(client.connect(url, 80)) {
Serial.println(" OK - Connection Established, Parsing Data");
client.println("POST / HTTP/1.1");
client.println("Host: harvest.soracom.io");
client.println("User-Agent: Arduino/1.0");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(dataToSend.length());
client.println("");
client.println(dataToSend);
Serial.println(" OK - Data Parsed");
}
Serial.println(" OK - Getting Responce");
Serial.println("");
while(1) {
if(client.available()) {
char c = client.read();
Serial.print(c);
}
if(!client.connected()) {
break;
}
}
Serial.println(" Success - Data is Parsed");
}
最後にデータをSoracomに送信。デバイスがサーバーとの接続を確立し、認証情報を準備。データを送信し、レスポンスをシリアルモニタに出力。その後、トリガーで起床するまでスリープし、手順を繰り返します。
ステップ4: 変数の設定
プロジェクト使用前に編集が必要な変数:
mode: デバイスモード。1=ボタン操作でサンプリング、2=定期的な自動サンプリングdeviceID と deviceName: 複数デバイス使用時の識別用。各デバイスにユニークなIDと名前を割り当てsleepTime: 測定間隔のスリープ時間。コードではテスト用に5秒だが、実運用では15分間隔などに変更proDebug: デバッグ用。falseがデフォルト。trueにするとシリアルモニタが接続されていないと動作しない
ステップ5: コードのアップロード
バックエンドセットアップ前にデータを送信する必要があります。MKR GSMをPCに接続してコードをアップロード。モードを1に設定。アップロード後、全センサーを水に浸し、デバイスのボタンを押してデータ収集・送信を実行。これを数回繰り返してSoracom Airにデータを蓄積。
ステップ6: Soracomのセットアップ
2セクションに分かれます。1つ目はSoracomアカウント作成とSIM登録、2つ目はSoracom Harvestでのデータ収集設定。既にアカウントがある場合は1つ目をスキップ。
セクション1: アカウント作成

セクション2: グループとHarvest

ステップ7: Lagoonのセットアップ
Soracomで最後に設定するのがLagoon。データ可視化と、データ異常時のメールアラート作成に使用。以下の手順に従ってください。

キャリブレーションの問題
濁度センサーとpHセンサーは正確な使用のためにキャリブレーションが必要です。コード実行時に濁度が105%になったり、水のpHが3になったりする場合はキャリブレーションが必要です。簡易ガイド:
- pHセンサー: モジュール上のポテンショメーターで調整。プローブをpH7の静止したボトル水に入れ5分待機。センサーからのpHをシリアルモニタに出力するコードを作成し、ポテンショメーターを調整してpH7に合わせる。
- 濁度センサー: 精度が高くないため、純水との相対比較でパーセンテージを算出。読み取り値が100%を超える場合、濁度センサーを純水に入れ、pHセンサーのアナログピン電圧をシリアルモニタに出力するコードを作成。
sensors.hのcalibration変数を、プローブを純水に入れたときの電圧値に変更。
使用ライブラリ
- ArduinoLowPower (c) 2016 Arduino LLC - GNU LGPL
- Adafruit_Neopixel (c) Phil Burges - GNU LGPL
- MKRGSM (c) 2016 Arduino AG - GNU LGPL
- Wire (c) 2006 Nicholas Zambetti - GNU LGPL
- OneWire (c) 2007 Jim Studt - GNU GPL
- DallasTemperature - GNU GPL
- RTCZero (c) 2015 Arduino LLC - GNU LGPL
完成
最終的に、モード1とモード両方でサンプリング可能な携帯型ケースを製作。手順は以下の通り。

最後にモードを適切に設定し、フィールドでデバイスを使用開始。近くの河川や湖をチェックして水質を確認。ダッシュボードで遊んで他のウィジェットも試してみてください。
背景
今日、データは新しい通貨であり、それを簡単かつ効率的に収集することはより良い環境の鍵です。河川や湖の汚染を集団で測定することで、水が汚れつつあることへの意識を高め、行動を促せます。
Soracomコンテストのアイデアを考えていたとき、環境に有益な何かを作りたいと感じました。人々や企業が共同ダッシュボードで世界中の河川や湖の状態を可視化し協力するというアイデアにインスパイアされ、このプロジェクトに取り組みました。
あなたは水質汚染を止めるために何をしますか? 行動は今日取らなければなりません。明日は遅すぎます。

コード
コード
プロジェクトのリポジトリ: https://github.com/Andrei-Florian/UnifiedWater-v1
回路図
schematics_e7TRP6KJKI.fzz
製造プロセス
- Raspberry PiでPIRモーションセンサーとLEDを制御
- Raspberry Piで低コスト土壌水分センサーを構築 - スマート灌漑に活用
- Raspberry PiでDS18B20温度センサーをテスト
- Raspberry Pi、MCP9808、InfluxDB、Grafanaで作る家庭温度モニター
- Sensor Telemetry 2.0.1:Azure IoT Hubによる高度な温度監視
- エモーションセンサー&EEG:リアルタイム感情検知のための低コストハードウェア
- Raspberry Pi 2からAzure Event HubsへAdafruit 10DOF IMUデータを送信(Windows 10 IoT Core)
- 川の健康を見守る:Arduinoベース水質監視システム「MyRiver」
- ESP32で作るIoT環境モニター:温湿度・気圧・CO2をWebダッシュボードで可視化
- モダンジュークボックス:Raspberry Pi & Arduino LEDミュージックプレーヤー
- 酸素(O2)センサーを理解する:役割、配置、故障の兆候