今回はESP32とpythonプログラムの間でwifi経由で通信を行う方法について紹介します。
・ESP32をpythonプログラムを用いて遠隔操作する方法を知りたい
今回の目標
ESP32をサーバ、pythonプログラムをクライアントとして、ESP32ーpythonプログラム間でwifi経由で通信(ソケット通信)を行います。
pythonプログラムから任意のメッセージを送信し、ESP32のシリアルモニタにメッセージを表示します。
使用するプログラムの紹介
ESP32用プログラム(サーバ側)
Arduino側には次のようなスケッチを使用します。
このスケッチはESP32のボードマネージャのサンプルプログラム"simpleWifiServer"を一部改変することで作成しました。
//#ESP32-PC間通信用プログラム(ESP32側) //ライブラリのインクルード #include <WiFi.h> const char* ssid = "yourSsid";//適宜ネットワークのSSIDに書き換えてください const char* password = "yourPassword";//適宜ネットワークのパスワードに書き換えてください WiFiServer server(5000);//ポート番号5000でサーバーとして使用する String message; String oneLetter; void setup() { Serial.begin(115200);//ビットレート115200でシリアル通信を開始 Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password);//アクセスポイントに接続 while (WiFi.status() != WL_CONNECTED) {//接続が完了しない場合"・"を打って待機 delay(500); Serial.print("."); } //接続が完了したら以下の内容を表示 Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP());//自身のIPアドレスを表示 server.begin();//サーバー開始 } int value = 0; void loop(){ WiFiClient client = server.available();//サーバーに接続され、読み取り可能なデータがあるクライアントを取得 if (client) {//クライアントの情報が取得出来た場合(クライアントに対しサーバーが開かれている場合) Serial.println("New Client."); String currentLine = "";//クライアントから得たデータを格納するための文字列を用意 while (client.connected()) { // client.connected()は接続時True,切断時Falth if (client.available()) { // client.available()は読み込み可能なバイト数(接続先のサーバーによってクライアントに書き込まれたデータの量)を返す char c = client.read(); //クライアントから送信されたデータを1バイトだけ読み取る if (c == '\n') { // 読み取った文字が改行コード(/n)だった場合 Serial.print("クライアントからのメッセージ: "); Serial.println(currentLine);//改行コードまでのメッセージを出力 message = "hello,client! by server"; client.print(message);//クライアントへメッセージを送信 client.stop();//サーバーとの接続を切断 Serial.println("Client Disconnected."); } else if (c != '\r') { // 受け取った文字が改行コードではない場合(普通の文字の場合) currentLine += c; //変数currentLineに受け取った文字を追加する } } } } }
ESP32スケッチの説明
上で示したスケッチについて簡単に説明します。
まずスケッチの最初の部分について。
//#ESP32-PC間通信用プログラム(ESP32側) //ライブラリのインクルード #include <WiFi.h> const char* ssid = "yourSsid";//適宜ルーターのSSIDに書き換えてください const char* password = "yourPassword";//適宜ルーターのパスワードに書き換えてください WiFiServer server(5000);//ポート番号5000でサーバーとして使用する String message; String oneLetter;
の部分では、スケッチ内で使用するWifiライブラリや各種変数の定義を行います。
ネットワークのssidやパスワードもここで設定します。
次に、setup関数の中身について説明します。
void setup() { Serial.begin(115200);//ビットレート115200でシリアル通信を開始 Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid);
の部分では、シリアル通信を開始し、ESP32の接続情報をシリアルモニタ上に表示する準備を行っています。
次に、
WiFi.begin(ssid, password);//アクセスポイントに接続
でESP32をネットワークに接続します。
while (WiFi.status() != WL_CONNECTED) {//接続が完了しない場合"・"を打って待機 delay(500); Serial.print("."); }
の部分では、ESP32がネットワークに接続されるのを待ちます。ネットワークに接続されると、変数WiFi.status()の値が WL_CONNECTEDになります。
その後、
//接続が完了したら以下の内容を表示 Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP());//自身のIPアドレスを表示 server.begin();//サーバー開始 }
の部分で、ネットワークへの接続が完了したことと、自身のIPアドレスをシリアルモニタ上に表示します。最後に server.begin()とすることで、ESP32はサーバとして動作し始めます。
|
次にloop関数の中身について説明します。
WiFiClient client = server.available();
の部分では、サーバに接続してきたクライアントの情報を変数clientに格納します。
次に、
if (client) {//クライアントの情報が取得出来た場合 Serial.println("New Client."); String currentLine = "";//クライアントから得たデータを格納するための文字列を用意
の部分では、if (client)という条件分岐があります。これは、新たにサーバーに接続してきたクライアントがいた場合のみ、以降の処理を行う、という意味です。
変数String currentLineは、サーバクライアント間でメッセージをやり取りするために用意された空の文字列です。
その後、
while (client.connected()) { // client.connected()は接続時True,切断時Falth if (client.available()) { // client.available()は読み込み可能なバイト数(接続先のサーバーによってクライアントに書き込まれたデータの量)を返す char c = client.read(); //クライアントから送信されたデータを1バイトだけ読み取る if (c == '\n') { // 読み取った文字が改行コード(/n)だった場合 Serial.print("クライアントからのメッセージ: "); Serial.println(currentLine);//改行コードまでのメッセージを出力 message = "hello,client! by server"; client.print(message);//クライアントへメッセージを送信 client.stop();//サーバーとの接続を切断 Serial.println("Client Disconnected."); } else if (c != '\r') { // 受け取った文字が改行コードではない場合(普通の文字の場合) currentLine += c; //変数currentLineに受け取った文字を追加する
の部分はサーバクライアント間の通信が維持されている場合のみ実行します。
この部分ではクライアントから送られてきたメッセージを受信し、シリアルモニタ上に表示するまでの一連の処理を行います。
なお、今回はクライアントからサーバーへ送信するメッセージの末尾に改行コード("\n")を付け加えることで、メッセージの文末が分かりやすいような工夫がされています。
まず、サーバーはクライアントから送られてきたデータを先頭から1バイトずつ読み取っていき、読み取った文字が通常の文字であれば変数currentLineに加えます。
これをくり返し行うことでメッセージを1文字ずつ読み込み、メッセージの文末を表す改行コード"\n"が読み込まれたところで、変数currentLineの中身をシリアルモニタ上に表示します。
この部分を説明した図を作成したので下に載せておきます。
最後に、メッセージの受信が無事に行えたことをクライアントに伝えるために、
message = "hello,client! by server"; client.print(message);//クライアントへメッセージを送信
の部分でクライアントへメッセージを送信し、
client.stop();//クライアントとの接続を切断
でクライアントとの通信を切断します。
pythonプログラム(クライアント側)
クライアントとして、次のようなpythonプログラムを使用しました。
#ESP32-PC間通信用プログラム(PC側) #socketライブラリをインポート import socket ip_address = '192.168.10.115' #サーバー(ESP32のIPアドレス) port = 5000 #ポート番号 buffer_size = 4092 #一度に受け取るデータの大きさを指定 recieve_message = "" recieve_status = True #クライアント用インスタンスを生成 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # サーバーに接続を要求する(IPアドレスとポート番号を指定) client.connect((ip_address, port)) # サーバにデータを送信する message = input("送信するメッセージを入力してください\n→") message += "\n"#文末に改行コードを追加 client.sendall(bytes(message, encoding='ASCII'))#文字列をバイトに変換し送信(文字コードはASCIIを使用) print("サーバーへデータ送信") #サーバーからの応答を受信 data = client.recv(buffer_size) #サーバから送られてきたデータを読み取り(上限4092ビット) print("サーバからのメッセージ") print(data.decode())#受け取ったデータ(バイト形式)を読める形式にデコードして表示 #通信を終了 client.close() print("ソケット通信を終了")
python用プログラムの説明
import socket
の部分で、今回用いるsocketライブラリをインポートします。
socketライブラリは、今回用いるソケット通信を行うために必要なライブラリです。
ソケット通信は通信方法の一種で、簡単に言えば、相手のIPアドレスとポート番号を指定して通信を行う方法のことです。
これは私たちが郵便物を送る際に送り先の住所と郵便番号を記入するのと似ていますね。
次の部分では、各変数の設定を行っています。
ip_address = '192.168.10.115' #サーバー(ESP32のIPアドレス) port = 5000 #ポート番号 buffer_size = 4092 #一度に受け取るデータの大きさを指定 recieve_message = "" recieve_status = True
ipアドレスの欄は、適宜お使いのESP32のipアドレスに変更してください。
その他の変数については、特に変更する必要はありません。
次の部分、
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
では、socketクラスのインスタンスを生成しています。
また、インスタンスを生成する際に引数を2つ与える必要があり、ここでは通信に用いるプロトコルの指定を行っています。
この部分に関して詳しく解説してある記事があったので、リンクを載せておきます。
次に、サーバーに接続を要求するために、
client.connect((ip_address, port))
とします。
サーバーとの接続が確立されたら、いよいよサーバに向けてメッセージを送る処理に入ります。
メッセージを送信する処は次のようになります。
message = input("送信するメッセージを入力してください\n→") message += "\n"#文末に改行コードを追加 client.sendall(bytes(message, encoding='ASCII'))#文字列をバイトに変換し送信(文字コードはASCIIを使用) print("サーバーへデータ送信")
まずinput関数を用いてサーバーへ送信するメッセージを決定したのち、メッセージの文末に改行コード"\n"を付け加えておきます。
これは上でも解説したように、メッセージを受信したときにメッセージの文末がどこなのかを簡単に判別できるように付け加えられています。
その後、client.sendall(bytes(message, encoding='ASCII'))とすることで、接続先のサーバーに変数messageの中身を送信します。
なお、引数のencoding='ASCII'は、送信時に使用する文字コードとしてASCIIを選択するために与えています。
その後、サーバーから送られてくるメッセージを受け取るために、
data = client.recv(buffer_size) #サーバから送られてきたデータを読み取り(上限4092ビット) print("サーバからのメッセージ") print(data.decode())#受け取ったデータ(バイト形式)を読める形式にデコードして表示
という処理を行います。
サーバから送られてくるメッセージは、そのまま読める文字ではなくバイト形式で送られてくるので、print(data.decode())とすることで、バイト形式から読める形式に変換してから、コマンドプロンプト上に出力します。
最後に
client.close()
として、サーバーとの通信を切断します。
実行例
まずはESP32をネットワークに接続します。
ネットワークのssidとパスワードが正しく入力されていれば、電源投入時に自動でネットワークに接続します。
接続が完了すると、ESP32に割り当てられたIPアドレスがシリアルモニタに表示されます。
次にクライアント側として機能するpythonプログラムを起動します。
プログラムを起動すると、送信するメッセージの入力受付画面となるので、メッセージを入力しEnterを押します。
その後、メッセージがサーバーに正常に送られると、サーバーからの返信がコマンドプロンプトに表示されます。
この時、ESP32のシリアルモニタには、クライアントから送られてきたメッセージが表示されます。
以上をもって、ESP32-python間でwifi経由でメッセージをやり取りすることができました!
まとめ
今回は、wifi経由でESP32-python間のメッセージのやり取りを行う方法について紹介しました。
今回は文字の送受信のみ行いましたが、これを応用すれば、pythonプログラムからLEDやモーターなどの電子部品を動かすことも可能です。
今回の記事で不明な点があったらお気軽にコメント欄等からご質問ください!