UARTおじさんの帰還

※ この記事は極めて偏った超保守的思想で書かれています。

BLEとはなんぞやというような話は2010年代にさんざん聞かされたし、その概念が分からないわけではないけども、ゼロベースで素直に考え直せばUART/SPPのほうが適しているケースも多いのです。

しかしそうは言ってもコスト面の問題があります。UARTおじさん御用達のRN42が2000円以上するのに対してBLEモジュールは1000円を切ることもあります。

そこでM5Stamp Picoですよ! こいつはSPPもできて800円台ですから。
UARTおじさんはRN42の代替にM5Stamp PicoでSPPやろうぜ!
(量産に使えるかはさておき。あと消費電力の問題もあるけど。)

f:id:licheng:20211125193935j:plain:w640

サンプル

UARTとSPPをブリッジするArduinoスケッチ

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32");
  delay(500);
}

void loop() {
  if(Serial.available()){
    SerialBT.write(Serial.read());
  }
  if(SerialBT.available()){
    Serial.write(SerialBT.read());
  }
}

補足

WebSocketみたいな迂遠で珍妙なプロトコルを平気で使っていながらBLEで16進文字列を送ることを非難するのはダブルスタンダードだと思ってます。もっとも、ちょっと大きめのデータを送ると破綻するようなオレオレなんちゃってBLEシリアル通信は論外です。若者はJSONが好きなので、SPPでシリアル通信すれば良いと思います。

メカナムホイールのトイラジコンを分解してみた

アマゾンで5000円で売ってるメカナムホイールのトイラジコンを分解してみました。
驚くべきことに各軸にエンコーダ(ただし一相)がついています。

開封の儀

コンパクトでわりと品位の良い箱なので、捨てずに収納ボックスとして使うのがよさそう。

f:id:licheng:20211120153834j:plain:w600

内容物は、ラジコン本体、コントローラ、18500 Li-ion電池 (3.7V 1200mAh) × 2本 (1本で駆動、1本は予備)、充電器、充電ケーブル(電池を本体に入れたまま充電できるUSBケーブル)、説明書(日本語)、+ドライバ。

f:id:licheng:20211120153843j:plain:w600

ちょっと走らせて遊んでみましたが、メカナムホイール楽しいですね。トイラジコンなのでやたらピカピカLEDが光ったり効果音やら謎のBGMが流れたりします。

さっそく分解

さっそく分解しました。メイン基板1枚に電池とモータとLEDとスピーカが接続されています。トイラジコンによくあるかんじです。RFはメイン基板と一体のようです。

f:id:licheng:20211120153852j:plain:w600

さらに分解を進めるとモータユニットがゴロっと取り外せました。おや? 線の数が多いですね。

f:id:licheng:20211120153901j:plain:w600

なんとエンコーダつき!?

なんとフォトインタラプタ式のロータリーエンコーダが入っています。ただし1相。なので回転量は取れますが回転方向は分かりません。まあ、モータを回そうとしている方向に回ってるはずだという推定で使うのでしょう。ケーブルは赤が3.3V、黒がGND、黄色と緑がフォトダイオードのカソード、あるいはフォトトランジスタのコレクタのようです。(動作は未確認です。) あと、青と白がモータです。

f:id:licheng:20211120153920j:plain:w600

メカナムホイール

メカナムホイールは外径6mmの六角シャフトにネジで固定されています。ホイールの直径は実測で約52mm、ホイールベース長は約127mm、トレッド幅は約90mmです。ちなみに製品仕様によると全長225mm、全幅115mm、全高110mmです。

f:id:licheng:20211120153933j:plain:w600

感想

これで5000円はめちゃくちゃ安い。もしもエンコーダがちゃんと2相だったら神でしたが、まあじゅうぶんハックしがいのありそうな内容です。ドライバーのフィギュアをどければ運転席のスペースが空くので、お好みのマイコンボードを載せることができるでしょう。

おまけ

メイン基板に乗ってるICを調べてみる。

f:id:licheng:20211127152427j:plain:w600

  • 右側にある2個の16ピンのICは、DCモータドライバ MX1616。Hブリッジ2回路入り。
  • 中央左寄りにある24ピンのICは、型番刻印なし。マイコンと思われる。
  • 左下のアンテナの近くにある8ピンのICは、2.4GHz GFSKトランシーバ XN297。
  • 中央下寄りにある8ピンのICは、録音IC ZC25P040。スピーカに接続されており効果音用と思われる。
  • 上部中央の8ピンのICは、汎用ロジックの6ビットバッファ TC4056。

マイコンと汎用ロジック以外は謎の中華ICばかり。こういう謎の半導体メーカーがゴロゴロ存在する中国のモノづくりすごいなと思う。

ギリシャ正教1ミリも知らない仏教徒が「アグニ・パルセネ」を和訳してみた

ギリシャ語の聖歌「アグニ・パルセネ」を和訳してみた。先入観を抱かないようになるべく英訳は見ずに難解な箇所のみ参考にした。(そもそもWikipediaにある英訳はぜんぜん原文に忠実でない気がする。)

Αγνή Παρθένε Δέσποινα, Άχραντε Θεοτόκε,
純潔の乙女よ、貴婦人よ ※1、穢れなき神産みの御方よ ※2

Παρθένε Μήτηρ Άνασσα, Πανένδροσε τε πόκε. ※3
乙女にして母なる女王よ、まるごと露を含んだ羊毛よ ※4

Χαίρε Νύμφη Ανύμφευτε.
歓べ 未婚の花嫁よ

Υψηλοτέρα ουρανών, ακτίνων λαμπροτέρα, ※5
天空よりもなお高く、陽射しよりもなお輝かしく

Χαρά παρθενικών χορών αγγέλων υπερτέρα. ※6
天使たちの合唱にもなお勝る乙女の歓びよ

Χαίρε Νύμφη Ανύμφευτε.
歓べ 未婚の花嫁よ

Εκλαμπροτέρα ουρανών, φωτός καθαροτέρα, ※7
天空よりもなお輝きを放ち、陽の光よりもなお澄みきって

Των ουρανίων στρατιών πασών αγιωτέρα.
天空の軍団その全てよりもなお聖なるかな

Χαίρε Νύμφη Ανύμφευτε.
歓べ 未婚の花嫁よ

「アグニ・パルセネ」の動画

ラトビア人の歌手 Aleksandra Spicberga さんによるギリシャ語とラトビア語による「アグニ・パルセネ」の歌唱。前半がギリシャ語だが、発音が現代ギリシャ語音とちょっと違うようだ。でも古典ギリシャ語音でもない。まあ、ラテン語の発音もイタリア式やらドイツ式やらあるし、そんなかんじかな?


※1 カトリックなら「聖母マリア」と訳すが、ここではその訳語は使えない。他の案としては、姫様、ひめみこ様、姫御前様、女領主様など、いずれも苦しい。
※2 正教会ではテオトコスを「生神女」と訳すらしいが、あまりに耳馴染みの無い訳語である。「神の母」という訳もあるが、ここでは原語に沿って「神産みの御方」とした。しかし「神産み」という語はイザナミノミコトを連想させてしまうかもしれない。
※3 「まるごと露を含んだ羊毛」というのは唐突で意味不明に感じるが、これは『旧約聖書』の『士師記』に記された士師ギデオンの故事をふまえたもののようだ。キリスト教では露を含んだ羊毛はマリアの処女受胎を象徴するらしい。
※4 πανένδροσε という語は辞書に見当たらないが、 παν + έν + δροσε で「全く露の中の(=まるごと露を含んだ)」の意味と解釈した。
※5 ~τέρα という語尾が頻出するが、これは形容詞の比較級の語尾。
※6 構文がよく分からない。「Χαρά παρθενικών」を「乙女の喜び」と訳してみたが、παρθενικών が複数形なのが解せない。
※7 εκλαμπροτέρα という語は辞書に見当たらないが、εκ + λαμπροτέρα で 「外に輝く (=輝きを放つ)」の意味と解釈した。

なんかよく分からんけどWebアプリをAzureにデプロイするまで (後編)

前回は開発フローの確立までをやった。今回は肝心のWebアプリの中身を作っていく。

作りたいWebアプリ

f:id:licheng:20211111230348p:plain:w500

静的なHTMLファイルのホスティング

前回はpugという謎のテンプレートからHTMLを生成するアプリを作ったが、ぶっちゃけ今回作りたいものは静的なHTMLファイルのホスティングで事足りるので、pugとかよく分からんものは使いたくない。そのような場合、最初のひな型生成の時の引数で --no-view を指定すればよいらしい。(詳しくはこちらのドキュメント)

npx express-generator myExpressApp --no-view

そうするとpugファイルを含むviewフォルダは生成されず、かわりに /public/index.html ファイルが生成される。エディタで開いてみると、ごくふつうのHTMLファイルである。こういうのでいいんだよ。

このHTMLファイルを自作のフロントエンドの index.html で置き換える。アプリを実行してブラウザで開いてみると、この index.html が表示された。これで静的なHTMLファイルのホスティングはできた。

Expressは何をしているのか?

なんか便利らしいのでExpressを使うことにしたが、こいつが何をやっていてどう使えばいいのかよく分からない。同じような思いを持った先人の記事が参考になった。

さっきの静的ファイルのホスティングに関しては生成された app.js の15行目に該当する記述がある。
(詳しくはこちらの記事)

app.use(express.static(path.join(__dirname, 'public')));

処理1: Web APIリクエストの受け付けとレスポンスの返信

今回はPOSTでJSON形式のリクエストを受け付け、JSON形式のレスポンスを返すAPIとする。

あるエンドポイントへのリクエストに対するレスポンスの返信は次のような形で書ける。(抜粋)

app.use(express.json());
app.use(express.urlencoded({ extended: false}));
app.post('/エンドポイント/', (req, res) => {
  req.body (=リクエストのボディ)を処理;
  var res_obj = レスポンスのオブジェクト;
  res.json(res_obj);
});

返信は文字列を返すなら res.send を、オブジェクトをJSON文字列に変換して返すなら res.json を使う。

またPOSTでなくGETの場合は、パスパラメータを取得するなら req.params を、クエリパラメータを取得するなら req.query を用いる。

処理2: Web APIリクエストの発行とレスポンスの受け取り

こちらも今回はPOSTでJSON形式のリクエストを発行し、JSON形式のレスポンスを受け取るAPIとする。

requestパッケージを用いてWeb APIリクエスト処理を実装する。じつはこの request というのはすでに非推奨のパッケージらしいのだが、ひとまずこれで実装することにする。

インストールは下記のコマンドでおこなう。ちなみに npm はデフォルトではカレントディレクトリの下の node_modules ディレクトリにパッケージをローカルインストールする。グローバルにインストールしたい場合にはオプション -g を指定する。ローカルにインストールしたパッケージに関する情報は package.json と package-lock.json に記録される。

npm install request

Web APIリクエスト処理は次のような形で書ける。(抜粋)

const request = require('request')

var req_obj = リクエストのオブジェクト;
const options = {
    method: 'POST',
    url: 'https://Web APIサーバのURL',
    headers: {
      'Content-type': 'application/json',
      'Authorization': 'API認証キー',
    },
    json: req_obj
}
request(options, (error, response, body) => {
    body (=レスポンスのボディ)を処理;
});

Web APIの中継 = 処理1 + 処理2

前述の処理1と処理2を合体させればWeb APIの中継サーバができる。
これは次のような形になる。(抜粋)

const request = require('request')

app.use(express.json());
app.use(express.urlencoded({ extended: false}));
app.post('/エンドポイント/', (req, res) => {
    const options = {
        method: 'POST',
        url: "https://Web APIサーバのURL",
        headers: {
          'Content-type': 'application/json',
          'Authorization': 'API認証キー',
        },
        json: req.body
    };
    request(options, (error, response, body) => {
        res.send(body);
    });
});

これらのコードは下記の記事を参考にした。

整理

app.js を見て不要そうなものを削除する。

  • public/style.css は使わないなら削除する。
  • indexRouter とか usersRouter とかは今回は不要っぽいので関連する記述を削除し、
    routesフォルダのファイルはフォルダごと削除する。
  • cookieParser も今回はクッキーを使用しないので不要っぽいので関連する記述を削除し、
    下記のコマンドで cookie-parser をアンインストールする。
npm uninstall cookie-parser

これでほぼミニマムな構成になった。

バージョン管理について

前述のように node_modules はnpmのパッケージをローカルインストールするフォルダなのでバージョン管理から除外する。さもないと大量のファイルがリポジトリに入ってしまう。必要なパッケージに関する情報は前述のように package.json と package-lock.json に記録されているので、この2つはバージョン管理に含める。

また、.vscode/settings.json をバージョン管理に含めるか否かは運用しだいかなと思う。Azure App Serviceのフォルダの場合、.vscode/settings.json の中にデプロイ先の情報が記述されているので要注意。

.gitignoreの例

node_modules/
.vscode/

リモート環境へのSSHログイン

デプロイしたAzureのリモート環境にSSHでログインしてコマンド操作したい場合、ブラウザで下記のようなURLにアクセスする。するとブラウザ上でターミナルが開く。(詳しくはこちらのドキュメント)

https://アプリ名.scm.azurewebsites.net/webssh/host

所感

  • 関数型っぽい書き方に慣れが必要。(本質的にはC言語の関数ポインタでコールバック関数を渡すのと同じことなのだけども。)
  • JavaScriptは関数の引数にも戻り値にも型宣言が無いので、どんな形で渡してどんな形で返ってくるか分からず困ることが多い。

はてなブログ内の画像を一括ダウンロード (Linux/Macコマンド使用)

こちらの記事を参考にLinuxコマンドラインでやってみた。たぶんMacでもできるはず。

(1) はてなブログのデータをエクスポート

はてなブログの「設定(スパナのアイコン)」→「詳細設定」の下のほうの「エクスポート / 記事のバックアップと製本サービス」でエクスポートしてダウンロードする。(MovableType形式のテキストファイルで書きだされる。)

(2) はてなフォトライフの画像のURLを抽出

はてなフォトライフの画像のURLは例えば下記のようなものである。
fotolife/」以降は「頭文字/ユーザ名/数字/数字.拡張子」の形式のようだ。

https://cdn-ak.f.st-hatena.com/images/fotolife/l/licheng/20211111/20211111230348.png

このような文字列を抽出してファイルに出力するには下記のコマンド(1行)を実行する。
ここで export.txt はエクスポートしたテキストファイルとする。
抽出したURLは list.txt に書き出される。

cat export.txt | grep https://cdn-ak.f.st-hatena.com/images/fotolife | sed -r "s/^.*(https:\/\/cdn-ak\.f\.st-hatena.com\/images\/fotolife\/l\/licheng\/[0-9]*\/[0-9]*\.[a-z]{3}).*$/\1/" > list.txt

(3) 一括ダウンロード

list.txt に書き出されたURLのファイルをダウンロードするには下記のコマンドを実行する。
ここで dl_folder はダウンロード先のフォルダ名とする。

wget -nc -P dl_folder -i list.txt

または、URLのディレクトリ構造どおりに保存したいなら下記のコマンドを実行する。

wget -nc -x -i list.txt

ダウンロードされるファイルの数は list.txt の行数よりかなり少ない。これはダブりを除外しているためである。記事ごとにアイキャッチ画像が指定されているため、必ずダブりが発生する。

参考

なんかよく分からんけどWebアプリをAzureにデプロイするまで (前編)

Web系ぜんぜん分からん組込み系のオッサンがなんかよく分からんけどやってみたメモ。
下記の公式サイトのチュートリアルをもとにやってみた。

ローカルにNode.jsをインストールする

なんかよく分からんけど、とりあえずローカルのPC上で動くNode.js環境を作る。僕はドザー(死語)なので、Windows版のインストーラNode.jsの公式サイトからダウンロードしてインストールしてもよいのだけど、この先DOS窓で作業するのはツラそうなので、WSLのUbuntu(詳しくはこちらの記事)にインストールすることにする。(PowerShellなにそれおいしいの?)

sudo apt update
sudo apt install nodejs
sudo apt install npm
node --version

しかし、node --version でバージョンを確認してみるとv10と、ちょっと古かった。そこで n をインストールして特定バージョン(今回はv14)のnode.jsをインストールし直し、最初にインストールしたnode.jsとnpmはアンインストールし、ログインし直す。改めてバージョンを確認するとv14になっていた。(詳しくはこちらの記事)

sudo npm install n -g
sudo n v14
sudo apt purge -y nodejs npm
exec $SHELL -l
node --version

あと、ファイルはWindows側に置いておいたほうが便利が良さそうなので、例えばドキュメントフォルダへのシンボリックリンクを張っておく。

ln -s /mnt/c/Users/ユーザ名/Documents ~/documents

ああ、でもファイルをWindows側(NTFS)に置いちゃうとパーミッションが全部777になっちゃうし、シンボリックリンクを作られるとWindowsからは空のファイルに見えちゃうのが難点。悩ましいところで正解が分からんけども、とりあえずこれで進める。

Express + Node.js でローカルにアプリのひな型を作る

なんかよく分からんけど、ExpressとかいうNode.jsのフレームワークを使うと簡単にWebアプリができるらしい。Webアプリのひな型を生成するために、テキトーなディレクトリに移動して次のコマンドを実行する。npx を使うと、よかろうで必要なものをインストールしてくれるらしい。ここで myExpressApp は任意のアプリ名とする。

npx express-generator myExpressApp --view pug

すると、myExpressApp というディレクトリができ、ここにWebアプリのひな型が生成されるようだ。このディレクトリに移動して npm install を実行すると、なんかよく分からんけどアプリがインストールされる?

cd myExpressApp 
npm install

ここで「found n vulnerabilities (n個の脆弱性が見つかった)」というメッセージが出た場合は npm audit を実行して指示されたコマンドを実行する。(例えば「Run npm install pug@3.0.2 to resolve 2 vulnerabilities」のようなメッセージが出る。) そしてnpm install を実行し直す。

npm audit
sudo npm install pug@3.0.2    # 脆弱性対策の一例
npm install

インストールできたら npm start でアプリを起動する。(停止はふつうに Ctrl+C で。)

npm start

ブラウザで http://localhost:3000 にアクセスして「Express Welcome to Express」と表示されたら成功。

VS CodeのAzure App Service拡張機能をインストール

さすがにAzureへのデプロイの操作をコマンドライン(Azure CLI)でやるほどストイックな人間ではないので、VS Code拡張機能を利用することにする。(コマンドラインでやりたい硬派な人はこちら)

「Azure」で検索すれば「Azure App Service」という拡張機能がすぐ見つかるのでこれをインストールする。

f:id:licheng:20211109214252p:plain

Azure へのデプロイ

さっきローカルに作ったアプリのディレクトリ(例では myExpressApp)で code . を実行するとVS Codeが起動してアプリのディレクトリが開く。または、VS Codeのメニューの File → Open Folder で アプリのディレクトリを開いても良い。「Do you trust the authors of the files in this folder?」とか聞かれたらYesで。

code .

なんかよく分からんけど、さっきAzure App Service拡張機能をインストールしたので、VS Codeの左端にAzureのアイコンが追加されている。ここをクリックして、「Sign in to Azure」を選択。(組込み系のオッサンはメニューの日本語化などせぬのである。必要ないし、トラブったときに英語の方がググラビリティが良い。)

f:id:licheng:20211109232647p:plain

するとブラウザに飛んでアカウント選択画面になる。ここでサインイン済みのアカウントを選択すると「You are signed in now and can close this page.」と表示されるので、この画面は閉じてVS Codeに戻る。すると作成済みのサブスクリプションが表示される。(なんの手違いかサブスクリプションが2個できてしまっているが、よく分からん。)ここで雲のアイコンをクリックしてWebアプリのデプロイに進む。

f:id:licheng:20211109231856p:plain

(そもそもデプロイってどういう意味かよく分からんけど、まあアプリをAzureにアップロードして実行するってことやろ、知らんけど。)

デプロイまでの手順
  • フォルダの選択: 今開いているフォルダを選択。
  • サブスクリプションの選択: 作成済みのサブスクリプションを選択。(※1)
  • Webアプリの選択:「Create new Web App... Advanced」を選択。
  • Webアプリの名前を入力: グローバルにユニークな名前を付ける。
  • リソースグループの選択: なんかよく分からんけど新しいリソースグループを作成する。(※2)
  • ランタイムの選択: 今回はNode.js v14のアプリなので「Node 14 LTS」を選択。
  • OSの選択: とりあえずまあ「Linux」を選択。
  • ロケーションの選択: わいは「Japan West」やで。
  • Linux Appサービスプランの選択: なんかよく分からんけど新しく作成する。
  • 価格レベルの選択: とりあえずまあ「Free(F1)」か「Basic(B1)」で。
  • Application Insightsリソースの選択: なんかよく分からんけど、今回はスキップする。

すると、Webアプリのデプロイが始まる。「Always deploy the workspace "フォルダ名" to "アプリ名" ?」と聞かれたら Yes で。Webアプリのデプロイが完了したらポップアップ表示されるので、「Browse Website」をクリックする。ブラウザが開いて、ローカル環境と同様に「Express Welcome to Express」と表示されたら成功。 URLは https://アプリ名.azurewebsites.net/ となる。

※1 ※2:サブスクリプションとかリソースグループとか、公式のドキュメント読んでもなんか分からんけど、こちらの記事にざっくりした解説があった。

アプリを変更して再デプロイする

アプリを試しにちょこっと変更してみる。myExpressApp/views/index.pug を開いて「p Welcome to #{title}」と書かれてあるのを「p Welcome to Azure!」に書き換えてみる。この index.pug ていうファイル、謎言語の謎ファイルだけども、どうやら index.html を生成するテンプレートらしい。

ローカルでアプリを起動してブラウザで再び http://localhost:3000 にアクセスすると今度は「Express Welcome to Azure!」と表示される。

VS Codeで再びAzure App Service拡張機能の雲のアイコンをクリックして再デプロイする。完了通知のポップアップで「Browse Website」をクリックし、ローカルと同様に表示が変わっていたら成功。

ひとまずこれで、「Webアプリをローカルで作成→動作確認→Azureにデプロイ→動作確認→ローカルに戻って変更→以降繰り返し」の流れができた。よく分からんけど。

所感

  • なんかよく分からんけど、頼りになるのはLinuxコマンドの教養である。
  • マイクロソフトのドキュメントは、かなり行間を読まないといけない。


後編につづく

ノート:ESP32(Arduino core)でWebサーバ&WebSocketサーバ

(1) Webサーバ

(1.1) ライブラリのインクルードとオブジェクトの定義

Arduino core for the ESP32に含まれるライブラリを使用する。
ポート番号を指定してオブジェクトを定義する。

#include <WebServer.h>

WebServer webServer(80);
(1.2) 初期化 (setup()での処理)

URLごとのコールバック関数を設定し、Webサーバを開始する。

  webServer.on("/", func_handleRoot);
  webServer.on("/index.html", func_handleRoot);
  webServer.onNotFound(func_notFound);
  webServer.begin();
(1.3) ループ処理 (loop()での処理)

loop()内で必ずhandleClientメソッドを呼ぶこと。
すなわち、loop()を他の同期処理などで止めてはならない。

  webServer.handleClient();
(1.4) リクエスト受信

リクエスト受信があると、初期化時に設定したコールバック関数が呼ばれる。
そこでクエリパラメータを取得できる。

  // パラメータの個数をチェック
  if(webServer.args() > 0){
    // 特定のパラメータがあるかチェック
    if (webServer.hasArg("hoge")){
      // パラメータの値を取得
      String val = webServer.arg("hoge");
    }
  }

また、リクエストのURLやメソッド、パラメータ名は下記のようにして取得できる。

  String uri = webServer.uri();
  HTTPMethod method = webServer.method(); // HTTP_GET, HTTP_POST など
  String argName = webServer.argName(0); // 最初のパラメータ名
(1.5) レスポンス送信

必要ならばHTTPヘッダを設定する。
HTTPステータスコード、コンテンツタイプ、コンテンツを指定してレスポンスを送信する。

  String message = "ほげほげ";
  webServer.sendHeader("Cache-Control", "no-cache");
  webServer.send(200, "text/plain", message);

ファイルを送信する場合にはSPIFFSライブラリを併用する。
ファイルを開き、コンテンツタイプを指定して送信し、最後にファイルを閉じる。

#include <FS.h>
#include <SPIFFS.h>
…
  File file = SPIFFS.open("/index.html", FILE_READ);
  size_t sent = webServer.streamFile(file, "text/html");
  file.close();

ファイルはアップローダーを使ってESP32に書き込む。アップローダーは下記ページからダウンロードできる。ZIPを解凍してArduoinoのtoolsフォルダに配置しておく。スケッチフォルダ内にdataフォルダを作成してそこに書き込みたいファイルを配置し、ツール → ESP32 Sketch Data Upload で書き込む。

【参考】

(2) WebSocketサーバ

(2.1) ライブラリのインクルードとオブジェクトの定義

WebSocketサーバはarduinoWebSocketsライブラリをGitHubからダウンロードして使用する。
ポート番号を指定してオブジェクトを定義する。

#include <WebSocketsServer.h>

static WebSocketsServer webSocket(81);


(2.2) 初期化 (setup()での処理)

WebSocketサーバを開始し、イベントハンドラ関数を設定する。

  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
(2.3) ループ処理 (loop()での処理)

loop()内で必ずloopメソッドを呼ぶこと。
すなわち、loop()を他の同期処理などで止めてはならない。

  webSocket.loop();
(2.4) 受信

受信データは初期化時に設定したコールバック関数で取得する。また、接続時、切断時、エラー時にもコールバック関数が呼ばれるのでイベント種別を判定して各々を処理する。

  // num: クライアント番号
  // type: イベント種別
  // payload, length: 受信データとそのサイズ
  void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
  {
    switch(type) {
      case WStype_DISCONNECTED:
        切断時の処理;
        break;
      case WStype_CONNECTED:
        {
          IPAddress ip = webSocket.remoteIP(num); // クライアントのIPアドレスを取得
          接続時の処理
        }
        break;
      case WStype_TEXT:
        テキストデータ受信時の処理;
        break;
      case WStype_BIN:
        バイナリデータ受信時の処理;
        break;
      case WStype_ERROR:
        エラー時の処理;
        break;
    }
  }
(2.5) 送信

ブロードキャストであれば broadcastTXT メソッドを用いる。

  webSocket.broadcastTXT(tx_str); // 文字列を渡す場合 (文字数を指定しない場合)
  webSocket.broadcastTXT(tx_buff, tx_len); // バイト数を指定する場合

特定のクライアントに送信するのであれば sendTXT メソッドを用いる。

  webSocket.sendTXT(client_num, tx_str); // 文字列を渡す場合 (文字数を指定しない場合)
  webSocket.sendTXT(client_num, tx_buff, tx_len); // バイト数を指定する場合

また、バイナリデータを送信する場合は broadcastTXT に代えて broadcastBIN を、sendTXT に代えて sendBIN を用いる。