🌾
SDI-12センサの安価な測定システムの作り方 #3(Wi-Fi接続編)
この記事のゴール
- マイコン(M5Stack ATOM)のインターネットへの接続
前提
- この記事をご覧になるのは研究者の方を想定していますので,コードに関しては比較的丁寧に記載いたします
- この記事はSDI-12センサの内,Acclima社製のTDTセンサを使用する例を記載しています
- この記事は筆者のHPから移植している部分が多いため,最新でない情報も含まれています
- Mac環境の例を記載していますので,Windowsの方は必要に応じて読み替えをお願いします
- 前回の記事を先にご覧になることを推奨します
必要な知識・もの
- Arduino言語の基本的な知識
- PC
必要な物品リスト
- SDI-12センサ(TDTセンサ) × 1
- ブレッドボード × 1
- 端子台(3極) × 1
- ジャンパワイヤ × 10本程度
- ATOM Lite × 1 (* その他のM5Stack系のマイコンでも動作可能ですが,適宜配線を変更する必要があります)
- USB type-c ケーブル × 1
- microSDカードスロットDIP化キット
- microSDカード × 1
以下前回からの追加
- 追加なし
ライブラリのインストール
- 今回は前回に加えて
WiFi.h
のライブラリを使用します- おそらくデフォルトでインストールされていると思います
配線
- 配線は前回の同じため,割愛します
Wi-Fi接続の流れ
- コード全体が長くなりましたので,前回からの差分を紹介します
- アクセスポイントのSSIDを設定(*1)
- アクセスポイントのパスワードを設定(*2)
- アクセスポイントに接続(*3)
- 接続に失敗した場合,再起動(*4)
- 処理中にWi-Fiの接続が切れた場合に再接続(*5)
// 前略
#include "WiFi.h"
// 中略
// Wi-Fiの設定
const char *ssid = "sample-access-point"; // *1
const char *pass = "sample-pass"; // *2
// 中略
void setup()
{
// 中略
const bool wifiStatus = connectToAccessPoint(ssid, pass); // *3
if (!wifiStatus)
{
// 5秒待機して再起動
delay(5000);
ESP.restart(); // *4
}
}
void loop()
{
// 再接続処理
handleWiFiReconnection(); // *5
// 後略
}
* @brief アクセスポイントに接続
*
* @param ssid 接続先SSID
* @param password 接続先PASS
* @return true: 成功, false: 失敗
*/
bool connectToAccessPoint(const char *ssid, const char *password)
{
WiFi.begin(ssid, password);
int waitCountInSec = 0;
while (WiFi.status() != WL_CONNECTED)
{
waitCountInSec++;
delay(1000);
Serial.print(".");
// 10秒待って接続できなかった場合失敗とする
if (waitCountInSec == 10)
{
Serial.println("Wi-Fi の接続に失敗しました。");
return false;
}
}
Serial.println("WiFi に接続しました。");
return true;
}
/**
* @brief アクセスポイントへの接続状況に応じて再接続する
*/
void handleWiFiReconnection()
{
// 接続状態でない場合
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("接続状態が解除されました。");
// 再接続を試みる
const bool wifiStatus = connectToAccessPoint(ssid, pass);
if (!wifiStatus)
{
// 5秒待機して再起動
delay(5000);
ESP.restart();
}
}
}
コード全体
#include <SDI12.h>
#include "SD.h"
#include "SPI.h"
#include "WiFi.h"
#define DATA_PIN 33
#define SD_PIN 23
#define SD_MISO_PIN 21
#define SD_MOSI_PIN 25
#define SD_CLK 19
// Wi-Fiの設定
const char *ssid = "sample-access-point";
const char *pass = "sample-pass";
// SDI-12の設定
SDI12 mySDI12(DATA_PIN);
String responseArray[10];
const String sensorAddress = "1";
String measureCommand = sensorAddress + "M!";
String resultCommand = sensorAddress + "D0!";
// CSVの設定
const char *path = "/result.csv";
void setup()
{
Serial.begin(115200);
mySDI12.begin();
if (!SD.begin(SD_PIN))
{
Serial.println("SDカードのが読み取れません");
while (1)
{
}
}
File file = SD.open(path);
if (!file)
{
SD.open(path, FILE_APPEND);
}
file.close();
const bool wifiStatus = connectToAccessPoint(ssid, pass);
if (!wifiStatus)
{
// 5秒待機して再起動
delay(5000);
ESP.restart();
}
}
void loop()
{
// 再接続処理
handleWiFiReconnection();
// 測定コマンド送信
const String response = sendCommandCollectResponse(measureCommand); // 例)100104
// 測定時間を取得
int waitTime = response.substring(3, 4).toInt() * 1000;
// 測定待機
delay(waitTime);
// 測定結果取得コマンド送信
const String result = sendCommandCollectResponse(resultCommand); // 例)1+20.27+15.2+10.67+0.41
Serial.println(result);
// +区切りの文字列をカンマ区切りに置換
String record = replace(result) + "\n"; // 改行コードを追加
// ファイルに書き込み
writeFile(path, record);
// 5秒間隔測定
delay(5000);
}
/**
* @brief コマンド送信とレスポンスの取得
*
* @param command コマンド文字列
* @return String レスポンス
*/
String sendCommandCollectResponse(String command)
{
String response = "";
mySDI12.sendCommand(command);
while (mySDI12.available())
{
char responseChar = mySDI12.read();
if ((responseChar != '\n') && (responseChar != '\r'))
{
response += responseChar;
delay(10);
}
}
mySDI12.clearBuffer();
return response;
}
/**
* @brief SDカードに書き込む
*
* @param path ファイルパス
* @param message 書き込む内容
*/
void writeFile(const char *path, String message)
{
File file = SD.open(path, FILE_WRITE);
if (!file)
{
return;
}
file.print(message);
file.close();
}
/**
* @brief +区切りの文字列をカンマ区切りに置換
*
* @param data +区切りの文字列
* @return String 置換後の文字列
*/
String replace(String data)
{
int index = 0;
int arraySize = (sizeof(data) / sizeof((data)[0]));
int dataLength = data.length();
String resultString = "";
for (int i = 0; i < dataLength; i++)
{
char dataChar = data.charAt(i);
if (dataChar == '+')
{
resultString += ",";
index++;
}
else
{
resultString += dataChar;
index++;
}
}
return resultString;
}
/**
* @brief アクセスポイントに接続
*
* @param ssid 接続先SSID
* @param password 接続先PASS
* @return true: 成功, false: 失敗
*/
bool connectToAccessPoint(const char *ssid, const char *password)
{
WiFi.begin(ssid, password);
int waitCountInSec = 0;
while (WiFi.status() != WL_CONNECTED)
{
waitCountInSec++;
delay(1000);
Serial.print(".");
// 10秒待って接続できなかった場合失敗とする
if (waitCountInSec == 10)
{
Serial.println("Wi-Fi の接続に失敗しました。");
return false;
}
}
Serial.println("WiFi に接続しました。");
return true;
}
/**
* @brief アクセスポイントへの接続状況に応じて再接続する
*/
void handleWiFiReconnection()
{
// 接続状態でない場合
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("接続状態が解除されました。");
// 再接続を試みる
const bool wifiStatus = connectToAccessPoint(ssid, pass);
if (!wifiStatus)
{
// 5秒待機して再起動
delay(5000);
ESP.restart();
}
}
}
おわりに
- 上記のコードでマイコンをWi-Fiアクセスポイントに接続することができます
- loop処理中にWiFi接続が切れた場合に再接続する処理を入れています
- 今回はWi-Fiに接続するまでをご紹介しました
- 次回はマイコンからインターネットを通じて飛んできた測定データを保存するシステム構築の前段として,構築するシステムの設計についてご紹介したいと思います
Discussion