Wi-FiマイコンESP-WROOM-02のWebサーバ動作
温度センサADT7410使用
2023.9.11 Coskx Lab
1 はじめに
Wi-FiマイコンESP-WROOM-02はArduinoIDEでの開発が便利です。
ボードとしてGeneric ESP8266 Moduleを選んでおくと,ESP8266がWi-Fi接続のWebサーバ動作をするスケッチ例が既に使えるようになっています。
ここでは,温度センサの値を発信するESP-WROOM-02がWebサーバとして働くようにします。
温度センサはADT7410を使用します。
このWebサーバから温度データをもらうためには,PCなどからWebブラウザでアクセスします。
"マイコンのサーバ"と"PCのWebブラウザ"のふるまい
2 使用環境
- Windows 10 64-bit
- ArduinoIDE 2.2.1
- AE-ESP-WROOM-02-DEV
- ADT7410
- WindowsPCもAE-ESP-WROOM-02-DEVも同じアクセスポイントでWi-Fi接続可能
- WindowsPCもAE-ESP-WROOM-02-DEVも同じLAN内接続
- LAN内でDHCP(Dynamic Host Configuration Protocol)サーバが稼働中
3 準備
3.1 ArduinoIDE
(1)[ファイルFile] -> [環境設定(Preferences)]の追加のボードマネージャに"https://arduino.esp8266.com/stable/package_esp8266com_index.json"を追加し、"OK"をクリックします。
(2)ツール[Tools] > ボード[Board] > Boards Manager
検索boxに「esp8266」を入力すると複数のボード候補が出てくるので
最新版の「esp8266」をinstall
(3)ツール[Tools] > ボード[Board] ボード選択では"Generic ESP8266 Module"を選びます。
3.2 AE-ESP-WROOM-02-DEV
AE-ESP-WROOM-02-DEVの説明書を読んでプログラムの転送方法を確認します。
RSTスイッチとPGMスイッチを両方押した状態から,RSTスイッチを離し,次にPGMスイッチを離すと,プログラム転送(書き込み)モードになります。
4 AE-ESP-WROOM-02-DEVと温度センサADT7410の配線
温度センサADT7410は温度をデジタル値に変換しているので,そのデータをAE-ESP-WROOM-02-DEVが読み出します。
AE-ESP-WROOM-02-DEVと温度センサADT7410はI2C接続ですので,電源線,GND線の他はSCLとSDAの2本のみで通信できます。
I2C 用の端子は,ESP8266 データシート上では SDA:IO2,SCL:IO14 となっていましたが、pins_arduino.h で SDA:IO4,SCL:IO5 として定義されています。
SDA IO4
SCL IO5
なおADT7410ではSDA,SCLをpullupせずに動作しています。
AE-ESP-WROOM-02-DEVと温度センサADT7410の配線
ブレッドボードには載せないので,AE-ESP-WROOM-02-DEVのピンを上向きに付けています。
AE-ESP-WROOM-02-DEVと温度センサADT7410
5 AE-ESP-WROOM-02-DEVのスケッチコード(サーバプログラム)
クライアント(例えばPCのwebブラウザ)からのリクエストで,サーバであるAE-ESP-WROOM-02-DEVは,温度センサADT7410の値を取得し,クライアントに返します。
送信ではHTTP通信の手順に従います。
setupでは,自分が接続すべきWi-FiアクセスポイントのSSIDとパスワードを設定して,LANの一員になろうと試みます。
成功すると,LAN内のDHCPサーバからIPアドレス(一次的な)をもらいます。
またmDNSプロトコルで,自分のホスト名を有効にします。
LAN内機器についてDNSサーバはホスト名の解決ができないので,WebブラウザはIPアドレスでアクセスしてくるのですが,mDNSのおかげでホスト名+".local"(ブラウザが賢いのでホスト名だけでもOK)としてアクセスすることができます。
ここでは,"http://esp8266.local/"でアクセスできます。IPアドレスはDHCPサーバにによりマイコン起動時に自動で割り当てられるので,いつも同じIPアドレスになっているとは限らないため,サーバ名(ホスト名)でアクセス可能になるmDNSの仕組みはありがたいです。
アクセスがあると,温度センサADT7410から,温度を取得し,"ホスト名","レスポンス回数","温度"の文字列をスペース区切りで返すようにしています。
次のコードは,IDEの既存スケッチ例"HelloServer.ino"を元に作ったものです。
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Wire.h>
#define STASSID "REPLACE_WITH_YOUR_SSID"
#define STAPSK "REPLACE_WITH_YOUR_PASSWORD"
#define SERVERNAME "esp8266"
const char* ssid = STASSID;
const char* password = STAPSK;
const char* servername = SERVERNAME;
ESP8266WebServer server(80);
const int led = 16; //AE-ESP-WROOM-02-DEVには実装されていない
const int adt7410I2CAddress = 0x48; //default
int count = 0;
//adt7410から温度を得る
float getTemperature() {
uint16_t uiVal;
float fVal;
int iVal; //符号ありの整数の値を保持
Wire.requestFrom(adt7410I2CAddress, 2); //2バイト要求
uiVal = (uint16_t)Wire.read() << 8;
uiVal |= Wire.read();
uiVal >>= 3;
if(uiVal & 0x1000) { // 13ビットで符号判定
iVal = uiVal - 0x2000; // マイナスの時 (10進数で8192)
}
else {
iVal = uiVal; //プラスの時,そのまま
}
fVal = (float)iVal / 16.0; // 温度換算(摂氏)
return fVal;
}
void handleRoot() {
float temperature = getTemperature();
digitalWrite(led, 1);
//ここがクライアントに返す文字列
char string1[128];
sprintf(string1,"%s %d %.1f\r\n", servername, count++, temperature);
server.send(200, "text/plain", string1);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA); //アクセスポイントに子機として接続 station mode
WiFi.begin(ssid, password);
Wire.begin();
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
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("servername: ");
Serial.println(servername);
}
server.on("/", handleRoot); //通常リクエストのとき
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
MDNS.update();
}
補足
「server.on("/", handleRoot);」は,ブラウザから「http://サーバ名/」というアクセスがあったら,handleRoot()を実行してね,という設定です。
通常,ブラウザには「http://サーバ名」と入力しますが,ブラウザはその後ろに「/」を加えて「http://サーバ名/」のように送信します。
6 PCのWebブラウザからアクセス
プログラムがAE-ESP-WROOM-02-DEVに転送された直後に,ArduinoIDEのシリアルモニタには次のように表示されます。(AE-ESP-WROOM-02-DEVをリセットした直後も同じように表示されます。文字化けするときは,115200baudであることを確認してください)
ここでAE-ESP-WROOM-02-DEVに割り当てられたIPアドレスは192.168.1.16であることがわかります。
Connected to xxxxxxxxxxxxx(アクセスポイントのSSID)
IP address: 192.168.1.16
MDNS responder started
servername: esp8266
HTTP server started
まず最初にgoogle chromeからIPアドレスでアクセスしてみました。
正確には"http://192.168.1.16/"のように書きます。
32.6が気温です。
次にホスト名でアクセスしてみました。
正確には"http://esp8266.local/"のように書きます。
33.6が気温です。
7 WinPCのExcelから2つのAE-ESP-WROOM-02-DEVにアクセス
2つのAE-ESP-WROOM-02-DEV(それぞれ温度センサADT7410を持っている)に,同じLAN内にあるWinPCのExcelからアクセスします。
2つのAE-ESP-WROOM-02-DEVには,プログラムコード上で
#define SERVERNAME "esp8266a"
と
#define SERVERNAME "esp8266b"
のように別々のサーバ名(ホスト名)を与え,起動しておきます。
Excelから,mDNSの恩恵で,2つのURLをホスト名を使ってアクセスします。
ExcelでVBAのプログラムを走らせ,Start,Stopボタンで動作を制御します。
なおVBAでブラウザと同じHTTPアクセスをするためには,Microsoft XMLライブラリを使います。
VBAの環境を開いて,メニューから"ツール"→"参照設定"を選ぶと,"参照設定"ダイアログが開くので,ライブラリファイルの中から"Microsoft XML, v6.0"を探して,チェックを入れてOKで組み込まれます。
Microsoft XMLライブラリからXMLHTTP60のオブジェクトを使って,関数requestHTTP内でHTTPアクセスします。
2つのAE-ESP-WROOM-02-DEVからは,それぞれ"ホスト名","アクセス回数","温度"がスペース区切りで送られてくるので,それを指定のセルに表示します。
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 3 <= UBound(parts) - LBound(parts) + 1 Then
Cells(3, 2).Value = parts(0)
Cells(3, 3).Value = parts(1)
Cells(3, 4).Value = parts(2)
End If
parts = Split(res2, " ")
If 3 <= UBound(parts) - LBound(parts) + 1 Then
Cells(4, 2).Value = parts(0)
Cells(4, 3).Value = parts(1)
Cells(4, 4).Value = parts(2)
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秒ごとにアクセスを繰り返します。
温度センサADT7410の個体差が測定温度に現れています。±0.3度程度の違いが現れます。
8 まとめ
Wi-FiマイコンESP-WROOM-02をWebサーバとして動作させ,ESP-WROOM-02に接続された温度センサADT7410の値を,クライアントがリクエストしたタイミングでデータを送信するようにしました。
また複数のESP-WROOM-02サーバからデータを得るためにVBAを使ってExcelに表示する例を示しました。
補足
Excelの画面では見た目が悪いので,Powerpointで作ることもできます。Excelのセルに表示するのではなく,Powerpointの表に表示することなどが考えられます。ただし,表示場所を指示するのが面倒なのと,ExcelVBAとPowerpointVBAに多少違いがあるので,注意が必要です。