アプリケーション開発

Arduino IDEでWifiRemoteライブラリを用いてモバイル端末によるマイコンのリモート制御アプリケーションを簡単に作ることができます。

提供ライブラリ

WifiRemoteライブラリはWifiRemoteライブラリよりダウンロードできます。

ダウンロードしたwifiremote.zipを展開すると次の3つのファイルが生成されます。

WiFiRemote.h WiFiRemoteライブラリのヘッダファイルです。
WiFiRemote.cpp WiFiRemoteライブラリのソースファイルです。
setting.html アクセスポイント設定用のHTMLファイルです。

開発手順

  1. アプリケーション MyRemote をArduino IDEで新規作成すると、MyRemoteフォルダ内に MyRemote.ino ファイルが作成されます。
  2. MyRemoteフォルダ内に dataフォルダを作ります。dataフォルダはマイコンのフラッシュメモリのSPIFFSに対応します。
  3. MyRemoteフォルダ内に 提供ライブラリの WiFiRemote.h と WiFiRemote.cpp をコピーします。
  4. MyRemoteフォルダ/dataフォルダ内に、提供ライブラリの setting.html をコピーします。
  5. MyRemoteフォルダ/dataフォルダ内に、リモートアプリケーションの操作画面となる index.html を作成します。必要に応じてCSSファイルや画像ファイルも追加します。
  6. MyRemote.inoとindex.htmlをArduino IDEで編集してアプリケーションを作成します。
  7. MyRemote.inoはArduino IDEでマイコンボードに書き込みます。
  8. dataフォルダ内のファイルは ESP32 Sketch Data Upload を使用してフラッシュメモリのSPIFFSにコピーします。

開発事例

以下のような仕様のマイコン装置をモバイル端末のブラウザ画面からリモート制御するプログラムを作ります。

仕様

マイコン装置仕様

タクトスイッチがGPIO32に接続されています。
表示用のLEDがGPIO16に接続されています。
未接続確認用のLEDがGPI25に接続されています。
接続済確認用のLEDがGPI27に接続されています。

リモコン画面仕様

マイコン装置のタクトスイッチが押されているかどうかを表示するテキストがあります。
マイコン装置の表示用LEDをオンオフするためのONとOFFの2つのボタンがあります。

動作仕様

マイコン装置を起動するとWiFi接続を試み、試行中は接続済確認用と未接続確認用のLEDが交互に点滅します。
WiFi接続に成功すると接続済確認用のLEDが点灯し、失敗すると未接続確認用のLEDが点灯します。
マイコン装置のタクトスイッチを押すと対応したリモコン画面のテキストが「ON」に、離すと「OFF」になります。
リモコン画面のONボタンを押すとマイコン装置の表示用LEDが点灯します。
リモコン画面のOFFボタンを押すとマイコン装置の表示用LEDが消灯します。

スケッチの作成

Arduino IDEでスケッチを新規作成します。名前を付けてスケッチを保存します。ここでは名前を MyRemote とします。

スケッチフォルダを開くと、MyRemote.ino が作成されているのが見れます。

提供ライブラリに含まれるWiFiRemote.hとWiFiRemote.cppをスケッチフォルダ内にコピーします。

スケッチフォルダ内に dataフォルダを作成します。

提供ライブラリに含まれる setting.html を dataフォルダ内にコピーします。setting.html はアクセスポイント設定用のWEBファイルです。

dataフォルダ内にindex.htmlを新規作成します。index.htmlはリモート制御画面用のWEBファイルです。

この段階でフォルダは次のような構成となります。

MyRemoteフォルダ
MyRemote.ino 
WiFiRemote.h
WiFiRemote.cpp
dataフォルダ
setting.html 
index.html

リモート制御用画面の作成

dataフォルダ内にあるindex.htmlを編集してリモート制御用の画面を作成します。

作り方は通常のHTMLの作り方と同じです。
リモート制御用画面とマイコン装置とのデータのやり取りにはJavaScriptが必要です。
仕様を満たす簡単なHTMLソースは次のようなものです。

(index.html)

<!DOCTYPE html>
<html>
	<head>
		<meta name="viewport" content="width =device-width,initial-scale =1">
		<title>My Remote Controller</title>
		<link rel="icon" href="favicon.ico">
	</head>
	<body>
		<table align="center" border="0" width=80%>
			<tr>
				<td align="center" colspan="3"><h1>My Remote Controller</h1></td>
			</tr>
			<tr>
				<td>SWITCH</td>
				<td colspan="2"><p id="sw">OFF</p></td>
			</tr>
			<tr>
				<td width="40%">LED</td>
				<td width="30%"><button onclick="buttonClick(0)">ON</button></td>
				<td width="30%"><button onclick="buttonClick(1)">OFF</button></td>
			</tr>
		</table>

		<script>
			function buttonClick(onoff) {
				var xhr = new XMLHttpRequest()
				xhr.open("POST", "/notify", true)
				xhr.setRequestHeader("Content-Type", "text/plain")
				xhr.send(String(onoff))
			}
			function getSwitch() {
				var xhr = new XMLHttpRequest();
				xhr.onreadystatechange = function () {
					if (this.readyState == 4 && this.status == 200 && this.responseText.length == 1) {
						var res = this.responseText;
						var sw = document.getElementById("sw");
						sw.textContent = res == "0" ? "OFF" : "ON";
					}
				};
				xhr.open("POST", "/inquire", true);
				xhr.send("switch");
			}
			setInterval(getSwitch, 200);
		</script>
	</body>
</html>

(解説)

このjavascriptではbuttonClickとgetSwitchの2つの関数を定義しています。

buttonClick関数

この関数はボタンを押したときに、ボタンが押されたことと、どのボタンが押されたかをマイコン装置に通知するものです。
2つのbutton要素のonClick属性に指定されていて、ボタンを押すごとに呼び出されます。
この関数は押されたボタンの種別(0又は1)を引数として受け取ります。
サーバー(マイコン)に通知を送信するには XMLHttpReques を用いて POST メソッドで アドレス /notify に非同期(true)で送信します。
これは定型的に次のようなコードとなります。

	var xhr = new XMLHttpRequest()
	xhr.open("POST", "/notify", true)
	xhr.setRequestHeader("Content-Type", "text/plain")
	xhr.send(通知メッセージ)

今回の場合は通知メッセージはボタンの種類を文字列化した String(onoff) となります。

getSwitch関数

この関数はマイコン装置のタクトスイッチが押されているかどうかを問い合わせるものです。
この関数はタイマーにより0.2秒間隔で呼び出されます。このことを指定しているのがスクリプトの最後に書かれている次のコードです。 

	setInterval(getSwitch, 200) ;

サーバー(マイコン)に問い合わせを送信するには XMLHttpReques を用いて POST メソッドで アドレス /inquireに非同期(true)で送信します。
これは定型的に次のようなコードとなります。

	var xhr = new XMLHttpRequest();
	xhr.open("POST", "/inquire", true);
	xhr.setRequestHeader("Content-Type", "text/plain")
	xhr.send(問い合わせ識別);

今回の場合は問い合わせ識別は文字列"switch"としました。
問い合わせの処理では問い合わせに対する応答を処理する必要があります。
問い合わせのに対する応答があった場合に readystatechange イベントが発生します。
readystatechange イベントを処理する関数を定義します。
その中で、リクエスト状態(readyState)が操作が完了した(4)ことと、レスポンス(status)が成功(200)したこと確認して下さい。
また、レスポンスはテキストはresponseTextとして入ってきますので、それを参照してブラウザの表示を変更する等の処理を行います。

	xhr.onreadystatechange = function () {
		if (this.readyState == 4 && this.status == 200 && this.responseText.length == 1) {
			var res = this.responseText;
			var sw = document.getElementById("sw");
			sw.textContent = res == "0" ? "OFF" : "ON";
		}
	};

マイコンプログラムの作成

arduino IDEを使用してMyReremote.inoを編集します。

(MyReremote.ino)

#include "WiFiRemote.h"

#define SW  32  // タクトスイッチ
#define LED 16  // 出力LED
#define CONNECTED 27  // 接続状態済LED
#define UNCONNECT 25  // 未接続状態LED

WiFiRemote wifiRemote(80);

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

  // マイコンをアクセスポイントにするときのアドレス等を設定
  wifiRemote.setESPAddress("ESP32", "", IPAddress(192,168,123,45), IPAddress(255,255,255,0));
  
  // WiFiRemoteライブラリから呼び出されるコールバック関数を登録
  wifiRemote.setCallback(onStarting, onNotify, onInquire);

  // 入出力ピン設定
  pinMode(SW,  INPUT);
  pinMode(LED, OUTPUT);
  pinMode(CONNECTED, OUTPUT);
  pinMode(UNCONNECT, OUTPUT);

  // WiFiRemoteを開始
  wifiRemote.begin(false);
}

void loop() {}

// コールバック関数

// マイコンをWEBサーバーとして起動中
// マイコンをWEBサーバーとして起動中に0.5秒間隔で呼び出され、その都度onoffの値が0と1に交互に変化する
// WEBサーバーの起動に成功すればonoffは1となり、失敗すれば0となる
void onStarting(byte onoff)
{
  digitalWrite(UNCONNECT, onoff == 0 ? HIGH : LOW);
  digitalWrite(CONNECTED, onoff == 1 ? HIGH : LOW);
}

// リモート端末より通知を受ける
// 通知が1の時LEDを点灯する
void onNotify(const char *notice)
{
  digitalWrite(LED, strcmp(notice, "1") == 0 ? LOW : HIGH);
}

// リモート端末より問合せを受ける
// kindが"switch"の場合にタクトスイッチの状態を返す
const char* onInquire(const char* kind)
{
    if (strcmp(kind, "switch") == 0)
    {
      return digitalRead(SW) == HIGH ? "1" : "0";
    }
    return "";
}

(解説)

#include "WiFiRemote.h"

最初にWiFiRemoteライブラリのヘッダファイルをインクルードします。

#define SW  32  // タクトスイッチ
#define LED 16  // 出力LED
#define CONNECTED 27  // 接続状態済LED
#define UNCONNECT 25  // 未接続状態LED

入出力ピンの定義です。

WiFiRemote wifiRemote(80);

ポート80を指定してWiFiRemoteのインスタンスを生成します。

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

setupでは最初にシリアルポートを転送レートを指定して初期化します。

  // マイコンをアクセスポイントにするときのアドレス等を設定
  wifiRemote.setESPAddress("ESP32", "", IPAddress(192,168,123,45), IPAddress(255,255,255,0));

マイコンをWiFiを利用してモバイル端末からリモートで制御するためには、マイコンとWiFiが通信できるように設定する必要があります。
この設定を行うにはマイコン側のアドレスをプログラムで固定しておき、モバイル端末からアクセスできるようにする必要があります。
このためにsetESPAddressの引数にはSSID、パスワード、IPアドレス、サブネットマスクを指定します。

  // WiFiRemoteライブラリから呼び出されるコールバック関数を登録
  wifiRemote.setCallback(onStarting, onNotify, onInquire);

WiFiRemoteライブラリから呼び出されるコールバック関数を登録を登録します。
onStartingは開始時に呼び出される関数, onNotifyはモバイル端末から通知があったときに呼び出される関数, onInquireはモバイル端末がマイコンの状態を要求した時の関数です。
これらの関数は別途定義する必要があります。

  // 入出力ピン設定
  pinMode(SW,  INPUT);
  pinMode(LED, OUTPUT);
  pinMode(CONNECTED, OUTPUT);
  pinMode(UNCONNECT, OUTPUT);
入出力ピンのモードを設定します。
  // WiFiRemoteを開始
  wifiRemote.begin(false);

準備ができたらWiFiRemoteを開始します。
引数をtrueとするとアクセスポイントを初期化して開始します。アクセスポイントを再設定するときに行います。
実装ではマイコンに初期化用のボタンを設け、ボタンが押されていれば初期化するようにします。

void loop() {}

通常は他にも書かなくても構いません。

(コールバック関数)

// マイコンをWEBサーバーとして起動中
// マイコンをWEBサーバーとして起動中に0.5秒間隔で呼び出され、その都度onoffの値が0と1に交互に変化する
// WEBサーバーの起動に成功すればonoffは1となり、失敗すれば0となる
void onStarting(byte onoff)
{
  digitalWrite(UNCONNECT, onoff == 0 ? HIGH : LOW);
  digitalWrite(CONNECTED, onoff == 1 ? HIGH : LOW);
}
マイコンをWEBサーバーとして起動中に呼び出されるコールバック関数です。
ここではonoffの値を用いて起動中は接続状態済LEDと未接続状態LEDを交互に点灯し、最終的に土地らかのLEDが点灯するようにしています。
// リモート端末より通知を受ける
// 通知が1の時LEDを点灯する
void onNotify(const char *notice)
{
  digitalWrite(LED, strcmp(notice, "1") == 0 ? LOW : HIGH);
}

リモート端末より通知を受けたときに呼び出されるコールバック関数です。
文字列noticeがリモート端末より渡されます。
ここではこの文字列が"0"か"1"かでLEDをON・OFFさせています。

// リモート端末より問合せを受ける
// kindに対応したタクトスイッチの状態を返す
const char* onInquire(const char* kind)
{
    if (strcmp(kind, "switch") == 0)
    {
      return digitalRead(SW) == HIGH ? "1" : "0";
    }
    return "";
}

リモート端末より問い合わせを受けたときに呼び出されるコールバック関数です。
問い合わせ内容を区別する文字列kindがリモート端末より渡されます。
この内容に応じてデータを返します。
ここではタクトスイッチの押下状態を"0"または"1"で返しています。