概要
Firefoxなどのブラウザを用いてAWS IoTのMQTTブローカーに接続します。ブラウザからの接続の場合、WebSocketでの接続になります。AWS IoT Coreデベロッパーガイドのデバイス通信プロトコルの表によるとMQTT over WebSocketはPublisおよびSubscribeに対応しており、認証方法は署名V4(SigV4)とカスタム認証を使うことになっています。
プロトコル オペレーション 認証 ポート MQTT over WebSocket 発行, 購読 署名V4 443 MQTT over WebSocket 発行, 購読 カスタム認証 443
独自の認証を使いたい場合はLambdaオーソライザーを使うようですが、この記事では「とにかくシンプルに使う」を目的にしているので、署名V4を使った接続方法を解説します。ここではカスタム認証の方法は扱いません。
準備
IAMユーザーの作成
接続に使用するIAMユーザーを作成します。コンソール接続は不要でプログラムからのみ使用します。例えばポリシーは以下のようにすることで、購読(subscribe)のみ可能です。発行(publish)したい場合は "iot:Publish"
を Action
の項目に追加します。{REGION}
および{AWS ACCOUNT ID}
、{TOPIC}
は適切なものに指定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IoT-20240915",
"Effect": "Allow",
"Action": [
"iot:Subscribe",
"iot:Connect",
"iot:Receive"
],
"Resource": [
"arn:aws:iot:{REGION}:{AWS ACCOUNT ID}:topicfilter/{TOPIC}",
"arn:aws:iot:{REGION}:{AWS ACCOUNT ID}:client/*",
"arn:aws:iot:{REGION}:{AWS ACCOUNT ID}:topic/{TOPIC}"
]
}
]
}
ユーザーを作成したらアクセスキーとシークレットアクセスキーをメモしておきます。
ブラウザ用AWS IoT Device SDKのビルド
Node.jsの場合はnpmでインストールすればすぐに使えるみたいですが、ブラウザ向けのjsファイルは自分で作る必要があります。browserifyでビルドします。以下はRocky Linux 9.4, node.js 20.11.1, npm 10.2.4で実行しました。
$ npm install browserify
$ git clone https://github.com/aws/aws-iot-device-sdk-js.git
$ cd aws-iot-device-sdk-js
$ npm run-script browserize
これで、browserディレクトリにaws-iot-sdk-browser-bundle.js
ファイルが生成されます。
Webページの作成
ブラウザで開くWebページを作成します。ここではできるだけ単純に以下の構成にしました。www
ディレクトリはWeb公開ディレクトリです。環境に合わせて調整してください。ひょっとしたらHTTPS接続が必要かもです(すみませんHTTPSでしか試していません)。
Windows 10 22H2のFirefox 130およびEdge 128で動作確認しました。
- www/
- aws-iot-sdk-browser-bundle.js
- mqttclient.html
以下がトピックを購読するための最低限のコードです。エラー処理などはしていません。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MQTT Client Test</title>
<script src="./aws-iot-sdk-browser-bundle.js"></script>
</head>
<body>
<p id="txtMessage">0</p>
<script>
const awsIot = require("aws-iot-device-sdk"); // SDKを読み込む
const IOT_TOPIC = "MyTopic/test"; // 対象とするトピック
const params = {
accessKeyId: "AKEXAMPLEACCESSKEYID",
secretKey: "MyExampleSecretKeyabcdef0123456789000000",
region: "ap-northeast-1",
host: "xxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com", // iot:Data-ATSエンドポイント
protocol: "wss",
clientId: self.crypto.randomUUID(), // 一意のクライアントID(何でもよい)
};
deviceIot = awsIot.device(params); // 接続開始
deviceIot.on("connect", () => { // 接続されたら購読する
console.debug("Connected!!");
deviceIot.subscribe(IOT_TOPIC, undefined, (err, granted) => {
console.debug("Subscribed!!");
});
});
deviceIot.on("message", (topic, payload) => { // メッセージが届いた
const message = new TextDecoder().decode(payload);
document.querySelector("#txtMessage").textContent = message;
});
</script>
</body>
</html>
mqttclient.html
をブラウザで開くとメッセージの購読が始まります。
ポイント
-
params.clientId
はrandomUUID()
で求めていますが、適当な文字列が使えます。 -
awsIot.device(params)
のオプションでsessionToken
も使えるので、高度な認証を行いたい場合はセッショントークンを使ってもいいかもしれません。
メッセージの発行
今回のHTMLには実装していませんが、publish()
メソッドでメッセージを発行できます。
この場合、IAMユーザーにiot:Publish
権限が必要となります。
deviceIot.publish("MyTopic/test", '{"message": "Hello, IoT World!!"}');
参考
- AWS IoT Coreにブラウザから様々な認証方法で接続してみる
- ブラウザでAWS IoT CoreにMQTTでPub/Subしたい場合にやるべきことリスト
- AWS IoT Coreデベロッパーガイド -- デバイス通信プロトコル
- AWS IoT: awsIot.device()
余談
最低限の実装というのがなかなか見つからず、署名V4でシンプルに接続したいだけなのに結構苦労しました。
TypeScriptは使わないので、AWS SDKをビルドするのが面倒…というのでできるだけシンプルな方法を探していたのですが、AWS IoT Device SDKは必要なんですね(他のやり方もあるのかもですが)。
私はM5Stackからのセンサー値の通信に使いたいなと思って試しましたが、ほぼリアルタイムな通信が簡単に実装できるので、IoTだけではなくブラウザ間通信など、アイデア次第でいろいろ遊べそうな気がします。