MENU

ESP32:UDPでセンサー値(変数)を送信し、Pythonで受信する

ESP32 → PC(RaspberryPi)一方向のUDP WiFi通信を行います。

記事の内容
  • ESP32のセンサー値をUDPを用いて取得する
  • UDP取得文字列のデータ整形について
  • char型のuint8_t変換について
こんな人向け
  • C++でのchar→uint8_t変換例を見たい方
  • ESP32のUDPの参考例が見たい方
目次

ESP32回路

以下の記事の回路を流用しています。

コード

ESP32(UDPデータ送信側)

コード全文

変更点

UDPライブラリの追加
#include <WiFiUDP.h>

WiFiUDP wifiUdp;
const char *kRemoteIpadr = "192.168.1.100"; //送信先IP
const int kRmoteUdpPort = 9998;             //送信先のポート
解説

UDPを使用するために、ライブラリ「WiFiUDP.h」を使用します。

インスタンスの作成及び、送信先のIP及びポートを設定します。

UDP送信部

179行以降

  //UDP設定
  wifiUdp.beginPacket(kRemoteIpadr, kRmoteUdpPort);
  //payload convert to type uint8_t
  //wifiUdp.write type uint8_t only >_<
  std::string str = payload;
  uint8_t arr[sizeof(payload)];
  std::copy(str.begin(), str.end(), std::begin(arr));
  wifiUdp.write(arr, sizeof(arr));
  wifiUdp.endPacket();
解説

UDP送信データはWiFiUDP.write(uint8_t byte) もしくは WiFiUDP.write(buff, size) と記述します。

このことから、charをuint8_t型に変換しています。

何故これで動くのか理解出来ていませんが、結果や過程を追うと嵌りそうだったので今回は流してます。

コードは下記のstack overflowを参考にしました。

Stack Overflow
Converting a string to uint8_t array in C++ I want an std::string object (such as a name) to a uint8_t array in C++. The function reinterpret_cast<const uint8_t*> rejects my string. And since I'm co...

また、固有の文字列を送信する場合はこの様に書くことも出来ます。

ただし、これも何故uint8_t型に文字列が代入出来るのか理解できていません。C++って難解😰

  //UDP設定
  wifiUdp.beginPacket(kRemoteIpadr, kRmoteUdpPort);
  //payload convert to type uint8_t
  //wifiUdp.write type uint8_t only >_<
  //std::string str = payload;
  //uint8_t arr[sizeof(payload)];
  //std::copy(str.begin(), str.end(), std::begin(arr));
  //wifiUdp.write(arr, sizeof(arr));
  uint8_t message = "messageだよ!"
  wifiUdp.write(message);
  wifiUdp.endPacket();

PC、RaspberryPi(UDPデータ受信側)

以下のコードを実行することで各種センサー値を入手出来ます。

RaspberryPiの使用を見越し、言語は「Python」を使用しています。

解説

生UDP文字列は以下のようになるため、データの整形が必要となります。

b'{"temp":28.7,"humd":62.6,"dist":11.3}\x00\x00\xff\x04\xd4\r\x80\x90\x1f\xfb?\xcc\x17\xfc?O\xfea\x04\x9d\x1d\r\x80p\x1f\xfb?\x98#@?\x00\x00\x00\x00\xe8\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xfc?'
STEP
str_data = data.decode(“utf-8″, errors=”ignore”)

「無理やり」デコードし、bytes型から「utf-8」の文字列にしています。

errors=”ignore”オプションを用いることで「強制的」に変換しています。

これにより、b'”が取れます。

STEP
str_data = str_data[:str_data.find(‘}’)+1]

UDPでの取得文字列の「}」以降はゴミなので除去します。

PythonはC++に比べ、文字列操作が直感的にわかるので有り難い。

あわせて読みたい
Pythonで特定の文字以降を削除する:Python str型のfind、split、partitionメソッドを使って特定の文字以降を削除するPythonのコードをご紹介しています。

受信側実行結果

Send from ESP ('192.168.1.155', 7778) - {"temp":28.4,"humd":69.8,"dist":36.8}
-----------------

temp: 28.4
humd: 69.8
dist: 36.8
210822
070014
-----------------

センサーの値、データ取得時の時間情報(最下部2行の数列)が出力できました。

これにより、csvで保存しロガーとしたり、値をトリガーにプログラムを実行するなど活用出来そうです。

まとめ

C++の理解が乏しく、uint8_t型への変換に戸惑ったが動かすことが出来た。

UDP受信時の値取得失敗時の処理が必要かも知れないが、問題が出た際に対応しよう。

参考記事まとめ

C++:char、及びfloat型をuint8_t型に変換する方法

Stack Overflow
Converting a string to uint8_t array in C++ I want an std::string object (such as a name) to a uint8_t array in C++. The function reinterpret_cast<const uint8_t*> rejects my string. And since I'm co...

Python:文字列を辞書型に変換する

Qiita
python3 文字列を辞書に変換 - Qiita 個人メモとして。 やりたいこと 以下の文字列をそのまま辞書にしたい。 str = "{'名前':'太郎', '身長':'165', '体重':'60'}" やったこと astモジュールを利用する...
シェアしてくださいな
目次
閉じる