# MQTT: IoTメッセージングの標準

MQTTは、Internet of Things（IoT）のためのOASIS標準メッセージングプロトコルです。これは、非常に軽量なパブリッシュ/サブスクライブメッセージングトランスポートとして設計されており、小さなコードフットプリントと最小限のネットワーク帯域幅でリモートデバイスを接続するのに理想的です。MQTTは今日、自動車、製造、通信、石油・ガスなど、さまざまな業界で使用されています。

## なぜMQTTなのか？

### 軽量で効率的

MQTTクライアントは非常に小さく、最小限のリソースしか必要としないため、小さなマイクロコントローラーで使用することができます。MQTTメッセージヘッダーは、ネットワーク帯域幅を最適化するために小さくなっています。

### 双方向通信

MQTTはデバイスからクラウド、クラウドからデバイスへのメッセージングを可能にします。これにより、グループのものにメッセージを簡単にブロードキャストすることができます。

### 数百万のものにスケールアップ

MQTTは、数百万のIoTデバイスと接続するためにスケールアップすることができます。

### 信頼性のあるメッセージ配信

メッセージの配信の信頼性は、多くのIoTユースケースにとって重要です。これがMQTTが定義する3つの品質保証レベルがある理由です：0 - 最大でも一度、1 - 少なくとも一度、2 - 正確に一度

### 不安定なネットワークへの対応

多くのIoTデバイスは不安定なセルラーネットワークを介して接続します。MQTTの永続セッションのサポートにより、クライアントとブローカーの再接続時間が短縮されます。

### セキュリティ対応

MQTTは、TLSを使用してメッセージを暗号化し、OAuthなどの現代の認証プロトコルを使用してクライアントを認証することを容易にします。

## MQTTのパブリッシュ/サブスクライブアーキテクチャ

<figure><img src="https://2492347595-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOYkbt2zJpXeHi1d4AtDs%2Fuploads%2FzzZSfcwa9p8uPsqlghMA%2Fmqtt-publish-subscribe.png?alt=media&amp;token=13e32e04-4a19-4ec4-a51f-7632a2bcf914" alt=""><figcaption><p>publish / subscribe</p></figcaption></figure>

## MQTTの実際の使用例

* 自動車
* ロジスティクス
* 製造業
* スマートホーム
* 消費者製品
* 交通


# MQTT 仕様

![](https://2492347595-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOYkbt2zJpXeHi1d4AtDs%2Fuploads%2FTgyBGlDPYprPUiOixRP9%2Foasis-logo.png?alt=media\&token=29023cac-6bca-4cd0-8271-92fee4ae6f6f)&#x20;

<https://www.oasis-open.org/committees/tc\\_home.php?wg\\_abbrev=mqtt>

MQTTはOASISの標準です。仕様はOASIS MQTT技術委員会によって管理されています。

### MQTT 5 仕様

これはOASISの標準です。仕様は以下のいずれかで利用可能です。

> [単一ページ](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html) HTMLまたは [PDF](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.pdf)。

### MQTT 3.1.1 仕様

これは古いISOとOASISの標準です。仕様は以下のいずれかで利用可能です。

> [単一ページ](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) HTMLまたは [PDF](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf)。

### MQTT 3.1 仕様

歴史的な参照のために、MQTT v3.1の仕様は以下で利用可能です。

> [ここ](https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html)。

### MQTT-SN v1.2

以前はMQTT-Sとして知られていました、以下で利用可能です。

> [ここ](https://www.oasis-open.org/committees/document.php?document_id=66091\&wg_abbrev=mqtt)

MQTT for Sensor Networksは、Zigbeeなどの非TCP/IPネットワーク上の組み込みデバイスを対象としています。MQTT-SNは、ワイヤレスセンサーネットワーク（WSN）のためのパブリッシュ/サブスクライブメッセージングプロトコルで、センサーとアクチュエータのソリューションのためにMQTTプロトコルをTCP/IPインフラストラクチャの範囲を超えて拡張することを目指しています。

[IBM Zurich Researchウェブサイトで詳細を読む](http://www.zurich.ibm.com/sys/energy/middleware.html)。


# 初心者ガイド

MQTTは、低帯域環境でのM2M（マシンとマシンの間）テレメトリー向けに設計された軽量な**パブリッシュ/サブスクライブ**メッセージングプロトコルです。

これは、1999年にアンディ・スタンフォード＝クラーク（IBM）とアーレン・ニッパーによって、衛星を介した石油パイプラインのテレメトリーシステムを接続するために設計されました。

もともとは独占的なプロトコルとして始まりましたが、2010年にロイヤリティフリーで公開され、2014年にOASIS標準になりました。

**MQTT**は**MQ Telemetry Transport**の略ですが、以前はMessage Queuing Telemetry Transportとして知られていました。

**MQTT**は、**IOT**（インターネットオブシングス）の展開のための主要なプロトコルの一つに急速になりつつあります。

## MQTTのバージョン

MQTTには2つの異なるバリアントといくつかのバージョンがあります。

* MQTT v3.1.0 –
* MQTT v3.1.1 – 一般的に使用されている
* MQTT v5 – 現在は限定的な使用
* **MQTT-SN** – 後で注記を参照

1999年に設計され、多くの年月にわたって使用されてきたオリジナルの**MQTT**は、**TCP/IPネットワーク**向けに設計されています。

MQTTv3.1.1は一般的に使用されているバージョンです。

v3.10と3.1.1の間にはほとんど違いがありません。こちらは主な違いを詳述した[Githubページ](https://github.com/mqtt/mqtt.github.io/wiki/Differences-between-3.1.0-and-3.1.1)です

こちらは実際の仕様[MQTT V3.1](http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/MQTT_V3.1_Protocol_Specific.pdf)と、[MQTTプロトコルパケット構造のより詳細な概要](http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/MQTT_V3.1_Protocol_Specific.pdf)です。

最新のMQTTバージョン(v5)は、[現在承認されています](https://www.oasis-open.org/news/announcements/mqtt-v5-0-is-an-approved-oasis-committee-specification) (2018年1月)。仕様は[こちら](http://docs.oasis-open.org/mqtt/mqtt/v5.0/cs01/mqtt-v5.0-cs01.pdf)からダウンロードできます。

4に何が起こったのか疑問に思うなら、[こちら](http://www.eclipse.org/community/eclipse_newsletter/2016/september/article3.php)を見てください。

詳細については、[MQTT v 5.0 新機能概要](http://www.steves-internet-guide.com/mqttv5/)を参照してください。

こちらはMQTT v3.1.1とMQTT v5の主な違いを詳述した[Githubページ](https://github.com/mqtt/mqtt.github.io/wiki/Differences-between-3.1.1-and-5.0)です。

### MQTTバージョン5サポートノート：

**リリース1.6**時点で、mosquittoブローカーはMQTT v3.11に加えてMQTT v5もサポートしています。

最新のブローカーを使用しても、古いバージョン3.11のクライアントを引き続き使用できます。

Paho Pythonクライアントv1.5は現在v5をサポートしています。

### MQTT-SNノート

**MQTT-SN**は2013年頃に指定され、**UDP**、ZigBeeおよびその他のトランスポート上で動作するように設計されました。

**MQTT-SN**は現在、非常に人気があるわけではなく、仕様もここ数年変更されていませんが、IOTの展開が始まるにつれて変わることを期待しています。MQTT-SNに関する詳細は、MQTT-SN作業ノートを参照してください。

## MQTTクライアント

MQTTクライアントにはメールアドレスや電話番号などのアドレスがないため、ほとんどのメッセージングシステムのようにクライアントにアドレスを割り当てる必要はありません。

MQTTv3.1.1には、ほぼすべてのプログラミング言語および主要なオペレーティングシステムLinux、Windows、Mac用のクライアントソフトウェアが[Eclipse Pahoプロジェクト](https://eclipse.org/paho/downloads.php)から入手できます。

* [Paho Pythonクライアント](http://www.steves-internet-guide.com/into-mqtt-python-client/)。
* [Node.js MQTTクライアント-スタートガイド](http://www.steves-internet-guide.com/using-node-mqtt-client/)
* [JavaScript Websocketsクライアント](http://www.steves-internet-guide.com/using-javascript-mqtt-client-websockets/)
* [Arduinoを使用したC++クライアント](http://www.steves-internet-guide.com/using-arduino-pubsub-mqtt-client/)

Pahoクライアントv1.5.1は現在MQTTv5.0をサポートしています。こちらはクライアント比較チャートとダウンロードページへの[リンク](https://www.eclipse.org/paho/index.php?page=downloads.php)です。

## MQTTブローカーまたはサーバー

> **注**: 元々の用語はブローカーでしたが、現在はサーバーとして標準化されています。両方の用語が使用されているのを見ることがあります。

テスト用や実際のアプリケーション用に多くのMQTTブローカーが利用可能です。

無料の自己ホスティング型ブローカーがあり、最も人気のあるものは[Mosquitto](https://mosquitto.org/)、商用のものでは[FuboX](https://www.fubogroup.com/)があります。

> **Mosquitto**は、WindowsとLinuxで動作する無料のオープンソースMQTTブローカーです。

## WebSockets経由のMQTT

**Websockets**を使用すると、MQTTデータを直接Webブラウザに受信できます。

これは、WebブラウザがMQTTデータを表示するための事実上のインターフェースになる可能性があるため重要です。

Webブラウザ向けのMQTT websocketサポートは、**Javascript MQTTクライアント**によって提供されます。

参照 –[WebSockets経由でのMQTTの使用](app://obsidian.md/...)

## MQTTセキュリティ

MQTTは、さまざまな認証およびデータセキュリティメカニズムをサポートしています。

これらのセキュリティメカニズムはMQTTブローカー上で設定され、クライアントがそれらのメカニズムに準拠するかどうかはクライアント次第であることに注意することが重要です。

参照 [MQTTセキュリティメカニズムの紹介](app://obsidian.md/...)

## よくある質問

Webやメールに慣れている場合、MQTTは非常に異なるものであると感じるかもしれません。これらは私が持っていた質問であり、他のサイトやフォーラムで見たもので、少し明確にするかもしれません。

**Q, MQTTは通常どのポートを使用しますか？**

* A: 標準ポートは1883です。
* Q: ブローカーなしでMQTTを使用できますか？
* A: いいえ、MQTTの仕組みを参照してください

**Q: MQTTはどのプロトコルを使用しますか？**

* A: 標準バージョンはTCP/IPを使用します。

**Q: 複数のクライアントが同じトピックに対してパブリッシュできますか？**

* A: はい

**Q: メッセージをパブリッシュしたクライアントの身元を知ることは可能ですか？**

* A: クライアントがその情報をトピックまたはペイロードに含めない限り、いいえ

**Q: 誰もサブスクライブしていないトピックにパブリッシュされたメッセージはどうなりますか？**

* A: ブローカーによって破棄されます。

**Q: どのトピックがパブリッシュされたかをどのように知ることができますか？**

* A: ブローカーはパブリッシュされたトピックのリストを保持していないようなので、これを簡単に行うことはできません。トピックは永続的ではありません。

**Q: 誰もパブリッシュしていないトピックをサブスクライブできますか？**

* A: はい

**Q: メッセージはブローカーに保存されますか？**

* A: はい、しかし一時的にのみです。全てのサブスクライバーに送信された後、それらは破棄されます。しかし、次の質問も参照してください。

**Q: 保持メッセージとは何ですか？**

* A: メッセージをパブリッシュするとき、ブローカーに最後にパブリッシュされたメッセージを保存させることができます。このメッセージは、そのトピックをサブスクライブする新しいサブスクライバーが最初に見るメッセージになります。MQTTは1つのメッセージのみを保持します。[保持メッセージの理解](app://obsidian.md/index.html)を参照してください。

## MQTTとNode.js

このサイトの例のスクリプトの多くはnode.jsを使用しています。Node.jsは使いやすく、すぐに利用できるため、MQTTを学ぶのに適した選択肢です。[mqtt.js](https://www.npmjs.com/package/mqtt)の使用を参照してください。

## MQTTとNode-Red

プログラミングをしたくない場合、Node-Redはフローベースのツールで、MQTTプロジェクトを簡単に作成できます。他のサイトでのNode-Red入門ガイドを参照して始めてください。\ <br>

MQTT vs HTTP プロジェクトに最適な選択肢がMQTTかどうか疑問に思っているなら、ここにMQTTとHTTPを比較した記事のコレクションがあります。

* インターネットオブシングス：プロトコルの戦い（HTTP vs. Websockets vs. MQTT）
* MQTT vs. HTTP：IoTに最適なのはどちらか？
* HTTP vs MQTT パフォーマンステスト
* MQTTとHTTP：2つのIoTプロトコルの比較 - 誤りを含むが、チャートは有用
* ロボティクスのためのMQTT-SN vs Coap

実際のMQTT例の展開 特定の技術が実際にどのように使用されているかを見ることは、しばしば有用で興味深いものです。ここに私が出会ったいくつかの例があります：

* Freight Farms-MQTT
* MQTTを使用したIPピンガースウォーム
* MQTTの使用方法 - Mosquitto.org
* Owntracks - 位置追跡


# Node.js MQTT クライアントガイド

node.js MQTTクライアントは、MQTTブローカーでメッセージを公開したりトピックを購読するために使用できるオープンソースのクライアントです。次の方法でインストールできます：

```
npm install mqtt --save 

# and To install the command line tools
npm install mqtt -g
```

クライアント向けのドキュメントはこちらでご覧いただけます

このチュートリアルでは、重要なクライアント機能をカバーし、シンプルなパブリッシュサブスクライブノード、jsの例示スクリプトを作成します。

クライアントを使用するには、次のものを使用する必要があります：

```
const mqtt=require('mqtt');
```

スクリプトの先頭に

## &#x20;概要

Node.jsのスクリプトは非同期であり、イベントを使用します。何かが起こるとイベントがトリガーされます。例えば、クライアントが接続したときなどです。

イベントリスナーを作成して、興味のあるイベントを監視し、このリスナーがコールバック関数を呼び出してイベントを処理します。

## &#x20;接続方法

これはメインメソッドで、呼び出されるとMQTTブローカーに接続し、クライアントクラスを返します。

翻訳テキスト：

```
const client = mqtt.connect(url, options);
```

&#x20;翻訳テキスト：

```
const client = mqtt.connect("mqtt://broker.fubogroup.com:1833", options)
const client = mqtt.connect("mqtt://broker.fubogroup.com:1833", { clientId: "mqttjs01" })
```

通常、メソッドに渡す必要がある多くのオプションがあり、そのオプションは通常、JavaScriptオブジェクトとして作成されます。例えば。

ユーザー名とパスワード認証およびクリーンセッションを使用するには、次のオプションを使用します。

```
options = {
	clientId:"mqttjs01",
	username:"steve",
	password:"password",
	clean:true
};
```

MQTTプロトコルはCONNACKメッセージで接続を認識します。

これにより、クライアントでon\_connectイベントが発生し、次のようにリスナーを作成することで調査できます：

```
client.on("connect", function() {	
	console.log("connected");
});
```

リスナーは接続イベントを待ち、コールバック関数を呼び出します。この例では、クライアントが接続するとメッセージを単に表示します。

私たちは今、最初の例のスクリプトを試すことができます。

このスクリプトはbroker.fubogroup.comのMQTTブローカーに接続し、接続時にメッセージを表示します。

```
const mqtt = require('mqtt');

const clientId = 'fubo' + Math.random().toString(16).substring(2, 8);

const client = mqtt.connect('mqtt://127.0.0.1:1883', {
  clientId,
});

client.on('connect', (response) => {
    console.log(`connected ${client.connected}`);
    console.log(response);
});
```

注目すべき点は、コマンドプロンプトのカーソルが新しい行にあり、点滅していることです。

[![simple-connect-node-script](https://github.com/Fubo-Group/docs/raw/main/images/mqtt-connect.png)](https://github.com/Fubo-Group/docs/blob/main/images/mqtt-connect.png)

これは、クライアントがまだブローカーに接続されており、イベントループに参加しているためです。

しかし、私たちは台本の終わりにいるので、起こりうるのはイベントだけです。だから私たちの台本はそこに座って何もしません。

スクリプトを終了するには、クライアント接続を閉じてください。

```
client.end();
```

on\_connect イベントは、connected というフラグを true に設定します。このフラグには次のようにアクセスできます: client.connected.

私たちのシンプルなスクリプトを変更して、このフラグを前後に印刷するようにしました：

```
var client  = mqtt.connect("mqtt://broker.fubogroup.com",{clientId:"mqttjs01"});
console.log("connected flag  "+client.connected);
client.on("connect",function(){	
console.log("connected  "+client.connected);
})
```

スクリプトを実行すると、次のように表示されるはずです：

ノード接続スクリプト2

## &#x20;接続失敗

接続が失敗した場合はどうなりますか？

ノードクライアントは接続失敗のためのエラーイベントを提供します。これを監視するためには、次のようにこのイベントのリスナーを作成する必要があります：

```
client.on("error",function(error){ console.log("Can't connect"+error);
```

残応に、これは認証失敗のような失敗のみを捕捉します。

誤ったポートまたは誤ったアドレスに接続しようとすると、エラーは生成されず、クライアントは再接続を試み続けることになります。

エラーが認証失敗を検出した場合、クライアントが継続して接続を試みるため、終了する必要があります。

したがって、on\_errorイベントリスナーは以下のようなものであるべきです：

```
client.on('error', (error) => {
    console.log(`Can't connect ${error}`);
});
```

## &#x20;メッセージを公開する

メッセージを公開するには：

```
client.publish(topic, message, [options], [callback])
```

オプションとコールバックパラメータは任意です。オプションにはメッセージフラグの保持、QoSなどが含まれます。例えば

```
client.publish("testtopic", "test message")
```

&#x20;そして

```
var options={
retain:true,
qos:1};
client.publish("testtopic", "test message",options)
```

出版する前に、接続されていることを確認するのが賢明です:

```
if (client.connected==true){
client.publish("testtopic", "test message",options)
}
```

> しかし、接続が非同期であるため、クライアントが接続される前にif 文が試される可能性が高いため、これはうまくいかないでしょう。

したがって、接続して公開し、切断するだけの場合は、on\_connectコールバックでpublishを呼び出すべきです。

定期的に公開する必要がある場合、例えばステータス情報を送信するときは、以下に示すように `setInterval` 関数を使用してください。

```
var message="test message";
var topic="testtopic";
//publish every 5 secs
var timer_id=setInterval(function(){publish(topic,message,options);},5000);

//publish function
function publish(topic,msg,options){
  console.log("publishing",msg);
if (client.connected == true){
  client.publish(topic,msg,options);
}
```

## &#x20;トピックの購読

購読するには、client.subscribeメソッドを使用します。一般的な形式は次のとおりです：

```
client.subscribe(topic/topic array/topic object, [options], [callback])
```

単一のトピックのみを購読したい場合は、トピック文字列メソッドを使用します。

配列メソッドを使用する場合は、同じQoSで複数のトピックを購読したい場合に使用します。つまり、オプションで渡すQoSは配列内のすべてのトピックに適用されます。

オブジェクトメソッドを使用するのは、異なるQoS 設定で複数のトピックを購読したい場合です。使用例：

```
var topic_s="topic";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
client.subscribe(topic_s,{qos:1});
client.subscribe(topic_list,{qos:1});
client.subscribe(topic_o);
```

## &#x20;受信メッセージ

トピックに登録する必要があります。

新しいメッセージが到着すると、メッセージイベントがトリガーされます。

このイベントを処理するにはリスナーを作成する必要があります。

```javascript
client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
});
```

コールバックは3つのパラメータを受け入れることができます。 `topic` 、 `message` 、そして `packet` 。

パケットオブジェクトには、メッセージ、トピック、QOS、保持などのメッセージの詳細が含まれています。

その内容を見るには、次を使用してください：

```javascript
console.log(JSON.stringify(packet)
```

以下は、受信したパケットの例のスクリーンショットです：

&#x20;ノードjs-受信パケット

もしリテインフラグを見たい場合は、次のように使用します：

```javascript
console.log("packet retain =" +packet.retain);
```

トピック、メッセージ、パケットを印刷して保持するには、次のコードを使用します：

```javascript
client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
	console.log("packet =" +JSON.stringify(packet));
	console.log("packet retain =" +packet.retain);
});
```

## &#x20;最終脚本例

最終スクリプトはブローカーに接続し、トピックのコレクションを購読して、x 秒ごとにそのトピックの1つにメッセージを公開します。

受信したメッセージをコンソールに出力し、2 回のループ後に終了します。

```javascript
var mqtt    = require('mqtt');
var count =0;
var client  = mqtt.connect("mqtt://192.168.1.157",{clientId:"mqttjs01"});
console.log("connected flag  " + client.connected);

//handle incoming messages
client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
});


client.on("connect",function(){	
console.log("connected  "+ client.connected);

})
//handle errors
client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)});
//publish
function publish(topic,msg,options){
console.log("publishing",msg);

if (client.connected == true){
	
client.publish(topic,msg,options);

}
count+=1;
if (count==2) //ens script
	clearTimeout(timer_id); //stop timer
	client.end();	
}

//////////////

var options={
retain:true,
qos:1};
var topic="testtopic";
var message="test message";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
console.log("subscribing to topics");
client.subscribe(topic,{qos:1}); //single topic
client.subscribe(topic_list,{qos:1}); //topic list
client.subscribe(topic_o); //object
var timer_id=setInterval(function(){publish(topic,message,options);},5000);
//notice this is printed even before we connect
console.log("end of script");
```

ソーステキスト：スクリプトが実行されているスクリーンショットはこちらです： 翻訳テキスト：

ノードMQTTスクリプト例

スクリプトが明らかに実行中であるにもかかわらず、スクリプトの終了メッセージが表示されることに気付くべきです。

これは、node.jsの非同期性を示しています。

## &#x20;SSLを使用しています

接続をSSLを使用して安全にすることができます。以下はSSLを使用してブローカーに接続する簡単な接続スクリプトです：

```javascript
var mqtt    = require('mqtt');
const fs = require('fs');
var caFile = fs.readFileSync("ca.crt");

var options={
clientId:"mqttjs01",
//port:8883,
//host:'192.168.1.71',
//protocol:'mqtts',
rejectUnauthorized : false,
ca:caFile 
}
var client  = mqtt.connect("mqtts://192.168.1.71:8883",options);
console.log("connected flag  " + client.connected);
client.on("connect",function(){	
console.log("connected  "+ client.connected);
})
```

rejectUnauthorized : false オプションは、証明書にドメインの不一致がある場合にのみ必要であり、通常は使用すべきではありません。

証明書ファイルが最初に読み込まれ、オプションとして渡されることに注意してください。

クライアント証明書も使用している場合は、次のものを使用してください：

```javascript
var KEY = fs.readFileSync(‘client-certs\\client.key’);
var CERT = fs.readFileSync(‘client-certs\\client.crt’);
```

&#x20;オプションで：

```javascript
key: KEY,
cert: CERT,
```

ここに動作するSSL 接続の例示スクリプトがあります：

```javascript
//https://github.com/mqttjs/MQTT.js/issues/264
var mqtt    = require('mqtt');
const fs = require('fs');
//var cert="ca.crt";
var caFile = fs.readFileSync("ca.crt");
//if using client certificates
var KEY = fs.readFileSync('client-certs\\client.key');
var CERT = fs.readFileSync('client-certs\\client.crt');
//
var options={
clientId:"mqttjs01",
//port:8883,
//host:'192.168.1.71',
//protocol:'mqtts',
rejectUnauthorized : false,
//if using client certificates
key: KEY,
cert: CERT,
//
ca:caFile 

}
var client  = mqtt.connect("mqtts://192.168.1.71:8883",options);
console.log("connected flag  " + client.connected);
client.on("connect",function(){	
console.log("connected  "+ client.connected);
})
```

詳細はGithubのリファレンスを参照してください


# MQTTブローカーに接続する

概要で説明されたように、接続メソッドは以下の目的で使用されます：

* クライアントクラスを作成する
* ブローカーに接続する

翻訳テキスト：

```javascript
var client = mqtt.connect(url,options)
```

呼び出されるとMQTTブローカーに接続し、クライアントクラスを返します。

&#x20;Source Text: e.g. Translation Text: 例えば

```javascript
var client = mqtt.connect("mqtt://192.168.1.157",options)
```

通常、メソッドに渡す必要がある多くのオプションがあり、そのオプションは通常、JavaScriptオブジェクトとして作成されます。

例えば、ユーザー名とパスワード認証およびクリーンセッションを使用するには、次のオプションを使用します。

```javascript
options={
clientId:"mqttjs01",
protocolVersion:4, //use 5 for mqttv5
username:"steve",
password:"password",
clean:true};
```

MQTTプロトコルは、 `CONNACK` メッセージで接続を認識します。

これによりクライアントで `on_connect` イベントが発生し、次のようにリスナーを作成することで調査できます：

```javascript
client.on("connect",function(){	
console.log("connected");
```

リスナーは `connect` イベントを待ち、コールバック関数を呼び出します。上記の例では、クライアントが接続するとメッセージを印刷するだけです。

on\_connect イベントは、connected というフラグを true に設定します。このフラグには client.connected を使用してアクセスできます。

## &#x20;URL

接続メソッドのURLには、ブローカーのIPアドレスまたはドメイン名が含まれています。例示された以下では、プロトコルであるMQTTが接頭辞として付けられています。

```javascript
var client = mqtt.connect("mqtt://192.168.1.157",options)
```

MQTT+SSLを使用して接続する場合、プロトコルの接頭辞はmqttsです。また、ws（ウェブソケット）とwss（ウェブソケット+SSL）の接頭辞もあります。

接続ポートはURLの一部としても渡すことができます。例えば

```javascript
var client = mqtt.connect("mqtt://192.168.1.157:1883",options)
```

しかし、通常はオプションの一部として設定されます。オプションの設定は、両方が存在する場合にURLの設定を上書きします。

## &#x20;オプション

接続メソッドに渡すことができる多くのオプションがあり、それらはここにリストされています。

このチュートリアルでは、知っておくべき最も重要で一般的なもののいくつかについて説明します。

### &#x20;クライアントID

各クライアントには固有のIDが必要です。通常、既知のプレフィックスを使用してランダムなIDを生成します。

接頭辞はACL（アクセス制御リスト）で使用できるため、現在 ACLを使用していなくても、接頭辞を使用することが良い習慣です。

私が使用しているコードは次のようになっています：

```javascript
let r = Math.floor(Math.random() * 10000); 
let clientId= "mqttjs-"+r,
```

### &#x20;プロトコルバージョン

この設定は接続パケットに設定されており、正しく設定することを確認してください。現在のデフォルトはMQTTv3.1.1（protocolVersion:4）です。MQTTv5を使用する場合はprotocolVersion:5を使用してください。

### 最後の遺言メッセージの設定

最後の遺言メッセージは接続パケットの一部です。遺言メッセージはMQTTv5で拡張されました。次のスクリーンショットはすべての可能な設定を示していますが、プロパティ属性はMQTT v5でのみ利用可能です。

[![mqtt-will-nodejs](https://github.com/Fubo-Group/docs/raw/main/images/mqtt-will-nodejs.png)](https://github.com/Fubo-Group/docs/blob/main/images/mqtt-will-nodejs.png)

### &#x20;設定例

接続オプションは次のようになります

```javascript
let r = Math.floor(Math.random() * 10000);
var options={
	clientId:"mqttjs-will-"+r,
	port:1883,
    will:{topic:"connected",payload:"offline"}
}
```

### &#x20;MQTT v5 プロパティ

MQTTv5を使用する際には、接続を制御するためにブローカーに追加情報を送信できます。

トピックエイリアスの数を制限したり、クライアントに送信されるメッセージのサイズを制限するなどが可能です。利用可能なオプションはすべてドキュメントに記載されています。

使用方法は以下の通りです：

```javascript
let r = Math.floor(Math.random() * 10000);
var options={
    protocolVersion:5,
	clientId:"mqttjs-"+r,
	properties:{maximumPacketSize:1000}

    }
```

## &#x20;SSLを使用して接続する

SSLを使用して接続するには、CA 証明書が必要です。証明書に不慣れな場合は、「Mosquitto MQTT Broker SSL 設定を自分の証明書を使用して行う方法」を参照してください。

ファイルからCA 証明書を読み取る必要があるため、次のように始めます

```javascript
const fs = require('fs');
var caFile = fs.readFileSync("certs/ca-pi2.crt");
```

接続オプションについては、以下のようなものを使用します：

```javascript
var options ={
  clientId: 'ssl-test',
  port: 8883,
  //rejectUnauthorized: false,
  ca: caFile
};
```

証明書の一般名とTCP/IP 接続でブローカーにアクセスする際に使用される名前が一致しない場合に、 `rejectUnauthorized` オプションはトラブルシューティングに役立ちます。

つまり、証明書にドメイン名を使用していますが、IPアドレスを使用して接続しています。

SSL、ws、およびwssは異なるポートを使用するため、ポートにも注意してください。

接続コールは次のようになります：

```javascript
var client = mqtt.connect("mqtts://pi2.home", options);
```

### &#x20;ウェブソケット接続

ウェブソケットを使用して接続するには：

```javascript
var client = mqtt.connect("ws://pi2.home", options);
```

SSL 上でのWebsocketsには、私たちは使用します。

```javascript
var client = mqtt.connect("wsss://pi2.home", options);
```

証明書の設定は、以前に示されたmqttsと同じです。

### 複数のブローカーへの接続

接続ごとにクライアントを作成する必要があります。以下のコードがこれを示しています：

```javascript
var topic="testtopic";
//options for first connection
let r = Math.floor(Math.random() * 10000);
var options1={
	clientId:"mqttjs-"+r,
	port:1883}

//options for seconds connection
r = Math.floor(Math.random() * 10000);
var options2={
	clientId:"mqttjs-"+r,
	port:1884}

//now we can connect
var client  = mqtt.connect("mqtt://192.168.1.23",options1);
var client2  = mqtt.connect("mqtt://192.168.1.23",options2);
You should note that you will also need callback functions for each client.
```

&#x20;原文: 訳文:

`mqtt.Client(streamBuilder, options)` オプションを使用して新しいクライアントを作成することは可能であるはずですが、動作させることができず、インターネット上で例も見つけることができませんでした。これは私が引き続き試みることです。さらに、connect コールを使用して新しいクライアントを作成することは可能ですが、ブローカーには接続しないでください。ドキュメントには次のように記載されています：

> manualConnect：コンストラクタがconnectを呼び出すのを防ぎます。この場合、mqtt.connectが呼び出された後、client.connectを手動で呼び出す必要があります。

この機能を動かすことができず、クライアントコード内でそのオプションを見つけることもできませんでした。再度、さらに調査が必要です。

## 一般的な質問と回答

**Q1: クライアントは複数のブローカーに接続できますか？**

* A1: 各接続に対して新しいクライアントを作成する必要があります。

**Q2：クライアントは公開と購読ができますか？**

* &#x20;はい

**Q3：接続が失敗した場合、クライアントは自動的に再接続しますか？**

* A3: はい、それがデフォルトの動作です。

**Q4: NQTTv5のプロパティを使用していますが、うまく機能していないようですか？**

* 接続パケットでプロトコルバージョンの設定を忘れている可能性があります。

**Q5：私のクライアントは接続と切断を繰り返していますが、その理由は何ですか？**

* A5: あなたは他のクライアントと同じclientIdを使用している可能性があります。これはテスト時に多くのテストスクリプトがclientIdをハードコードするため、よく発生します。


# MQTTメッセージの公開

このチュートリアルでは、node.js MQTTクライアントを使用してメッセージを公開する方法について説明します。

MQTTでメッセージを公開するときは、指定する必要があります

* &#x20;トピック
* &#x20;メッセージ
* &#x20;保持
* QOS (0,1,2)
* &#x20;プロパティ (MQTT v5)

QOSに応じて、公開されたメッセージはブローカーからの確認を受け取ります（QOS=1,2）。

すべてのMQTTクライアントには、通常、保持、QoS、プロパティのデフォルトがあります。それらは通常、 `0` 、 `false` 、 `null` です。

QOS 1または2で公開する場合、メッセージにはmessageIdが割り当てられ、PubAckのmessageIdと組み合わせてブローカーにメッセージが受信されたかどうかを判断することができます。

送信メッセージのmessageIdが受信したPubAckメッセージのmessageIdと一致する場合、メッセージは正常に受信されたことになります。以下にmessageIdが `7844` の例を示します：

&#x20;nodejs-mqtt-パブリッシュ

## &#x20;MQTT パブリッシュ API

メッセージを公開するには：

```javascript
client.publish(topic, message, [options], [callback])
```

オプションとコールバックパラメータは任意です。

オプションにはメッセージを保持するフラグ、QoSなどが含まれます。例えば

```
client.publish("testtopic", "test message")
```

&#x20;翻訳テキスト：そしてオプションと共に：

```javascript
var options={
retain:true,
qos:1};
client.publish("testtopic", "test message",options)
```

コールバックは次の用途に使用できます：

* &#x20;成功のためのテスト
* 公開されたメッセージIDをキャプチャします。

## &#x20;イベント

パブアックをキャプチャするには、packetreceiveイベントをリッスンする必要があります。

## &#x20;タイミング

ノード.jsは非同期関数を使用しているため、タイミングに注意する必要があります。

例えばそのプロセス

1. &#x20;接続する
2. &#x20;公開

公開が接続完了前に行われるため、機能しない可能性があります。他の言語では、単にこのように接続が完了するのを待ちます：

1. &#x20;接続する
2. &#x20;接続を待つ
3. &#x20;公開

しかし、Node.jsではこれを行うことはできません。

接続が確立されるかどうかを公開する前にテストできます:

```javascript
if (client.connected==true){
client.publish("testtopic", "test message",options)
}
```

> しかし、接続が非同期であるため、クライアントが接続される前にif 文が試される可能性が高いため、これもうまくいく可能性は低いです。

したがって、単に接続して、公開して、切断する場合は、on\_connectコールバックでpublishを呼び出すべきです。

この方法なら、公開する前に接続されていることがわかります。

```javascript
client.on("connect",function(){	
	console.log("connected  "+ client.connected);
    let topic="test_topic";
    let options={qos:1};
    msg="test message";
    client.publish(topic,msg,options);
	
	})
```

定期的に公開する必要がある場合（例えば、ステータス情報を送信するときなど）は、以下に示すようにsetInterval 関数を使用してください。

```javascript
var message="test message";
var topic="testtopic";
//publish every 5 secs
var timer_id=setInterval(function(){publish(topic,message,options);},5000);

//publish function
function publish(topic,msg,options){
  console.log("publishing",msg);
if (client.connected == true){
  client.publish(topic,msg,options);
}
```

この状況では接続テストが機能します

## &#x20;メッセージペイロード

文字列、JSONデータ、バッファを送信できます。

```
msg=string
msg=JSON string
msg=buffer
```

整数または浮動小数点数を送信するには、まず以下のいずれかを使用して文字列に変換する必要があります：

&#x20;ソーステキスト: `JSON.stringify(value)` または `value.toString()` ; 翻訳テキスト:

例えば、数値（浮動小数点）2.31を使用することができます：

```javascript
 let n=2.32;
 msg=JSON.stringify(n);
```

&#x20;そして

```javascript
 let n=2.32;
 msg=n.toString();
```

ブール値 true/false を送信するには、JSON データに変換して使用します。

```javascript
let msg=JSON.stringify(true);
```

バッファの使用にはBufferモジュールを使用してください

```javascript
  msg = Buffer.from('abce');
  console.log("type="+ typeof msg);
```

そして通常通りに公開します。

## 公開コールバックの使用

公開メソッドを呼び出す際には、公開が完了したときに呼び出されるコールバックを送信することができます。

完了とは、確認プロセスが完了していることを意味します（QOSが1または2）

私が使用しているコードは以下の通りです

```
client.publish(topic,msg,options,puback);
```

以下の例で定義するコールバック関数がpubackです

```javascript
function puback(error,response)
{
	console.log("in puback");
	console.log("callback packet =" +JSON.stringify(response));
    if (error) {
      console.error(error)
}
```

テストメッセージを公開すると、次の出力が生成されます：

```javascript
//in puback
callback packet ={"cmd":"publish","topic":"testtopic","payload":"test message","qos":1,"retain":false,"messageId":64009,"dup":false}
```

送信されているパケットは、公開者が送信しているパケットです。

確認を表示するために、パケット受信イベントを監視します。

```javascript
client.on("packetreceive",function(packet){	
	console.log("receive packet  "+ JSON.stringify(packet));
	})
```

この結果、次の出力が得られます： 翻訳テキスト：

```javascript
receive packet  {"cmd":"puback","retain":false,"qos":0,"dup":false,"length":2,"topic":null,"payload":null,"messageId":64009}
```

## トピックエイリアスを使用した出版

MQTTv5はトピックエイリアスに対応しています。トピックエイリアスの背後にある考え方は、より短いトピックを使用して公開パケットのサイズを削減することです。

トピックエイリアスを使用するには、まずパブリッシュを使用してエイリアスを設定し、その後トピックエイリアスと空のトピックフィールドを使用してパブリッシュできます。

ソーステキスト：ここにコードがあります： 翻訳テキスト：

```javascript
//first published message asigns the topic alias of 1 to the topic //testtopic

var topic="testtopic";
	options.properties={topicAlias:1};
and subsequent messages set the topic to “” and use the topic alias.

//first published message asigns the topic alias of 1 to the topic //testtopic

var topic="";
	options.properties={topicAlias:1};
```

> 注意：メッセージを受信するには、トピックエイリアスではなくトピック(testtopic)を購読する必要があります。

クライアント接続にのみ有効なトピックエイリアスについても注意する必要があります。他のクライアントは自分のトピックエイリアスを設定できます。

さらに、サーバーは通常トピックエイリアスを制限します（デフォルト=10） トピックエイリアス0は許可されていません。

## &#x20;公開例

### QoS=1 および保持フラグを設定してメッセージを公開します

```javascript
if (client.connected == true){
var options={
		retain:true,
		qos:1};
		
msg="test message string";
console.log("publishing",msg);
client.publish(topic,msg,options);
}
```

### QOS=1でJSONメッセージを公開します

```javascript
if (client.connected == true){
	
var options={
		qos:1};

let data={volts:240,current:1.2};
msg =JSON.stringify(data);
console.log("publishing",msg);
client.publish(topic,msg,options);
}
```

メッセージをmessageExpiryInterval 設定で公開する

```javascript
if (client.connected == true){
	
var options={
		qos:1,
	properties:
{
	messageExpiryInterval:120
}
};

let data={volts:240,current:1.2};
msg =JSON.stringify(data);
console.log("publishing",msg);
client.publish(topic,msg,options);
}
```

注意：これを機能させるためには、クライアント接続をバージョン5に設定する必要があります

```javascript
let r = Math.floor(Math.random() * 10000);
var options={
	clientId:"mqttjs-"+r,
	protocolVersion:5,
	port:1883
}
let broker="mqtt://192.168.1.23";
var client  = mqtt.connect(broker,options);
```


# MQTTメッセージの購読

トピックに関するメッセージを受信するには、そのトピックまたは複数のトピックを購読する必要があります。

トピックを購読するには、Paho MQTTクライアントクラスのsubscribeメソッドを使用します。

上の図に示されているように、サブスクライブメッセージはSubAckメッセージによって確認されます。

購読するには提供する必要があります

1. QOS -0,1,2
2. &#x20;トピックまたはトピック

あなたは一つの関数呼び出しで複数のトピックを購読できることに注意してください。

MQTT v5を使用する際には、サブスクライブプロパティも送信できます。

再び、publishメッセージと同様に、SubAckメッセージを受け取るためにはpacketreceiveイベントをリッスンする必要があります。

## &#x20;購読 API

まずクライアントオブジェクトを作成し、次に以下のようにsubscribeメソッドを呼び出します：

```
client.subscribe(topic/topic array/topic object, [options], [callback])
```

単一のトピックとトピックの配列、そしてトピックオブジェクトを渡すことができます。

&#x20;選択肢は次のとおりです

1. QOS -0,1,2
2. &#x20;トピックまたはトピックス
3. ローカルなし - MQTT v5
4. 公開時のまま保持 - MQTT v5
5. 取り扱い維持 - MQTT v5
6. &#x20;プロパティ - MQTT v5

コールバック関数は以下の形式をしています：

&#x20;**関数 (err, granted)**

&#x20;どこで：

* サブスクリプションエラー、またはクライアントが切断する際に発生するエラー
* 付与されるのは{topic, qos}の配列です
* トピックは購読されたトピックです
* qosはそれに与えられたQoSレベルです

## &#x20;イベント

サブアックをキャプチャするには、以下に示すようにpacketreceiveイベントをリッスンする必要があります

```javascript
client.on("packetreceive",function(packet){	
	console.log("receive packet  "+ JSON.stringify(packet));
	
	})
```

これが私たちが見るものです：

```javascript
connected  true
subscribing to topics
receive packet  {"cmd":"suback","retain":false,"qos":0,"dup":false,"length":3,"topic":null,"payload":null,"granted":[1],"messageId":26988}
```

## &#x20;タイミング

ノード.jsは非同期関数を使用しているため、タイミングに注意する必要があります。

例えばそのプロセス

1. &#x20;接続する
2. &#x20;登録する

接続が完了する前に購読が行われるため、機能しない可能性があります。他の言語では、次のように接続が完了するのを単に待ちます:

1. &#x20;接続する
2. &#x20;接続を待つ
3. &#x20;公開

しかし、Node.jsではこれを行うことはできません。

接続が確立されるかテストしてから購読する場合：

```javascript
if (client.connected==true){
client.subscribe("testtopic",options)
}
```

> その場合、ほぼ確実に機能していないでしょう。接続が確立されていない可能性が高いです。

したがって、ほとんど常にon\_connectコールバックでサブスクライブします。

この方法なら、購読する前に接続されていることがわかり、接続が切れた場合は購読が更新されます。

```javascript
client.on("connect",function(){	
    console.log("connected  "+ client.connected);
    let topic="test_topic";
    let options={qos:1};
    client.subscribe(topic,options);
	
	})
```

## &#x20;購読例

### シングルトピックに登録する

```javascript
var topic="testtopic";
var message="test message";
console.log("subscribing to topics");
client.subscribe(topic,{qos:1}); //single topic
```

### 複数のトピックを購読する

この場合、彼らはすべて同じQOSを使用します。

```javascript
var topics=["testtopic","testtopic2"];
var message="test message";
console.log("subscribing to topics");
client.subscribe(topics,{qos:1}); //single topic
```

### トピックオブジェクトを使用して複数のトピックに登録する

この場合、使用されるQOSレベルはトピックオブジェクトにある0です。オプションで設定されたQOSは無視されます。

```javascript
var topics={"testtopic":{qos:0},"testtopic2":{qos:0}};
var message="test message";
console.log("subscribing to topics");
client.subscribe(topics,{qos:1}); //single topic
```

### rh オプションを使用して購読する

このオプションは、例のように2に設定すると、ブローカーに対してサブスクライブ時に保持メッセージを送信しないように指示します。これが機能するためには、接続時にプロトコルバージョンを5に設定する必要があります。

```
var topic="testtopic";
console.log("subscribing to topics");
client.subscribe(topic,{qos:0,rh:2}); //single topic
```

## プロパティを使用して購読する

この例では、受信メッセージのフィルタリングに使用できるサブスクリプション識別子を設定します。

ブローカーがクライアントに送信するメッセージには、サブスクリプションのトピックに一致するサブスクリプション識別子が含まれています。

この例では、購読するトピックはtesttopicで、サブスクリプション識別子は1に設定されています。

したがって、サブスクリプション識別子が1に設定されているクライアントには、testopicに公開されたメッセージが送信されます

```javascript
var topic="testtopic";
console.log("subscribing to topics");
let subOptions={qos:0,properties:{subscriptionIdentifier:1}}
client.subscribe(topic,subOptions); //single topic
```

これがクライアントが受け取るものです。ペイロードの最後にサブスクリプション識別子があることに注意してください。

```javascript
// message is test message
// topic is testtopic
packet ={"cmd":"publish","retain":true,"qos":0,"dup":false,"length":26,"topic":"testtopic","payload":{"type":"Buffer","data":[116,101,115,116,32,109,101,115,115,97,103,101]},"properties":{"subscriptionIdentifier":1}}
```

\ <br>


# 受信メッセージ

メッセージイベントを処理することによってメッセージが受信されます。形式は以下の通りです：

`function (topic, message, packet) {}`

以下に示すのは例示コードです：

```javascript
//handle incoming messages
client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
	console.log("packet =" +JSON.stringify(packet));
	console.log("packet retain =" +packet.retain);
});
```

メッセージにはテキストメッセージが含まれ、パケットオブジェクトには、以下に示すように、リテインフラグなどのメッセージプロパティに加えて、メッセージがバッファオブジェクトとして含まれています

```javascript
message is {"volts":240}
topic is testtopic
packet ={"cmd":"publish","retain":false,"qos":0,"dup":false,"length":27,"topic":"testtopic","payload":{"type":"Buffer","data":[123,34,118,111,108,116,115,34,58,50,52,48,125]},"properties":{"subscriptionIdentifier":1}}
```

## &#x20;サンプルコード

次のコードは `on.message()` 関数の一部です。

### メッセージが保持されているかを検出する

```javascript
console.log("packet retain =" +packet.retain);
if(packet.retain)
console.log("message is a retained message");
else
console.log("message is not retained message");
```

### メッセージからサブスクリプション識別子を抽出します

```
console.log("subscription Identifier= "+packet.properties.subscriptionIdentifier)
```

### 受信したJSONペイロードで作業する

受信したJSONペイロードを使用するには、まず次を使用してペイロードをJavaScriptオブジェクトに変換する必要があります:

```javascript
let message=JSON.parse(message);
```

受信したメッセージの例です

```javascript
message is {“volts”:240}
```

電圧を得るために、私たちは以下のことを行います

```javascript
let message=JSON.parse(message);
let volts=message.volts;
```

ペイロードがJSONでない可能性があるため、テストする必要があります。以下に示すように、try catchシーケンス（参照）を使用するのが最も簡単な方法です。

```javascript
try
{
message=JSON.parse(message);
let volts=message.volts
console.log("volts="+volts);
}
catch(err)
{
	console.log("not JSON");
}
```


# セッションとQoS

クライアントがブローカーに接続するとき、それは次のいずれかを使用して接続できます

* 非永続的な接続（クリーンセッション）または
* 持続的な接続

非永続的な接続では、ブローカーはクライアントのサブスクリプション情報や未配信メッセージを保存しません。

このモードは、クライアントがメッセージを公開するだけの場合に理想的です。

持続的な接続を使用して耐久性のあるクライアントとして接続することもできます

このモードでは、ブローカーはクライアントのサブスクリプション情報と未配信メッセージを保存します。

> ブローカーがクライアントのセッション情報を保存するためには、クライアントIDを使用する必要があります。

注意：クライアントに配信されたメッセージはブローカーから削除されます。メールメッセージが保存されるようには保存されません。

クライアントがブローカーに接続する際、永続的な接続が必要かどうかを示すために、フラグ（clean\_sessionフラグ）を使用します。

> しかし、サービスの品質や加入者と発行者の影響により、すべてのメッセージが配信用に保存されるわけではないことを理解することが重要です。

この例では、clean\_sessionフラグと品質保証設定がメッセージ配信に与える影響を見ていきます。

## 例の概要と目標

この例では、2つのクライアント接続を作成するPythonスクリプトを使用します。

一方の接続がトピックを購読し、もう一方の接続がそのトピックに対して公開します。

目的は、購読者が何らかの理由で接続が切断された場合に公開されたメッセージに何が起こるかを確認することであり、 `clean_session` フラグとQOS 設定がメッセージ配信にどのように影響するかを見ることです。

&#x20;**基本的なプロセス**

1. クライアントをclean\_sessionフラグを適切に設定して初期化します
2. トピックをQOS 設定で購読する
3. &#x20;切断します。
4. クライアントがサブスクライブしたトピックにQOSを設定して公開します。
5. &#x20;クライアントを再接続
6. 受信したメッセージをメモしてください

## Pythonクライアント設定

クリーンセッションフラグは、4つのオプショナルパラメーターを取るクライアントコンストラクターで設定されます。デフォルト値は以下の通りです：

```python
Client(client_id=””, clean_session=True, userdata=None, protocol=MQTTv311, transport=”tcp”)
```

スクリプトでクライアントインスタンスを作成するには：

```python
client= paho.Client("Python1",False) #create client object persistent connection
```

&#x20;翻訳テキスト：

```python
client= paho.Client("Python1",True) #create client object clean seesion
```

### &#x20;テスト1

* &#x20;clean\_session = True,
* 公開と購読のデフォルトQOS（サービス品質）は0です

予想される結果：ブローカーはメッセージを保存すべきではないため、メッセージは受信されません。

実際の結果：ブローカーがメッセージを保存していなかったため、再接続時にメッセージは受信されませんでした。

&#x20;スクリーンショット：

[![clean-session-1](https://github.com/Fubo-Group/docs/raw/main/images/clean-session-1.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/clean-session-1.jpg)

### &#x20;試験 2

* &#x20;clean\_session = False,
* 公開と購読のデフォルトQOS（サービス品質）は0です

予想される結果：メッセージが受信される。

実際の結果：再接続時にメッセージは受信されませんでした

コメント 重要なのは、clean\_sessionフラグをFalseに設定するだけでなく、QOSを1 以上でパブリッシュおよびサブスクライブする必要があることです。

しかし、サブスクリプション情報はブローカーによって記憶されているため、クライアントは再度サブスクリプションする必要はありません。

&#x20;スクリーンショット：

[![clean-session-2](https://github.com/Fubo-Group/docs/raw/main/images/clean-session-2.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/clean-session-2.jpg)

### &#x20;テスト 3

* &#x20;clean\_session = True, 翻訳テキスト：
* 公開と購読 QoS（品質保証）= 1

再接続時にメッセージが受信されないことが予想されます。

実際の結果：clean\_sessionフラグがtrueの場合、再接続時にメッセージは受信されませんでした。

&#x20;スクリーンショット

[![clean-session-3](https://github.com/Fubo-Group/docs/raw/main/images/clean-session-3.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/clean-session-3.jpg)

### &#x20;テスト4

* &#x20;clean\_session = False,
* 公開と購読 QoS（品質保証）= 1

予想される結果：再接続時にメッセージを受信すること。実際の結果：再接続時にメッセージを受信しました。

コメントクリーンセッションフラグはfalseで、公開と購読のQOSは0より大きいです。

[![clean-session-4](https://github.com/Fubo-Group/docs/raw/main/images/clean-session-4.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/clean-session-4.jpg)

###

### &#x20;テスト 5

* &#x20;clean\_session = False,
* 送信 QOS（品質保証）= 0 と受信 QOS（品質保証）= 1

予惜結果：？ 実際の結果：再接続時にメッセージが受信されない

コメントクリーンセッションフラグはfalseですが、公開時のQOSは0より大きくありません

[![clean-session-5](https://github.com/Fubo-Group/docs/raw/main/images/clean-session-5.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/clean-session-5.jpg)

以下の表は、QOS、クリーンセッションフラグ、および保持メッセージフラグが受信されるメッセージにどのように影響するかを示す要約です。

[![mqtt-qos-retain-clean-session-table](https://github.com/Fubo-Group/docs/raw/main/images/MQTT-qos-retain-clean-session-table.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/MQTT-qos-retain-clean-session-table.jpg)

&#x20;デモスクリプト

## クリーンセッションとクライアントID

永続的な接続では、接続の詳細がクライアントIDに対して保存されるため、永続的な接続（クリーンセッションがFalse）を使用する場合、ランダムなクライアントIDを使用することはできません。

## 一般的な質問と回答

**Q: ブローカーはどれくらいのメッセージを保存しますか？**

* A: これはブローカーの設定です。mosquittoブローカーのデフォルトは100です - 設定はmax\_queued\_messagesのカウントです。

**Q: クライアント接続を非永続的にリセットするにはどうすればいいですか？**

* A: 再接続するとセッションがクリーンに設定されます（True）

## &#x20;要約

MQTTは、電子メールのようなサービスと同じ方法でメッセージを保存しませんが、特定の状況下ではメッセージを保存します。

発行者と購読者のQOSによって、それらが保存されるかどうかが決まります。

しかし、購読者に受信され、認識されると、ブローカーはクリーンセッションとQOS 設定に関係なく、それらを直ちに削除します。


# MQTT セキュリティメカニズム

このチュートリアルでは、ブローカーへのアクセスを制限する方法と、さまざまなセキュリティメカニズムを使用してデータを保護する方法について説明します。

これらのセキュリティメカニズムはブローカーによって開始されることに注意することが重要であり、クライアントは設置されているメカニズムに従うことが求められます。

実装のセキュリティを計画する際には、MQTTクライアントの能力だけでなく、ブローカーの能力も考慮することが重要です。

このチュートリアルでは、無料のオープンソースFuboブローカーとPaho Python MQTTクライアントを使用して、これらのメカニズムを説明します。

## &#x20;クライアント認証

FuboブローカーがMQTTクライアントの身元を確認する方法は3つあります：

* &#x20;クライアントID
* ユーザー名とパスワード。
* &#x20;クライアント証明書

### &#x20;クライアントID

すべてのMQTTクライアントはクライアントIDを提供しなければなりません。

クライアントがトピックに登録すると、クライアントIDがそのトピックをクライアントおよびTCP 接続にリンクします。

持続的な接続では、ブローカーはクライアントIDと購読しているトピックを記憶します。

MQTTクライアントを設定する際には、クライアントに名前/IDを割り当てる必要がありますが、その名前は一般的には重要ではありません。ただし、それがユニークである限りです。

しかし、Fubo Brokerはクライアント名にクライアントIDプレフィックスの制限を課すことができ、これにより基本的なクライアントセキュリティが提供されます。

たとえば、クライアントIDにC1-というプレフィックスを選択することができ、その場合、クライアントIDがC1-python1のクライアントは許可されますが、IDがpython2のクライアントは許可されません。

この設定はFubo.confファイルのセキュリティ設定セクションにあります。

&#x20;クライアントIDプレフィックス C1-

### &#x20;ユーザー名とパスワード

MQTTブローカーは、接続が許可される前にクライアントから有効なユーザー名とパスワードを要求することができます。

ユーザー名/パスワードの組み合わせは平文で送信され、トランスポート暗号化の形式がなければ安全ではありません。

しかし、それはブローカーへのアクセス制限を容易にする方法を提供し、おそらく最も一般的な識別形式です。

認証に使用されるユーザー名は、トピックへのアクセス制限にも使用できます。

Fuboブローカーでは、これを機能させるために2つの設定を行う必要があります。再度、これらの設定はFubo.confファイルのセキュリティセクションで見つけることができます。

彼らは `allow_anonymous` と `password_file` です。ユーザー名/パスワードが必要な場合、 `allow_anonymous` は `false` でなければならず、 `password_file` には有効なパスワードファイルを含める必要があります。設定例

```
allow_anonymous false
password_file c:\Fubo\passwords.txt #Windows machine
```

パスワードを作成するには、Fuboブローカーに付属の `mosquiito_passwd` ユーティリティを使用する必要があります。

MQTTの例によるユーザー名とパスワード認証の探求を見る

## &#x20;x509クライアント証明書

これはクライアント認証の最も安全な方法ですが、多くのクライアントに証明書を展開して管理する必要があるため、実装が最も困難です。

この認証形式は、高いレベルのセキュリティが必要な少数のクライアントにのみ適しています。

SSLとSSL 証明書についての説明

## トピックへのアクセス制限

トピックに対して購読や公開ができるクライアントを制御できます。

主な制御メカニズムはユーザー名です（注：パスワードは不要ですが、クライアントIDも使用できます。

オープンブローカーを運用していない限り、このタイプの制限は一般的です。Fuboのトピック制限の設定と探索についてご覧ください。

## &#x20;データの保護

MQTTメッセージの内容を保護するためには、次の方法が使用できます：

* TLSまたはSSLセキュリティ
* &#x20;ペイロード暗号化

### &#x20;TLS セキュリティ

TLSセキュリティ、または一般的に知られているSSLセキュリティは、ウェブ上で使用される技術です。

このセキュリティはTCP/IPプロトコルの一部であり、MQTTではありません。

TLSセキュリティは、MQTTメッセージが流れる暗号化されたパイプを提供します。

これにより、MQTTメッセージのペイロードだけでなく、すべての部分が保護されます。

この問題は、クライアントのサポートが必要であり、シンプルなクライアントでは利用できない可能性が高いことです。

これを行う方法は3つあります：

* 自己生成証明書を使用して
* 無料商用証明書を使用する（レッツ・エンクリプト）
* 有料の商用証明書を使用して

### &#x20;ペイロード暗号化

これはアプリケーションレベルで行われ、ブローカーによってではありません。つまり、ブローカーを設定することなく暗号化されたデータを持つことができます。

データはブローカーとクライアント間だけでなく、端から端まで暗号化されています。

MQTTは結局のところメッセージングプロトコルです。

このタイプの暗号化は、接続自体のパスワード（使用されている場合）を保護しません。

ブローカーの設定やサポートを必要としないため、これはデータ保護の非常に人気のある方法になる可能性が高いです。

MQTTペイロードPython 例の暗号化を参照し、SSLまたはペイロード暗号化ディスカッションポスト

## 一般的な質問と回答

**Q: ペイロード暗号化でTLSを使用できますか？**

* &#x20;A: はい。

**Q: ペイロードの暗号化を実装するには、証明書が必要ですか？**

* 共有キーを使用できます。それは実装が簡単です。

**Q: メッセージが本物で変更されていないかどうかをどうやって知ることができますか？**&#x20;

* デジタル署名はこれを行う最良の方法ですが、公開/秘密鍵インフラストラクチャに依存しており、センサーのような制約のあるクライアントで実装される可能性は低いです。ただし、HMACのような簡単な代替手段があります。fuboセキュリティ記事を参照してください。

## &#x20;要約

MQTT 接続を保護するためのいくつかのメカニズムが利用可能です。

セキュリティ制限はMQTTブローカーによって施行され、クライアントはそれに応じて設定されなければなりません。


# MQTT 保持メッセージ

通常、出版者がトピックにメッセージを公開し、そのトピックに誰も登録していない場合、メッセージはブローカーによって単に破棄されます。

出版者は、保持メッセージフラグを設定することによって、そのトピックに関する最後のメッセージをブローカーに保持させるよう指示することができます。

この機能は非常に便利です。たとえば、状態が変化したときにのみその状態を公開するセンサー（例：ドアセンサー）がある場合、新しい購読者がこの状態に購読した場合はどうなるでしょうか？

保持されたメッセージがなければ、購読者はメッセージを受け取る前にステータスが変更されるのを待たなければならないでしょう。

しかし、保持されたメッセージにより、加入者はセンサーの現在の状態を確認できます。

重要なのは、トピックごとに1つのメッセージだけが保持されるということです。

そのトピックについて次に公開されるメッセージは、そのトピックの最後の保持メッセージを置き換えます。

## MQTT 保持メッセージの例の概要

このチュートリアルでは、Pythonスクリプトを使用してメッセージの公開と購読を行います。

その後、さまざまなフラグとQOS 設定で保持メッセージがどのように機能するかを調査します。

> 重要な点は、クライアントが購読する前にメッセージを公開することです。

混乱を避けるために、クリーンなセッションを使用していることもご留意ください。

クリーンセッションを使用しない場合、保存されているが保持されていないメッセージが表示されることがあります！

基本的なプロセスは次のとおりです：

1. トピックにメッセージを公開し、保持メッセージフラグを設定しないでください
2. トピックに関するメッセージを購読する
3. メッセージを監視し、結果を分析する

私たちは複数のメッセージを公開する方法と、保持されたメッセージを削除または削除する方法についても見ていきます。

以下のスクリーンショットを参照してください：

例 1 - メッセージ保持フラグが設定されておらず、新しいサブスクライバーはメッセージを受け取りません。つまり、メッセージは受信されません。

例 2 - メッセージフラグを保持し、新しいサブスクライバーは受信したメッセージに示される最後のメッセージを受け取ります。

例 3 - メッセージフラグを保持し、いくつかのメッセージOFF、OFF2、OFF3を公開します。しかし、新しいサブスクライバーは最後のメッセージOFF3のみを受け取ります。

[![retain-message-1](https://github.com/Fubo-Group/docs/raw/main/images/retain-message-1.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/retain-message-1.jpg)

### QOS 設定と保持メッセージと保持メッセージの削除

以下のスクリーンショットは、QOS 効果を示すための4つの接続例を示しており、その後で保持メッセージを削除する方法を説明しています。

例 1：QOSを0に設定して、QOS 設定が効果があるかどうかを確認します。保持されたメッセージがまだ受信されており、公開されたメッセージのQOSには影響がないことがわかります。

例 2：保持されたメッセージを保持メッセージフラグをFalseに設定して削除しようとします。しかし、メッセージがまだ保持されていることに気づきます。

例 3：メッセージを空白に設定しますが、保持メッセージフラグはFalseのままにします。再び、メッセージは保持されます。

例 4：最後にメッセージを空白に設定し、保持フラグを `true` に設定して、保持されたメッセージをクリアします。

[![retain-message-2](https://github.com/Fubo-Group/docs/raw/main/images/retain-message-2.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/retain-message-2.jpg)

以下の表は、QOS、クリーンセッションフラグ、および保持メッセージフラグがトピックの新しいサブスクライバーによって受信されるメッセージにどのように影響するかを示す要約です。

[![mqtt-qos-retain-clean-session-table](https://github.com/Fubo-Group/docs/raw/main/images/MQTT-qos-retain-clean-session-table.jpg)](https://github.com/Fubo-Group/docs/blob/main/images/MQTT-qos-retain-clean-session-table.jpg)

> 注意：retainフラグの扱い方の一部は、ブローカーの実装に依存します。

## &#x20;ソーステキスト: Pythonコード 翻訳テキスト:

公開するためのコードで、保持フラグが設定されています：

```
client.publish(“bulb1”,”test message “,qos=0,retain=True)
```

&#x20;どこで：

```
topic=bulb
nessage =test mesage
QOS=0
Reatained message Flag=True
```

## 検出された保持メッセージ

トピックを購読すると、保持されているメッセージがある場合、そのメッセージはクライアントに配信されます。

クライアントは、以下のコードスニペットに示されているように、on messageコールバックのmessage.retainフラグを調つことで、それが保持メッセージであることを検出できます。

```python
def on_message(client, userdata, message):
    print("message received  ",str(message.payload.decode("utf-8")),\
          "topic",message.topic,"retained ",message.retain)
    if message.retain==1:
        print("This is a retained message")
```

## &#x20;台本

私は、一連のトピックに保持されているメッセージをクリアし、保持メッセージがあるトピックについて報告するPythonスクリプトを作成しました。

&#x20;ダウンロード

## 一般的な質問と回答

**Q: 保持されたメッセージを削除するにはどうすればいいですか？ Translation Text:**

* A: 保持フラグをtrueに設定して空のメッセージを公開し、保持されたメッセージをクリアします。

**Q: メッセージのQOSは保持されたメッセージに影響を与えますか？**

* A: いいえ、違います。

**Q: メッセージが保持されているかどうかはどうすればわかりますか？ Translation Text:**

* A: トピックを購読して、保持フラグを調べるときにのみわかります。
* 質問: トピックを購読して保持メッセージを受け取った場合、ブローカー/サーバーはそのメッセージを削除しますか？
* A: いいえ、保持され、新しいクライアントが登録するときに設定されます。
* Q: Fuboで保持されているメッセージをすべて削除またはクリアするにはどうすればいいですか？
* A：永続データベースを使用していない場合、もっとも簡単な方法は、mosquittoを停止して再起動することです。それ以外の場合は、すべてのトピックを購読して保持メッセージを確認およびクリアする必要があります。これには私のPythonスクリプトを使用できます。ただし、これは忙しいブローカーではお勧めできません。

## いつ保持メッセージを使用するか

通常、メッセージに永続的なデータが含まれている場合、保持フラグが設定されたメッセージを公開します。

たとえば、センサーはファームウェアのバージョン番号、IPアドレス、現在の状態など、自身に関する情報を公開することができます。

この情報は変更される可能性が低いため、retainフラグを使用して一度だけ公開する必要があります。そうすれば、新しいクライアントはその情報を取得できます。

## 保持メッセージをデータストアとして使用する

私は、保持されたメッセージがデータストアとして使用されているアプリケーションを見たことがあります。

もし私のホームアシスタントとMQTTに関するチュートリアルを見ていただければ、その動作を確認できます。

可能であることは認識していますが、例えば誰かがクリーンアップの一環として保持されているメッセージを削除した場合の結果を考慮する必要があります。

## 保持メッセージ形式の提案

保持されたメッセージがセミ永続的/永続的なデータストアとして使用されているため、実際のメッセージペイロードと一環して追加情報を公開することが私の意見では有用です。

最低限、タイムスタンプと削除許可フラグを公開する必要があります。そうすれば私たちは

```
{"payload":payload,"timestamp":timestamp,"delete_allowed":True/False}
```

削除ユーティリティはこれらをチェックし、非常に古いメッセージを削除することができますが、削除してはならないメッセージは削除しません。

## &#x20;要約

保持メッセージ機能は、オブジェクトの最後の状態を保持するための便利な機能であり、状態が頻繁に変わらない場合に特に便利です。

サービス品質の設定は保持メッセージに影響しません。


