WiFi(ローカル接続、サーバー)で遠隔操作する方法(Arduinoプログラミング)

Arduinoコマンド:WiFiローカル接続設定

「ATOM LITE」を例に自宅のWi-Fiローカル通信環境に接続して、スマホ等からWi-Fi通信で遠隔操作を行う方法を紹介します。

「ATOM LITE」については以下のリンクで詳しく紹介しています。

ATOM LITE プログラミング初心者におすすめ超小型で高機能!
マイコンボードはRaspberry Pi、Arduino、M5Stack等がありますが、一通りやってみてそれぞれの良さはあるものの「最初に何を?」と聞かれたらATOM LITEが一番お手軽♪プログラミング初心者におすすめ
「開発環境の準備」がまだの方は → こちら

「ATOM LITE」をWi-Fiアクセスポイントにして遠隔操作する方法は以下のリンクで詳しく紹介しています。

WiFi(アクセスポイント、サーバー)で近距離遠隔操作する方法(Arduinoプログラミング)
「ATOM LITE」を例にWiFiアクセスポイントに設定して、スマホ等から近距離遠隔操作を行う方法を紹介します。サーバーのリクエスト(要求)に対してレスポンス(応答)を返すという動作を利用して、簡単なプログラムで遠隔操作が実現できます。

JavaScriptの「fetch」を使用してページを更新しない実用的なWi-Fi遠隔操作方法は以下リンクで詳しく紹介しています。

WiFi遠隔操作Arduinoコマンドでブラウザベースのスマホ、PCリモートコントローラの紹介
ブラウザベースで遠隔操作、リアルタイムデータ通信を行う方法をコピペ用サンプルプログラムを使って紹介します。 サーバー機能を利用して「JavaScript」の「fetch」を使うことでデータの送受信を行います。
スポンサーリンク

1.動作紹介(ATOM LITE)

サンプルプログラムの動作について紹介します。

まずは自宅のWi-Fiルータの設定に合わせて、プログラム内で「SSID」と「パスワード」を設定します。

・SSID:自宅のWiFi接続先名
・パスワード:接続先のパスワード

Wi-Fiルータとの接続が完了すると「IPアドレス」が自動で取得されます。
設定した「SSID」や「パスワード」、「IPアドレス」はシリアルモニタで確認することができます。
※表示されない場合は「ATOM LITE」側面の小さいリセットボタンを押すと表示されます。

「シリアルモニタ」については以下のリンクで詳しく紹介しています。

シリアル(UART)出力で内部データの表示(Arduinoプログラミング)
シリアル出力モニタとはプログラム内の値やデータをパソコンのモニタ上に表示させることができる機能で、ほとんどの開発環境にこの機能があります。表示だけではなく出力したデータを記録して保存したり、機器間でデータをやり取りする時にも使用されます。
「SSID」は自宅で使用しているWi-Fiの接続先です。
今使用しているパソコンやスマホと同じ「SSID」に接続先しましょう。
「パスワード」はWi-Fi接続時に入力するパスワードです。わからない時は自宅のWi-Fiルータのどこかに書いてあると思いますので確認してみましょう。
「IPアドレス」はWi-Fi接続時に自動で取得されます。これをブラウザのアドレスバーに入力することでサーバーにアクセスすることができます。

次に何でもよいのでネットを見るのに使っているブラウザを立ち上げて、アドレスバーに「IPアドレス」を入力してエンターを押すと、以下のような画面が表示されます。(下画像はGoogle Chromeです。)

アクセスポイント接続トップ画面

これは「ATOM LITE」をサーバーとして設定おり、ブラウザからのリクエスト(要求)に対して「ATOM LITE」側からレスポンス(応答)として「htmlデータ」が送信され、ブラウザ側で表示されたためです。

「ON」「OFF」ボタンにもリクエストとしてアドレスが設定されており、ボタンが押されることでこのアドレスがリクエストとして送信されます。
「ATOM LITE」側サーバーはこれをうけて、それぞれに対応したプログラムを実行し、設定したレスポンスを返します。

これにより「ON」ボタンを押すと「ATOM LITE」本体のLEDが青色に「OFF」を押すとLEDは白色に変わる動作が行えるようになっています。
出力端子「21」も同時にON/OFFさせているため、LED等を接続すると連動してON/OFFさせることができます。


スポンサーリンク

2.サンプルプログラム(コピペ)

下のコードを「コピペ」して書き込んで動作確認してみましょう。
※コピーは下コード(黒枠)内の右上角にある小さなアイコンのクリックでもできます。

#include <M5Atom.h>
#include <WiFi.h>       //Wi-Fi接続用
#include <WebServer.h>  //サーバー設定用

// Wi-Fiローカル接続先設定
const char ssid[] = "自宅のWi-Fi接続先を記入"; //接続先SSID
const char pass[] = "接続先のパスワードを記入"; //接続先パスワード

// サーバー設定ポート80で接続
WebServer server(80);
// htmlメイン画面データ ※R"この中の文字列は改行は無視され連続した文字列として扱われる"
char html[] = R"(
  <!DOCTYPE html>
  <html lang="jp">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>REMOTE-SWITCH</title>
  </head>
    <body>
      <h1>REMOTE-SWITCH</h1>
      <div>
        <button style="height:50px" onclick="location.href='/get/btn_on'"> ON </button>
        <button style="height:50px" onclick="location.href='/get/btn_off'"> OFF </button>
      </div>
    </body>
  </html>
)";

// FastLED(CRGB構造体)設定
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
  return (CRGB)((r << 16) | (g << 8) | b);
}
//-------------------------------------------------
// サーバーリクエスト時処理関数
//-------------------------------------------------
// ルートアクセス時の応答関数
void handleRoot() {
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}
// エラー(Webページが見つからない)時の応答関数
void handleNotFound() {
  server.send(404, "text/plain", "404 Not Found!");  //text送信
}
// ブラウザONボタン処理
void btnOn() {
  digitalWrite(21, HIGH);                   //出力0 ON(青色LED)
  M5.dis.drawpix(0, dispColor(0, 0, 200));  //本体LED(青)
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}
// ブラウザOFFボタン処理
void btnOff() {
  digitalWrite(21, LOW);                    //出力0 OFF(青色LED)
  M5.dis.drawpix(0, dispColor(20, 20, 20)); //本体LED(白)
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}
//-------------------------------------------------
// 初期設定
//-------------------------------------------------
void setup() {
  M5.begin(true, false, true);  //Serial,POWER,LED
  Serial.begin(9600);           //標準のシリアル通信設定

  // WiFi接続開始
  WiFi.begin(ssid, pass); //ローカル接続開始

  // WiFi接続完了待ち
  while (WiFi.status() != WL_CONNECTED) { //接続完了するまで繰り返す
    delay(500);                       //0.5秒待機
    Serial.print(".");                //「.」シリアル出力
  }

  // サーバー設定
  server.on("/", handleRoot);         //ルートアクセス時の応答関数を設定
  server.onNotFound(handleNotFound);  //Webページが見つからない時の応答関数を設定
  server.on("/get/btn_on", btnOn);    //ボタンオン受信処理
  server.on("/get/btn_off", btnOff);  //ボタンオフ受信処理
  server.begin();                     //Webサーバー開始

  // シリアル出力
  Serial.printf("\nSSID:%s\n", ssid);//SSID
  Serial.printf("PASS:%s\n", pass);  //PASSWORD
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());    //IPアドレス(配列)

  // 本体LED設定
  M5.dis.drawpix(0, dispColor(20, 20, 20)); //LED点灯(白)
  // 入出力端子設定
  pinMode(21, OUTPUT);  //出力端子
}
//-------------------------------------------------
// メイン
//-------------------------------------------------
void loop() {
  server.handleClient();  //クライアントからのアクセス確認
  delay(200);             //遅延時間(ms)
}
スポンサーリンク

3.ローカルWi-Fi接続方法

ローカルWi-Fi接続するプログラムについて紹介します。

まず上コードの2行目のように以下のWi-Fi接続に必要なヘッダーファイル「WiFi.h」を準備します。

#include <WiFi.h>  //WiFi接続用

ローカル接続の設定を行うために、5行目~7行目のように接続先のWi-Fiルータの「SSID」と「パスワード」の設定を行います。

// WiFiローカル接続先設定
const char ssid[] = "自宅のWi-Fi接続先を記入";  //接続先SSID
const char pass[] = "接続先のパスワードを記入"; //接続先パスワード
プログラムの「SSID」と「パスワード」は使用しているWi-Fiの接続先に合わせて書き換えてください。
「パスワード」がわからない時はWi-Fiルータのどこかに書いてあると思いますので確認してみましょう。

次に64, 65行目のように初期設定(void setup)の中で以下のように設定することでローカル接続が開始されます。

// WiFi接続開始
WiFi.begin(ssid, pass);  //ローカル接続開始

次に67行目~71行目のようにローカル接続が完了するまでC言語の「while文」を使用して待ちます。
WiFi.status()は通信状態の情報を返します。これが「WL_CONNECTED(接続完了)」になるまで0.5秒ごとに「.」をシリアル出力モニタに表示し続けます。

// WiFi接続完了待ち
while (WiFi.status() != WL_CONNECTED) { //接続完了するまで繰り返す
  delay(500);                       //0.5秒待機
  Serial.print(".");                //「.」シリアル出力
}

WL_CONNECTED(接続完了)」になればローカル接続は完了です。

4.サーバー設定プログラムの詳細

「ATOM LITE」をサーバーとして設定するプログラムについて紹介します。

ここはWi-Fiアクセスポイント接続で紹介した記事とIPアドレス以外同じ内容です。
サーバーとはリクエスト(要求)に対してレスポンス(応答)を返すという動作をします。
この動作を利用して、リクエストを受けたら必要な処理を実行してからレスポンスを返すというのが本プログラムの基本動作になります。

まず3行目のように以下のWi-Fi接続に必要なヘッダーファイル「WebServer.h」を準備します。

#include <WebServer.h>  //サーバー設定用

次に10行目のようにサーバーのポート設定を行います。
一般的に「80」が使用されるので以下のように「80」で設定しましょう。

// サーバー設定ポート80で接続
WebServer server(80);
ポートは80以外に設定してもいいですが、この場合はIPアドレスの後に設定したポートを指定する必要があります。
例:ポート8080の場合、「(IPアドレス):8080」
※ポート80は省略されているだけで実際は「(IPアドレス):80」として送信されています。80にしておけば「:80」を書かなくてもよいです。

次に11行目~28行目のようにブラウザで表示させたい「htmlデータ」を文字列として以下のように準備しておきます。

// htmlメイン画面データ ※R"この中の文字列は改行は無視され連続した文字列として扱われる"
char html[] = R"(
  <!DOCTYPE html>
  <html lang="jp">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>REMOTE-SWITCH</title>
  </head>
    <body>
      <h1>REMOTE-SWITCH</h1>
      <div>
        <button style="height:50px" onclick="location.href='/get/btn_on'"> ON </button>
        <button style="height:50px" onclick="location.href='/get/btn_off'"> OFF </button>
      </div>
    </body>
  </html>
)";

今回の「htmlデータ」は「REMOTE-SWITCH」という表示と「ON」「OFF」ボタンを置いただけのシンプルなものです。

ボタンには「onclick」でリンク先のアドレスが指定されており、ボタンが押された時にそれぞれのアドレスへのリクエストを受けて「ATOM LITE」側で処理が実行されます。

各ボタンには以下のようにルート(IPアドレス)に続くアドレスを指定しています。

・ONボタン:(IPアドレス)/get/btn_on
・OFFボタン:(IPアドレス)/get/btn_off
アドレスの指定で「/」はルートのアドレス(IPアドレス)を表します。
「htmlデータ」の文字列は「R”( )”」のカッコ内に書くことで、改行は無視され連続した文字列として扱われます。

次に73行目~78行目のように初期設定(void setup)の中でブラウザからのリクエスト(アドレス)を受けた時に実行する処理(関数)を以下のように設定します。

// サーバー設定
server.on("/", handleRoot);         //ルートアクセス時の応答関数を設定
server.onNotFound(handleNotFound);  //Webページが見つからない時の応答関数を設定
server.on("/get/btn_on", btnOn);    //ボタンオン受信処理
server.on("/get/btn_off", btnOff);  //ボタンオフ受信処理
server.begin();                     //Webサーバー開始
server.on ( アドレス関数名 ) ;

server.on:ブラウザからのリクエストに対して実行する関数を指定するコマンド。
アドレス:ブラウザから受信するアドレス(リクエスト)を指定(「/」はルート[IPアドレス]を表す。)
関数名:ブラウザからのリクエストを受けて実行する関数を指定。レスポンスもこの関数内で返す。

設定が終わったら最後に「server.begin()」を実行してサーバー動作を開始します。


次にブラウザからのリクエストに対して実行する処理を関数にまとめて設定します。

この関数は初期設定(void setup)より上に書く必要があります。

まずは37行目~40行目のようにルート「/」(IPアドレス)へのリクエストに対して実行される処理を以下のように設定します。

ここでは、レスポンスコード「200」で通信が正常に行われたことを知らせて、「html」に格納されている文字列を「htmlデータ」として返しています。

// ルートアクセス時の応答関数
void handleRoot() {
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}
server.send ( レスポンスコードデータ形式送信データ) ;

server.send:ブラウザのリクエストに対してレスポンスを返すコマンド。
レスポンスコード:通信結果をブラウザ側に伝える3桁のコード。
・「200」通信正常終了
・「404」Webページが見つからない・・・等
データ形式:ブラウザへ送信するデータ形式(MIMEタイプ)を指定。
・「text/html」htmlデータ
・「text/plain」テキストデータ
・「text/css」cssデータ
・「text/javascript」JavaScriptデータ・・・等
送信データ:ブラウザへ送信するデータ


次に41行目~44行目のようにブラウザからリクエストされたアドレスが見つからなかった時の処理を以下のように設定します。

ここでは、レスポンスコード「404」でページが見つからなかったことを知らせて、「404 Not Found!」を「textデータ」として返しています。

// エラー(Webページが見つからない)時の応答関数
void handleNotFound() {
  server.send(404, "text/plain", "404 Not Found!");  //text送信
}
textデータ」はブラウザ上でそのまま表示されます。

次に45行目~56行目のようにブラウザの「ON」「OFF」ボタンが押された時のリクエストに対して実行される処理を以下のように設定します。

「ON」ボタンの処理は出力端子をHIGH(3.3V)にして本体LEDを青色に点灯した後、レスポンスコード「200」で通信が正常に行われたことを知らせて、「html」に格納されている文字列を「htmlデータ」として返しています。

「OFF」ボタンの処理は出力端子をLOW(0V)にして本体LEDを白色に点灯した後、レスポンスコード「200」で通信が正常に行われたことを知らせて、「html」に格納されている文字列を「htmlデータ」として返しています。

// ブラウザONボタン処理
void btnOn() {
  digitalWrite(21, HIGH);                   //出力0 ON(青色LED)
  M5.dis.drawpix(0, dispColor(0, 0, 200));  //本体LED(青)
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}
// ブラウザOFFボタン処理
void btnOff() {
  digitalWrite(21, LOW);                    //出力0 OFF(青色LED)
  M5.dis.drawpix(0, dispColor(20, 20, 20)); //本体LED(白)
  server.send(200, "text/html", html);  //レスポンス200を返しhtml送信
}

最後に95行目のようにメイン処理(void loop)内で以下を実行し続けブラウザからのリクエストを監視します。

ブラウザからのリクエストが確認されたら、サーバー設定で設定した各処理を実行します。

server.handleClient();  //クライアントからのアクセス確認

5.まとめ

Wi-Fi通信で自宅のローカル環境に接続するには、ヘッダーファイル「WiFi.h」を準備して、設定した「SSID」と「パスワード」で「WiFi.begin」を実行するだけで接続が開始されます。

WiFi.status()で通信状況を確認し、これが「WL_CONNECTED(接続完了)」になれば接続完了です。

サーバーの設定は、ヘッダーファイル「WebServer.h」を準備して、通信ポートを「80」に設定します。
ブラウザページとして表示する「htmlデータ」を文字列で準備します。

server.on」で各リクエストに対して実行する関数を設定し、この関数内の処理が実行された時には「server.send」でレスポンスコードとデータを返すように設定します。

メイン内で「server.handleClient」を繰り返し実行しブラウザからのリクエストを監視し、ブラウザからのリクエストが確認されたら、設定した各処理を実行しています。

今回の遠隔操作は、サーバーのリクエスト(要求)に対してレスポンス(応答)を返すという動作を利用して、リクエストを受けたら必要な処理を実行させることで実現しています。


以上のように、サーバーの基本的な動作を利用することでシンプルなプログラムで遠隔操作が実現できましたが、今回のプログラムではボタン操作を行うごとにページが更新されてしまっています。
こうならないように「javascript」を使用してボタンにイベントを設定することでページを更新しない動作も実現できます。
「css」を使えばページのデザインも凝ったものが作れます
また「M5Stack GRAY」のようにSDカードが使えれば、そこからデータを読み込んで表示させると文字列ではなくそのままデータを読み込めて便利なので、また詳しく紹介したいと思います。

アクセスポイント接続ですが、ボタンの「ON」「OFF」だけでなく「ATOM LITE」側のボタン状態やカウント数、アナログ値を表示する「簡易IoT」は以下のリンクで紹介しています。

簡易IoT(稼働監視、遠隔操作)テストプログラム(ATOM LITE使用)の紹介
簡易ですが「IoT」やりましょう♪ IoTとは「Internet of Things」の略で「モノのインターネット」と呼ばれるものです。スマホから遠隔操作でLチカしたり、ボタンを押した回数やアナログ値の取得もできます。

コメント

タイトルとURLをコピーしました