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 使用環境

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に多少違いがあるので,注意が必要です。