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クライアントはWebサーバ(例えばPC上で動作しているApache2)に,温度データを伴ってアクセスします。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のスケッチコード(クライアントプログラム)

クライアントであるAE-ESP-WROOM-02-DEVは,一定の時間間隔で温度センサADT7410の値を取得し,Weサーバに送信します。
送信ではHTTP通信の手順に従います。

setupでは,自分が接続すべきWi-FiアクセスポイントのSSIDとパスワードを設定して,LANの一員になろうと試みます。
成功すると,LAN内のDHCPサーバーからIPアドレス(一次的な)をもらいます。
AE-ESP-WROOM-02-DEVは,クライアントなので他の機器からアクセスされることはないので,このIPアドレスもらって,自分が使うだけです。 一定時間ごとに,温度センサADT7410から,温度を取得し,"ホスト名","レスポンス回数","温度"の文字列をjson型式のデータとしてWebサーバにpostメソッドで送信します。

次のコードは,IDEの既存スケッチ例"PostHttpClient.ino"を元に作ったものです。

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Wire.h>
#include <Arduino_JSON.h>

#define SERVER_IP "192.168.1.25" //IP address of Web Server
#define SERVER_PATH "/jsontest/jsontest.php" //access target path in the Web Server

#define STASSID "REPLACE_WITH_YOUR_SSID"
#define STAPSK "REPLACE_WITH_YOUR_PASSWORD"

const String clientname = "esp8266a";

const int adt7410I2CAddress = 0x48; //default

int count = 0;

//adt7410から温度を得る
float getTemperature() {
  uint16_t uiVal; //2バイト(16ビット)の領域
  float fVal;
  int iVal; //符号ありの整数の値を保持

  Wire.requestFrom(adt7410I2CAddress, 2);   //2バイト要求
  
  uiVal = (uint16_t)Wire.read() << 8;   // 1バイト読み出しで上位にシフト
  uiVal |= Wire.read();                 // 1バイト読み出して下位にセット
    
  uiVal >>= 3;                          // シフトで13bit化

  if(uiVal & 0x1000) {               // 13ビットで符号判定
      iVal = uiVal - 0x2000;         // マイナスの時 (10進数で8192)
  }
  else{
      iVal = uiVal;                 //プラスの時
  }

  fVal = (float)iVal / 16.0;           // 温度換算(摂氏)
  return fVal;
}

void setup() {

  Serial.begin(115200);

  Serial.println();
  Serial.println();
  Serial.println();

  WiFi.begin(STASSID, STAPSK);
  Wire.begin(); //マスタで初期化

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // wait for WiFi connection
  if ((WiFi.status() == WL_CONNECTED)) {

    WiFiClient client;
    HTTPClient http;
    String url = String("http://") + SERVER_IP + SERVER_PATH;

    Serial.print("[HTTP] begin...\n");
    http.begin(client, url);  // HTTP access with post method
    http.addHeader("Content-Type", "application/json");

    Serial.print("[HTTP] POST...\n");

    // start connection and send HTTP header and body
    float temperature = getTemperature();
    Serial.println(temperature);

    //json format data
    JSONVar doc;
    doc["clientname"] = clientname;
    doc["count"]   = String(count++);
    doc["temperature"] = String(temperature);
    String jsonstr = JSON.stringify(doc);

    int httpCode = http.POST(jsonstr);

    // httpCode will be negative on error
    if (httpCode > 0) {
      // HTTP header has been sent and Server response header has been handled
      Serial.printf("[HTTP] POST... code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK) {
        const String& payload = http.getString();
        Serial.println("received payload:\n<<");
        Serial.println(payload);
        Serial.println(">>");
      }
    } else {
      Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    http.end();
  }

  delay(60000);
}

プログラムをAE-ESP-WROOM-02-DEVに書き込んで起動させると,直ちにIPアドレスを取得したことをArduinoIDEのシリアルモニターに表示します。
"Connected! IP address: 192.168.1.18"は,取得したIPアドレスでアクセスポイントに接続したことを表しています。
しかし,まだWebサーバの準備ができていないので,その後は失敗した(connection failed)と表示されます。
そのまま60秒間隔で失敗したと表示を続けます。

Connected! IP address: 192.168.1.18
[HTTP] begin...
[HTTP] POST...
32.25
[HTTP] POST... failed, error: connection failed
[HTTP] begin...
[HTTP] POST...
31.69
[HTTP] POST... failed, error: connection failed
 :

6 PCのWebサーバの準備

AE-ESP-WROOM-02-DEVのクライアントプログラムは単体では意味を成しません。対応するWebサーバ側にxxxxx.phpのような受け皿が必要です。
ここではWindowsPCにWindows Subsystem for Linuxを動かし,apache2をインストール・起動し,WebDocumentに.phpファイルを作ります。
WindowsPCのIPアドレスはAE-ESP-WROOM-02-DEVのプログラムに埋め込んだように
192.168.1.25
.phpファイルのpathはAE-ESP-WROOM-02-DEVのプログラムに埋め込んだように
/jsontest/jsontest.php
になります。

注意
Webサーバでは,ディレクトリ・ファイルのオーナやグループを,apache2が操作できるように設定する必要があります。
また,WinPCを使っている場合はWindowsPCのファイアウォールでポート番号80 (HTTP)を通す設定が必要です。

jsontest.phpでは"ホスト名","レスポンス回数","温度"のjson型式のデータを受け取り,それを三つの文字列に分解し,現在時刻とともにファイルに追加保存します。
複数のクライアントから非同期でアクセスが来るため,ファイル書き込みでは衝突しないように排他制御を行います。

jsontest.phpは次のようなphpプログラムです。

<?php
    print "Hello! from jsontest.php<br>\n";

    $body = file_get_contents('php://input');   //BODYの取得
 
    if (is_null($body)) {
        # error データが無い
        http_response_code(500);        //HTTP response code 500
        echo "No data (JSON)<br>";
        exit();
    }
 
    $jsonarry = json_decode($body, true);   //連想配列に変換
    if (is_null($jsonarry)) {
        # error JSONをデコードできない
        http_response_code(500);        //HTTP response code 500
        echo "Cannot decode JSON<br>";
        exit();
    }

    echo $jsonarry;
    var_dump($jsonarry);

    $str = date("Y/m/d H:i:s");
    foreach ($jsonarry as $i => $value) {
        $str .= ", " . $value;
    }
    // ファイルへ書き込み
    $fp = fopen("sample.txt", "a");
    flock($fp, LOCK_EX); //排他制御ここから
    fwrite($fp, $str . "\n");
    flock($fp, LOCK_UN); //排他制御ここまで
    fclose($fp);

?>

補足
Webブラウザ(client)からのアクセスに対してWebサーバはhtmlデータを返しますが,ここではマイコン(client)からのアクセスなので,htmlデータではなく最小限のデバッグ用データを返しています。

Webサーバの準備ができたところで,AE-ESP-WROOM-02-DEVを起動すると,ArduinoIDEのシリアルモニターに成功の様子が表示されるようになります。
うまくアクセスして,データがWebサーバに届くと,届けられたデータを返してくるのでその様子を見ることができます。
jsontest.phpの内容に不具合があると
[HTTP] POST... code: 500
が返ってくることもあります。

[HTTP] begin...
[HTTP] POST...
32.88
[HTTP] POST... code: 200
received payload:
<<
Hello! from jsontest.php<br>
Arrayarray(3) {
  ["clientname"]=>
  string(8) "esp8266a"
  ["count"]=>
  string(2) "13"
  ["temperature"]=>
  string(5) "32.88"
}

>>

7 2つのAE-ESP-WROOM-02-DEVがWebサーバにアクセス

2つのAE-ESP-WROOM-02-DEV(それぞれ温度センサADT7410を持っている)がクライアントとしてがWebサーバにアクセスします。

"2つのマイコンのクライアント"と"PCのWebサーバ"

AE-ESP-WROOM-02-DEVから見ると"http://192.168.1.25/jsontest/jsontest.php"とアクセスしていることになります。
表からは見えませんがpostメソッドでjson型式の"ホスト名","レスポンス回数","温度"のデータも同時に送信されます。
2つのAE-ESP-WROOM-02-DEVはそれぞれ,60秒間隔でアクセスします。
Webサーバー側のjsontest.phpはいつアクセスしてくるかわからないけれど,アクセスしてきたら,ファイルにアクセス内容を保存します。
保存されたファイルの内容は次のようになりました。60秒間隔で2つのクライアントAE-ESP-WROOM-02-DEVが,温度データを送信してきているのがわかります。

2023/09/03 06:19:14, esp8266b, 11, 33.38
2023/09/03 06:20:04, esp8266a, 0, 33.13
2023/09/03 06:20:14, esp8266b, 12, 33.38
2023/09/03 06:21:04, esp8266a, 1, 33.31
2023/09/03 06:21:14, esp8266b, 13, 33.25
2023/09/03 06:22:04, esp8266a, 2, 33.31
2023/09/03 06:22:14, esp8266b, 14, 33.25
2023/09/03 06:23:04, esp8266a, 3, 33.44
2023/09/03 06:23:14, esp8266b, 15, 33.38
2023/09/03 06:24:04, esp8266a, 4, 33.38
2023/09/03 06:24:14, esp8266b, 16, 33.25
2023/09/03 06:25:04, esp8266a, 5, 33.50
2023/09/03 06:25:14, esp8266b, 17, 33.31
2023/09/03 06:26:04, esp8266a, 6, 33.56
2023/09/03 06:26:14, esp8266b, 18, 33.31
2023/09/03 06:27:04, esp8266a, 7, 33.50
2023/09/03 06:27:14, esp8266b, 19, 33.31
2023/09/03 06:28:04, esp8266a, 8, 33.44
2023/09/03 06:28:14, esp8266b, 20, 33.31
2023/09/03 06:29:04, esp8266a, 9, 33.44

8 まとめ

Wi-FiマイコンESP-WROOM-02をWebクライアントとして動作させ,ESP-WROOM-02に接続された温度センサADT7410の値を,Webサーバの受け皿URLに60秒間隔でデータを送信するようにしました。 Webサーバの受け皿であるphpプログラムは受け取ったデータをファイルに追記するようにしました。