インターフォンの製作(その2)

前回は、ESP32同士でUDP通信を行いました。一方がサーバーで他方がクライアントでした。今回はルータを通した通信を行いたいと思います。

ルータを通すので、前回の様にサーバを上げる必要は有りません。2つのESP32をSTAモードでWiFiにつなげば良いはずです。前回のクライアント側スケッチを元に書き換えました。先ずは送信側


#include "WiFi.h"
#include <WiFiUdp.h>

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

IPAddress ip(192, 168, 3, 30);              // IP Address
IPAddress gateway(192,168, 3, 1);           // Gateway Address
IPAddress subnet(255, 255, 255, 0);         // Subnet Address

IPAddress cl01_ip(192, 168, 3, 31);           // Client01 IP Address

static const int Remote_Port = 9000;        // Destination port
static const int Org_Port = 9000;           // Source port

WiFiUDP UDP;

void setup()
{
  Serial.begin(115200);
    
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  
  Serial.println("Connected");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
    
  UDP.begin(Org_Port);
  Serial.println("Client OK");
    
}

char a = 'A';
void loop()
{
  Serial.println("Send : " + String(a));

  UDP.beginPacket(cl01_ip, Remote_Port);
  UDP.write(a);
  UDP.endPacket();  

  a ++;
  if(a > 'F') a = 'A';

  delay(3000);
}
  • 4,5行 ルータデータ
    • 今回は自宅ルータのSSIDとPASSWORDを入力して下さい。
  • 7行 IPAddress ip(192, 168, 3, 31);
    • IPアドレスの指定。ルータの都合で”192. 168. 3. 30″としました。
  • 8,9行 GatewayとSubnetの指定。
  • 11行 IPAddress cl01_ip(192, 168, 3, 31);
    • 相手側のIPアドレスです。
  • 22行 WiFi.mode(WIFI_STA);
    • STAモード設定
  • 23行 WiFi.config(ip, gateway, subnet);
    • IPアドレス等設定。
  • 24行 WiFiに接続。
  • 後は前回の送信側と同じです。

次は受信側


#include <WiFiUdp.h>
#include "WiFi.h"

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

IPAddress ip(192, 168, 3, 31);              // IP Address
IPAddress gateway(192,168, 3, 1);           // Gateway Address
IPAddress subnet(255, 255, 255, 0);         // Subnet Address

IPAddress cl00_ip(192, 168, 3, 30);         // Client00 IP Address

static const int Remote_Port = 9000;        // Destination port
static const int Org_Port = 9000;           // Source port

WiFiUDP UDP;

void setup()
{
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  
  Serial.println("Connected");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  
  UDP.begin(Org_Port);
  Serial.println("Server OK");
   
}

void loop()
{
  char rv_data[2] = {0,0};

  if (UDP.parsePacket() > 0)
    {
      UDP.read(rv_data , 1);
      Serial.print("Recieve : ");
      Serial.println(rv_data);
      UDP.flush();
    }
}
  • 7,11行 送信側とIPアドレスが逆。
  • 22,23,24行 WiFiにSTAモードで接続。
  • 後は前回の送信プログラムと同じ。

コンパイル、実行して下さい。下記は左が送信側、右が受信側のモニタです。

送信側、受信側共にIPアドレスが正しく設定されています。これでルータを通してESP32同士UDPで繋ぎました。

DNSサーバーを使えば

UDPでデータを送る場合、UDP.beginPacket()で先ず通信の準備を行いますが、この関数の最初の引数は送信先のIPアドレスです。だとすれば、DNSを使ってWiFiに繋ぎ、ドメイン名からIPアドレスを引っ張って来ればIPアドレスを固定する必要が無いのでは。試して見ます。

先ずは送信側


#include "WiFi.h"
#include <WiFiUdp.h>
#include <ESPmDNS.h>

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

static const int Remote_Port = 9000;        // Destination port
static const int Org_Port = 9000;           // Source port

WiFiUDP UDP;

void setup()
{
  Serial.begin(115200);
    
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
    
  if (MDNS.begin("UDP_Client01")) 
    Serial.println("MDNS responder started");

  UDP.begin(Org_Port);
  Serial.println("Client01 OK");
    
}

char a = 'A';
void loop()
{
  char buf[7];

  Serial.println("Send : " + String(a));

  UDP.beginPacket(MDNS.queryHost("UDP_Client00"), Remote_Port);
  UDP.write(a);
  UDP.endPacket();  

  a ++;
  if(a > 'F') a = 'A';

  delay(3000);
}
  • 3行 #include
    • DNSヘッダーファイルのインクルード
  • 29行 if (MDNS.begin(“UDP_Client01”))
    • ドメイン名を”UDP_Client01″に設定
  • 44行 UDP.beginPacket(MDNS.queryHost(“UDP_Client00”), Remote_Port);
    • MDNS.queryHost(“UDP_Client00”)がドメイン名”UDP_Client00″のIPアドレスを返す。
    • “UDP_Client00″は送信先のドメイン名

受信側


#include <WiFiUdp.h>
#include "WiFi.h"
#include <ESPmDNS.h>

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

static const int Remote_Port = 9000;        // Destination port
static const int Org_Port = 9000;           // Source port

WiFiUDP UDP;

void setup()
{
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP()); 

  if (MDNS.begin("UDP_Client00")) 
    Serial.println("MDNS responder started");
   
  UDP.begin(Org_Port);
  Serial.println("Client00 OK");
   
}

void loop()
{
  char rv_data[2] = {0,0};

  if (UDP.parsePacket() > 0)
    {
      UDP.read(rv_data , 1);
      Serial.print("Recieve : ");
      Serial.println(rv_data);
      UDP.flush();
    }
}
  • 29行 if (MDNS.begin(“UDP_Client00”))
    • ここでドメイン名を”UDP_Client00″に設定
  • 後は変更なし

コンパイル、実行して下さい。左が送信側、右が受信側です。送信、受信共にIPアドレスは指定していませんが、ルータが、”192.168.3.13”と”192.168.3.12”を振ってくれた様です。かつそのIPアドレスを指定する事無くドメイン名で送信先にデータを送る事が出来ました。かなり便利な気がします。

このDNA、softAPモードでも使用出来ました。ルータに繋いだ方が通信範囲が広いと思うので取り敢えずルータを通す事にします。

一回に送るデータが1バイトでは困る

送信用のプログラムでデータを送信する関数は、UDP.write(a); 一回の通信で1バイトの送信です。流石にこれでは通信量が少ないと思っていたら、バッファーデータを送る関数が有りました。

UDP.write(Buffer,Buffer_size); 

関数名は同じですが、引数が違います。最初の引数が、データを格納したバッファーのアドレス。次はそのバッファーのサイズです。また、バッファーは符号無し8ビットで宣言する様です。

受け側もこれに対応して、

UDP.read(Buffer , Buffer_size);

が有りました。最初の引数は、データを格納するバッファーのアドレス。次は読み込むデータの数です。

送れる最大数は

次の興味はバッファーを使用した場合1回で送れる最大数は幾つかです。バッファーサイズを変えて送信して見ましたが、どうも1280以上は1回では送れない様です。つまり、1回で送れる最大数は1280バイトとなります。

だいぶ進んで来ました。UDPに関しては取り敢えずここまで。次回は音声の入力と出力について考えます。