Wi-FiマイコンXIAO ESP32S3のWebサーバ動作
温度センサBMP280ブレイクアウトボード使用
2023.9.11 Coskx Lab
1 はじめに
Wi-FiマイコンXIAO ESP32S3はArduinoIDEでの開発が便利です。
ボードとしてXIAO ESP32S3を選んでおくと,XIAO ESP32S3がWi-Fi接続のWebサーバ動作をするスケッチ例が既に使えるようになっています。
ここでは,温度センサの値を発信するXIAO ESP32S3がWebサーバとして働くようにします。
温度センサはBMP280を使用します。
このWebサーバから温度データをもらうためには,PCなどからWebブラウザでアクセスします。
"マイコンのサーバ"と"PCのWebブラウザ"のふるまい
閲覧するのはスマホやタブレットのWebブラウザでもよい
2 使用環境
- Windows 10 64-bit
- ArduinoIDE 2.2.1
- XIAO ESP32S3
- BMP280 (HW-611 E/P 280)
- WindowsPCもXIAO ESP32S3も同じアクセスポイントでWi-Fi接続可能
- WindowsPCもXIAO ESP32S3も同じLAN内接続
- LAN内でDHCP(Dynamic Host Configuration Protocol)サーバが稼働中
3 準備
3.1 ArduinoIDE
(1)Arduino IDEのメニューバーから[ファイルFile] -> [環境設定(Preferences)]
Additional board manager URLsに
https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
および
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
を設定してOK
(2)ツール[Tools] > ボード[Board] > Boards Manager
検索boxに「ESP」を入力すると複数のボード候補が出てくるので
esp32 by Espressif Systems
をinstall
(3)ツール[Tools] > ボード[Board]でESP32を探すとXIAO ESP32S3が見つかるので,これを選ぶ。
3.2 XIAO ESP32S3
XIAO ESP32S3の説明書を読んでプログラムの転送方法を確認します。
(USBケーブルでつないで書き込むだけでした。)
4 XIAO ESP32S3と温度センサBMP280の配線
温度センサBMP280は温度をデジタル値に変換しているので,そのデータをXIAO ESP32S3が読み出します。
XIAO ESP32S3と温度センサBMP280はI2C接続ですので,電源線,GND線の他はSCLとSDAの2本のみで通信できます。
CSBをVCCにつなぐとBMP280はI2C接続になります。(データシートによれば確実にVCCにつなぐべきとなっています)
SDO(シルク印刷は間違えていてSDDとなっている)をVCCにつなぐとBMP280のI2Cアドレスは77になります。GNDにつなぐとBMP280のI2Cアドレスは76になります。Groveライブラリのデフォルトは77なのでVCCにつないでいます。
なおBMP280ではSDA,SCLをpullupせずに動作しています。
XIAO ESP32S3と温度センサBMP280の配線
ブレッドボードには載せないので,XIAO ESP32S3のピンを上向きに付けています。
XIAO ESP32S3と温度センサBMP280
5 XIAO ESP32S3のスケッチコード(サーバプログラム)
クライアント(例えばPCのwebブラウザ)からのリクエストで,サーバであるXIAO ESP32S3は,温度センサBMP280の値を取得し,クライアントに返します。
送信ではHTTP通信の手順に従います。
setupでは,自分が接続すべきWi-FiアクセスポイントのSSIDとパスワードを設定して,LANの一員になろうと試みます。
成功すると,LAN内のDHCPサーバからIPアドレス(一次的な)をもらいます。
またmDNSプロトコルで,自分のホスト名を有効にします。
LAN内機器についてDNSサーバはホスト名の解決ができないので,WebブラウザはIPアドレスでアクセスしてくるのですが,mDNSのおかげでホスト名+".local"(ブラウザが賢いのでホスト名だけでもOK)としてアクセスすることができます。
ここでは,"http://esp32a.local/"でアクセスできます。IPアドレスはDHCPサーバによりマイコン起動時に自動で割り当てられるので,いつも同じIPアドレスになっているとは限らないため,サーバ名(ホスト名)でアクセス可能になるmDNSの仕組みはありがたいです。
アクセスがあると,温度センサBMP280から,温度と気圧を取得し,標高を計算し,"ホスト名:レスポンス回数","標高","温度","気圧"の文字列をスペース区切りで返すようにしています。
次のコードは,IDEの既存スケッチ例"HelloServer.ino"を元に作ったものです。
ライブラリ"Grove_-_Barometer_Sensor_BMP280"を予め追加しておいてください。
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Seeed_BMP280PP.h>
#define STASSID "REPLACE_WITH_YOUR_SSID"
#define STAPSK "REPLACE_WITH_YOUR_PASSWORD"
const char* ssid = STASSID;
const char* password = STAPSK;
const char* servername = "esp32a";
int count = 0;
WebServer server(80);
const int led = LED_BUILTIN;
int ledonoff = 0;
BMP280PP bmp280;
void handleRoot() {
digitalWrite(led, ledonoff = 1 - ledonoff);
float temperature = bmp280.getTemperature();
float pressure = bmp280.getPressure();
float altitude = bmp280.calcAltitude(pressure);
char chrs[128];
sprintf(chrs, "%s:%d %.1f %.1f %.1f", servername, count++, altitude, temperature, pressure);
String message = String(chrs);
server.send(200, "text/plain", message);
}
void setup(void) {
Serial.begin(115200);
Serial.print("\n\n\n");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Wait for connection
int connectcount = 0;
while (WiFi.status() != WL_CONNECTED) {
if (10 <= connectcount++) ESP.restart();
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin(servername)) {
Serial.println("MDNS responder started");
Serial.print("server name: ");
Serial.println(servername);
}
server.on("/", handleRoot);
server.begin();
Serial.println("HTTP server started");
if (!bmp280.init()) {
Serial.println("Device bmp280 not connected or broken");
} else {
Serial.println("Device bmp280 started");
}
pinMode(led, OUTPUT);
digitalWrite(led, ledonoff); //turn LED on
}
void loop(void) {
server.handleClient();
delay(2);//allow the cpu to switch to other tasks
}
補足
「server.on("/", handleRoot);」は,ブラウザから「http://サーバ名/」というアクセスがあったら,handleRoot()を実行してね,という設定です。
通常,ブラウザには「http://サーバ名」と入力しますが,ブラウザはその後ろに「/」を加えて「http://サーバ名/」のように送信します。
BMP280のオリジナルライブラリでは,BMP280操作のクラス名はBMP280です。
BMP280の初期設定を手直ししたかったので,クラスBMP280の継承クラスBMP280PPを作って,このクラスを使用しています。
#include <Seeed_BMP280PP.h>
BMP280PP bmp280;
の2行が継承クラスBMP280PPを使っているのですが,オリジナルライブラリを使用する場合はこの2行を
#include <Seeed_BMP280.h>
BMP280 bmp280;
のように戻してください。
次の2つのファイルを作りましたがそれらは,Seeed_BMP280.h,Seeed_BMP280.cppと同じフォルダ(Arduino\libraries\Grove_-_Barometer_Sensor_BMP280)内に保存されています。
BMP280PP.h
#include <Seeed_BMP280.h>
class BMP280PP : public BMP280
{
public:
bool init(void);
private:
void writeRegister(uint8_t reg, uint8_t val);
};
BMP280PP.ino
#include "Seeed_BMP280PP.h"
bool BMP280PP::init(void)
{
if (!BMP280::init()) return false;
//changeig Temperature oversampling to index=4
//(oversampling x8)
//100 111 11
writeRegister(BMP280_REG_CONTROL, 0x9F);
//adding, IIR filter coeficient = 8 (index=3)
//000 011 00
writeRegister(BMP280_REG_CONFIG, 0xC);
return true;
}
void BMP280PP::writeRegister(uint8_t reg, uint8_t val)
{
Wire.beginTransmission(BMP280_ADDRESS); // start transmission to device
Wire.write(reg); // send register address
Wire.write(val); // send value to write
Wire.endTransmission(); // end transmission
}
6 PCのWebブラウザからアクセス
プログラムがXIAO ESP32S3に転送された直後に,ArduinoIDEのシリアルモニタには次のように表示されます。
(XIAO ESP32S3をリセットした直後も同じように表示されます。文字化けするときは,115200baudであることを確認してください)
ここでXIAO ESP32S3に割り当てられたIPアドレスは192.168.1.16であり,サーバー名(ホスト名)はesp32aであることがわかります。
Connected to xxxxxxxxxxxxx
IP address: 192.168.1.16
MDNS responder started
server name: esp32a
HTTP server started
Device bmp280 started
まず最初にgoogle chromeからIPアドレスでアクセスしてみました。
正確には"http://192.168.1.16/"のように書きます。
169.9が標高,35.3が気温,98982.0が気圧です。
次にサーバー名でアクセスしてみました。
正確には"http://esp32a.local/"のように書きます。
167.0が標高,35.2が気温,98981.0が気圧です。
ただし,標高は海面気圧が1013.25hPaとして,ライブラリ内で気圧と気温から計算されています。
7 WinPCのExcelから2つのXIAO ESP32S3にアクセス
2つのXIAO ESP32S3(それぞれ温度センサBMP280を持っている)に,同じLAN内にあるWinPCのExcelからアクセスします。
2つのXIAO ESP32S3には,プログラムコード上で
#define SERVERNAME "esp32a"
と
#define SERVERNAME "esp32b"
のように別々のサーバ名(ホスト名)を与え,起動しておきます。
Excelから,mDNSの恩恵で,2つのURLをホスト名を使ってアクセスします。
ExcelでVBAのプログラムを走らせ,Start,Stopボタンで動作を制御します。
なおVBAでブラウザと同じHTTPアクセスをするためには,Microsoft XMLライブラリを使います。
VBAの環境を開いて,メニューから"ツール"→"参照設定"を選ぶと,"参照設定"ダイアログが開くので,ライブラリファイルの中から"Microsoft XML, v6.0"を探して,チェックを入れてOKで組み込まれます。
Microsoft XMLライブラリからXMLHTTP60のオブジェクトを使って,関数requestHTTP内でHTTPアクセスします。
2つのXIAO ESP32S3からは,それぞれ"ホスト名","標高","温度","気圧"がスペース区切りで送られてくるので,それを指定のセルに表示します。
VBAのプログラムは次のようになりました。
Dim hasRequestToStop As Boolean
Sub go()
hasRequestToStop = False
main
End Sub
Sub stopbtn()
hasRequestToStop = True
End Sub
Function requestHTTP(url As String) As String
Dim httpReq As XMLHTTP60
Set httpReq = New XMLHTTP60
Debug.Print httpReq.readyState
httpReq.Open "GET", "http://" & url
httpReq.setRequestHeader "Pragma", "no-cache"
httpReq.setRequestHeader "Cache-Control", "no-cache"
httpReq.setRequestHeader "If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT"
httpReq.Send
Do While httpReq.readyState < 4
DoEvents
Loop
Debug.Print httpReq.responseText
requestHTTP = httpReq.responseText
Set httpReq = Nothing
End Function
Function extractBody(text As String) As String
Dim point As Integer
text = Replace(text, vbCr, "")
text = Replace(text, vbLf, "")
text = StrConv(text, vbLowerCase)
point = InStr(text, "<html>")
If point <> 0 Then text = Right(text, Len(text) - (point + 5))
point = InStr(text, "</html>")
If point <> 0 Then text = Left(text, point - 1)
extractBody = text
End Function
Sub mainwork()
Dim res1 As String
Dim res2 As String
Dim parts() As String
res1 = requestHTTP(Range("A3"))
res2 = requestHTTP(Range("A4"))
res1 = extractBody(res1)
res2 = extractBody(res2)
parts = Split(res1, " ")
If 4 <= UBound(parts) - LBound(parts) + 1 Then
Cells(3, 2).Value = parts(0)
Cells(3, 3).Value = parts(1)
Cells(3, 4).Value = parts(2)
Cells(3, 5).Value = parts(3)
End If
parts = Split(res2, " ")
If 4 <= UBound(parts) - LBound(parts) + 1 Then
Cells(4, 2).Value = parts(0)
Cells(4, 3).Value = parts(1)
Cells(4, 4).Value = parts(2)
Cells(4, 5).Value = parts(3)
End If
End Sub
Sub main()
Do
mainwork
Application.Wait Now + TimeValue("00:00:01")
If hasRequestToStop = True Then
Exit Do
DoEvents
End If
DoEvents
Loop
End Sub
補足
httpReq.setRequestHeader "Pragma", "no-cache"
httpReq.setRequestHeader "Cache-Control", "no-cache"
httpReq.setRequestHeader "If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT"
の3行は,キャッシュに残っているデータは捨てて,必ず新しいデータを受け取るようにしなさいの意味です。
これがないと,キャッシュ内のデータを受け取るだけになってしまい,古いデータが表示されたままになってしまいます。
VBAが動作しているExcelの画面内で次のようにアクセス結果を表示します。
約1秒ごとにアクセスを繰り返します。
センサBMP280の個体差が測定温度と測定気圧に現れています。温度で±0.3度程度,気圧では±100Paの違いが現れます。
8 通信距離
XIAO ESP32S3のWi-Fiでの通信は約70mでした。
9 まとめ
Wi-FiマイコンXIAO ESP32S3をWebサーバとして動作させ,XIAO ESP32S3に接続された温度センサBMP280の値を,クライアントがリクエストしたタイミングでデータを送信するようにしました。
また複数のXIAO ESP32S3サーバからデータを得るためにVBAを使ってExcelに表示する例を示しました。
補足
Excelの画面では見た目が悪いので,Powerpointで作ることもできます。Excelのセルに表示するのではなく,Powerpointの表に表示することなどが考えられます。ただし,表示場所を指示するのが面倒なのと,ExcelVBAとPowerpointVBAに多少違いがあるので,注意が必要です。