MQTT
MQTTパブリッシャー/サブスクライバーモデル
MQTTは、マシン間通信を整理するための一般的なプロトコルの1つです(M2M、Machine to Machine)。 「パブリッシャー-サブスクライバー」の原則に基づいて動作し、TCP / IPに基づいて構築されます。 MQTTの2つの主要コンポーネントは、クライアントとブローカーです。 MQTTクライアントは、特定のトピック(トピック)でメッセージを公開するか、メッセージをサブスクライブしてそれらを聞きます。 MQTTブローカーは、パブリッシャーによって発行されたすべてのメッセージを受信し、関連するメッセージをサブスクライバーにリダイレクトします。 サブスクライバーとパブリッシャーはお互いについて知る必要はありません。メッセージトピックとメッセージ自体のみが役割を果たします。 パブリッシャーとサブスクライバーは、通常の対話を整理するために、共通のトピック名とメッセージ形式を使用する必要があります。
メッセージを公開する、または特定のトピックのメッセージをサブスクライブするには、MQTTクライアントが必要です。 Mosquitto MQTTディストリビューションでは、メッセージを発行するクライアントはmosquitto_pubと呼ばれ、メッセージをサブスクライブするクライアントはmosquitto_subと呼ばれます。
これがメッセージングの外観です。これについては以下で説明します。 赤いウィンドウは、クライアントサブスクライバーの作業を示し、黒はクライアントパブリッシャーの作業を示します。 チームには、参照しやすいようにタグが付けられています。
サブスクライバーパブリッシャーインタラクション
サブスクライブするクライアントに必要な引数の最小セットは、ブローカーのIPアドレスとメッセージの件名、およびパブリッシャークライアントの場合はメッセージテキストです。 MQTTブローカーが127.0.0.1(localhost)で利用できる場合、以下に示すコマンドは、件名「edison / hello」で発行されたすべてのメッセージのリスニングを有効にします。
sub 3> mosquitto_sub –h localhost –t edison/hello
そして、件名が「edison / hello」のメッセージを投稿する方法を次に示します。
pub 3> mosquitto_pub –h localhost –t edison/hello –m "Message#1: Hello World!"
MQTTブローカーが、件名「edison / hello」のパブリッシャークライアント(pub 3)からメッセージ「Message#1:Hello World」を受信すると、ブローカーは件名「edison / hello」にサブスクライブしているクライアントのリストをスキャンします。 サブスクライバー・クライアント(サブ3)が指定されたトピックにサブスクライブされていることを検出すると、MQTTブローカーはメッセージをこのクライアントにリダイレクトします。
サブスクライバーはメッセージを受信すると、ターミナルウィンドウに表示します。 Sub 3 SubscriberおよびPub 3 Publisherのコマンドでは、デフォルトのMQTTポート番号が暗黙的に設定されているため(1833)、コマンドラインには示されていません。 sub 4およびpub 4コマンドでは、ポート番号が指定されています。 sub 5およびpub 5コマンドでは、-vオプションがサブスクリプション引数に追加されました。 これにより、メッセージだけでなくトピックの名前も端末ウィンドウに表示できます。 これは、テンプレートを使用して複数のトピックをサブスクライブするときに役立ちます。 サブスクライバクライアントが自動的に破棄されない場合、たとえばpub 6コマンドを使用して「edison / hello」という件名で発行された追加のメッセージは、このサブスクライバにリダイレクトされます。
MQTTブローカーの標準的な動作は、顧客に配信された直後にメッセージを破棄することです。 pub 7クライアントは新しいトピック「edison / hello1」を含むメッセージを発行しますが、サブ5サブスクライバークライアントはトピック「edison / hello」を含むメッセージを待機しているため、pub 7からのメッセージを受信しません。 次に、サブスクライバークライアント、サブ6は、トピック「edison / hello1」にサブスクライブしますが、既に破棄されているため、このトピックで以前に送信されたメッセージも受信しません。 彼は、このトピックとともに発行された次のメッセージ(たとえば、pub 8行で発行されたメッセージ)のみを受け取ります。
特定のトピックで発行された最後のメッセージを保持するようにMQTTブローカーに指示する追加のパラメーターがあります。 ブローカーがメッセージを配信する方法に影響するQuality of Service(QoS)を構成できるディレクティブもあります。 これらの機能の詳細は、 MQTT Wikiに記載されています。
ポート設定によっては、追加の引数が必要になる場合があります。 後でこの問題に戻ります。
複数のトピックを購読する
通常、実際にはMQTTクライアントが使用されます。MQTTクライアントは、いくつかのトピックにサブスクライブされ、受信したメッセージに応じてさまざまなアクションを実行します。 MQTTトピックについて話しましょう。
MQTTトピックは、階層構造に編成されています。 「/」記号は、トピックの論理レベルを強調するために使用されます。 論理的に設計されたトピックスペースは次のようになります。
Temperature/Building1/Room1/Location1 Temperature/Building1/Room1/Location2 Temperature/Building2/Room2 Temperature/Outdoor/West Temperature/Outdoor/East Temperature/Average
サブスクライバーは、テンプレートを使用して、特定のトピック(「温度/屋外/西」など)をサブスクライブできます。
MQTTには、「+」と「#」の2つのワイルドカード文字があります。 「+」記号は、同じ階層レベルにあるトピックをサブスクライブするために使用されます。 記号「#」は、特定のトピックのすべてのサブセクションにサブスクライブするために使用されます。
たとえば、「Temperature /#」にサブスクライブすると、例のトピックのいずれかを含むメッセージがクライアントに配信されます。 「Temperature / +」にサブスクライブすると、クライアントは件名が「Temperature / Average」のメッセージのみを受信します。これは、他のすべてのトピックが下位階層レベルにあるためです。 MQTTテーマスペースの編成の詳細については、 MQTT Wikiを参照してください 。
安全なMosquittoブローカーのセットアップ
MQTTクライアントは、主に4つの方法でMosquittoサーバーに接続できます。
- 開いているポートを介して、つまり保護なしで。 これは、MQTTデバイスを実際に使用する前に開発およびテストする場合に便利です。 ブローカーとクライアント間のデータは、暗号化されずにプレーンテキストで送信されます。 その結果、それらは簡単に傍受されます。
- ユーザー名とパスワードを使用します。 この方法を使用すると、ブローカーはクライアントの信頼性を検証できます。 ただし、データは送信中に暗号化されません。
- TLS-PSK暗号化を使用します。 クライアントとブローカーは、安全な接続を確立するために使用される共通の秘密鍵を共有します。 この機能は、Mosquitto 1.3.5以降で使用できます。
- SSL暗号化を使用します。 これは、Mosquitto MQTTで利用可能な最も高度な暗号化および認証スキームです。 SSLを使用する場合、VerisignやEquifaxなどの信頼できる認証局(Certificate Authority、CA)からサーバー証明書を取得する必要があります。 多くの場合、テストのために、サーバー証明書の署名に使用できる自己生成証明書を作成します。 SSLを使用すると、高度なセキュリティを実現できますが、このようなスキームを実装することは他のスキームよりも困難です。 実際、SSLを使用する場合、すべてのクライアントデバイスに適切な証明書を提供する必要があります。 さらに、システムの運用中にクライアント証明書とブローカー証明書の一貫性を維持するための更新メカニズムを開発する必要があります。
次の構成ディレクティブを使用して、Mosquitto MQTTセキュアブローカーを構成します。 テスト目的に適した自己生成証明書を使用します。 このような証明書は、運用サーバーでは使用しないでください。
port 1883 password_file /home/mosquitto/conf/pwdfile.txt log_type debug log_type error log_type warning log_type information log_type notice user root pid_file /home/mosquitto/logs/mosquitto.pid persistence true persistence_location /home/mosquitto/db/ log_dest file /home/mosquitto/logs/mosquitto.log listener 1995 # 1995 TLS-PSK, # --psk-identity --psk psk_file /home/mosquitto/conf/pskfile.txt # psk_hint, 1995 psk_hint hint listener 1994 # 1994 SSL-, # , , # , , ca.crt cafile /home/mosquitto/certs/ca.crt certfile /home/mosquitto/certs/server.crt keyfile /home/mosquitto/certs/server.key
この例のpwdfile.txtファイルは、Linuxパスワードファイルと同じ方法で暗号化されたパスワードファイルです。 Mosquittoに同梱されているmosquitto_passwdユーティリティを使用して作成できます。 pskfile.txtファイルは、以前にクライアントとサーバーでホストされていたパスワードファイルです。 TLS-PSKを使用して接続を確立するために使用されます。 これは通常のテキストファイルで、各行には「user:password」という形式のペアが1つ含まれています。 TLS-PSKに使用されるパスワードは大文字と小文字を区別せず、16進文字のみを含めることができます。 パスワードファイルとPSKファイルの例を次に示します。
/* Mosquitto */ user:$6$Su4WZkkQ0LmqeD/X$Q57AYfcu27McE14/MojWgto7fmloRyrZ7BpTtKOkME8UZzJZ5hGXpOea81RlgcXttJbeRFY9s0f+UTY2dO5xdg== /* PSK- Mosquitto */ user1:deadbeef user2:DEADBEEF0123456789ABCDEF0123456789abcdef0123456789abcdef0123456789abcdef <h1> MQTT </h1>
Intel Edisonは、プロセスの1つとしてArduinoのプログラム(スケッチ)を実行できるLinuxシステムであるため、既に準備したMosquitto MQTTパッケージを使用できます。 スケッチ内では、 mosquitto_subおよびmosquitto_pubを呼び出すためのLinuxソフトウェアが利用可能です。 このアプローチにはいくつかの利点があります。
- Arduino用にMQTTクライアントを書き換える必要はありません。 Mosquitto MQTTは、よく知られ、十分にテストされたコードです。 Arduinoスケッチで使用できるように、ラッパークラスを作成する必要があります。
- Mosquitto MQTTクライアントは、安全なSSL接続をサポートしています。 同時に、通常のArduinoの低電力マイクロコントローラーは、SSLの計算要件を満たしていません。
- より高度なMQTTパッケージが発見された場合、またはすでに使用されているものの新しいバージョンがリリースされた場合、既存のコードの大部分を再利用し、イノベーションのサポートで補足することができます。
クラスMQTTClient
Intel Edisonはフル機能のLinux OSを実行しているため、すべてのLinux開発ツールはArduinoプログラムで使用できます。 スケッチに関与するラッパークラスMQTTClientを作成します。 MQTTClietnメソッドでは、Linuxシステムコールを使用してmosquitto_subおよびmosquitto_pubを呼び出し、MQTTプロトコルを使用して通信タスクを処理します。 以下に、MQTTClentクラスの説明を示しますが、最低限必要な機能によって制限されています。
// : MQTTClient.h /* MQTT-, mosquitto_sub mosquitto_pub , Mosquitto MQTT mosquitto_pub/sub */ #ifndef __MQTTClient_H__ #define __MQTTClient_H__ #include <Arduino.h> #include <stdio.h> enum security_mode {OPEN = 0, SSL = 1, PSK = 2}; class MQTTClient { public: MQTTClient(); ~MQTTClient(); void begin(char * broker, int port, security_mode mode, char* certificate_file, char *psk_identity, char *psk); boolean publish(char *topic, char *message); boolean subscribe(char* topic, void (*callback)(char *topic, char* message)); boolean loop(); boolean available(); void close(); private: void parseDataBuffer(); FILE* spipe; char mqtt_broker[32]; security_mode mode; char topicString[64]; char certificate_file[64]; char psk_identity[32]; char psk_password[32]; int serverPort; char *topic; char *message; boolean retain_flag; void (*callback_function)(char* topic, char* message); char dataBuffer[256]; }; #endif
このクラスを使用するには、MQTTClientオブジェクトの作成から開始し、 MQTTClient :: begin()を呼び出してMQTTClient :: subscribe()およびMQTTClient :: publish()を使用してMQTTブローカーに接続するさまざまな変数を初期化する必要があります。 これらの変数の説明は次のとおりです。
- mqtt_broker :MQTTブローカーの名前。 IPアドレスまたはDNS名を指定できます。 この場合、ブローカーはスケッチと同じIntel Edisonボードで実行されるため、「localhost」を使用します。 Edisonが静的IPアドレスを使用するように構成されている場合、「localhost」の代わりに使用できます。
- serverPort :使用されるポート。 Mosquittoブローカーに3つの異なるポートを割り当てました。それぞれに独自のセキュリティポリシーがあります。
- 1883はデフォルトのMQTTポートであり、すべてのクライアントに対して開かれています。
- 1994は安全なSSLポートとして設定されています。 このようなポートに接続するクライアントには、サーバー証明書を発行した証明機関が発行したSSL証明書が必要です。
- 1995は安全なTLS-PSKポートです。 これにアクセスするには、ユーザー名とパスワードが必要です。これは、システムのクライアント部分とサーバー部分の両方で事前に知られています。
- mode :使用するセキュリティモード。 この例には、OPEN、SSL、およびPSKの3つのモードがあります。 選択したセキュリティモードに応じて、証明書またはユーザー名とパスワードが他の引数でメソッドに渡されます。 選択したセキュリティモードで使用されない引数は無視されます。
トピックをサブスクライブするには、トピックの名前と、新しいメッセージが到着したときに起動されるコールバック関数を使用して、 MQTTClient:subscribe()メソッドを呼び出します。 特定の件名でメッセージを公開するには、 MQTTClient:publish()を件名とメッセージ名で呼び出します。
メッセージをサブスクライブする方法とパブリケーションの方法の両方で、 mosquitto_subまたはmosquitto_pubを呼び出し、引数メソッドと保存されたパラメーターを使用する適切なコマンドが生成されます。 次に、Linuxチャネルが開き、コマンドが実行され、結果がチャネルを介してスケッチに返されます。
公開するとき、チャネルはメッセージを送信した直後に閉じます。 サブスクライブするときは、新しいデータを受信できるようにチャネルを開いたままにしておく必要があります。 MQTTClient:loop()メソッドは、チャネル内のデータを定期的にチェックし、コールバック関数を呼び出して新しいメッセージを処理するように設計されています。 Linuxチャネルはブロックされるため、検証中にLinuxチャネルに何もない場合、チャネルを非ブロックにしました。 したがって、 MQTTClient:loop()メソッドでのチェック中にチャネルが空であることが判明した場合、メソッドからすぐに戻ります。 以下の疑似コードは、MQTTClientクラスの一般的な使用法を示しています。
#include <MQTTClient.h> #define SAMPLING_PERIOD 100 #define PUBLISH_INTERVAL 30000 MQTTClient mqttClient; void setup() { mqttClient.begin("localhost",1833,PSK,NULL,"psk_user","psk_password"); mqttClient.subscribe("edison/#",myCallBack); } void myCallBack(char* topic, char* message) { // , , } unsigned long publishTime = millis(); void loop() { mqttClient.loop(); // if (millis() > publishTime) { publishTime = millis() + PUBLISH_INTERVAL; mqttClient.publish("edison/sensor1","sensor1value"); mqttClient.publish("edison/sensor2","sensor2value"); } delay(SAMPLING_PERIOD); }
変数「 SAMPLING_PERIOD 」は、新しいメッセージがチェックされる頻度を設定します。 この変数の値は、Arduinoプログラムの一部でアクションをトリガーするメッセージが遅く到着して意味を失わないように選択する必要があります。
作業時間のほとんどで、 MQTTClietn:loop()メソッドは非常に迅速に終了するため、このメソッドを頻繁に呼び出すと、システムの負荷が非常に小さくなります。 メッセージが公開される間隔は、 PUBLISH_INTERVAL変数を使用して設定されます。 間隔の長さは、センサーがデータを公開する頻度に対応する必要があります。 たとえば、温度センサーは、インジケータが情報目的で使用される場合、室温情報を1分に1回公開する場合があります。 ただし、煙センサーが数秒ごとにデータを公開するのは理にかなっています。そのため、センサーがトリガーされた場合にメッセージを待っているサブスクライバーは、手遅れになる前に何かをする機会があります。
MQTTClientクラスの実装は次のとおりです。
// : MQTTClient.cpp #include "MQTTClient.h" #include <fcntl.h> /*====================================================================== / ========================================================================*/ MQTTClient::MQTTClient() { } MQTTClient::~MQTTClient() { close(); } void MQTTClient::close() { if (spipe) { fclose(spipe); } } /*======================================================================== . ==========================================================================*/ void MQTTClient::begin(char *broker, int port, security_mode smode, char* cafile, char *user, char *psk) { strcpy(mqtt_broker, broker); serverPort = port; mode = smode; if (mode == SSL) { strcpy(certificate_file, cafile); } else if (mode == PSK) { strcpy(psk_identity, user); strcpy(psk_password, psk); } Serial.println("MQTTClient initialized"); Serial.print("Broker: "); Serial.println(mqtt_broker); Serial.print("Port: "); Serial.println(serverPort); Serial.print("Mode: "); Serial.println(mode); } /*======================================================================= , (*callback) , , . =========================================================================*/ boolean MQTTClient::subscribe(char* topic, void (*callback)(char* topic, char* message)) { char cmdString[256]; if (mqtt_broker == NULL) { return false; } if (topic == NULL) { return false; } callback_function = callback; switch(mode) { case OPEN: sprintf(cmdString, "mosquitto_sub -h %s -p %d -t %s -v", mqtt_broker, serverPort, topic); break; case SSL: sprintf(cmdString, "mosquitto_sub -h %s -p %d -t %s -v --cafile %s", mqtt_broker, serverPort, topic, certificate_file); break; case PSK: sprintf(cmdString, "mosquitto_sub -h %s -p %d -t %s -v --psk-identity %s --psk %s", mqtt_broker, serverPort, topic, psk_identity, psk_password); break; default: break; } if ((spipe = (FILE*)popen(cmdString, "r")) != NULL) { // int fd = fileno(spipe); int flags = fcntl(fd, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); strcpy(topicString, topic); return true; } else { return false; } } /*==================================================================== , , , . , . ======================================================================*/ boolean MQTTClient::loop() { if (fgets(dataBuffer, sizeof(dataBuffer), spipe)) { parseDataBuffer(); callback_function(topic, message); } } /*==================================================================== . ======================================================================*/ boolean MQTTClient::publish(char *topic, char *message) { FILE* ppipe; char cmdString[256]; boolean retval = false; if (this->mqtt_broker == NULL) { return false; } if (topic == NULL) { return false; } switch (this->mode) { case OPEN: sprintf(cmdString, "mosquitto_pub -h %s -p %d -t %s -m \"%s\" %s", mqtt_broker, serverPort, topic, message, retain_flag?"-r":""); break; case SSL: sprintf(cmdString, "mosquitto_pub -h %s -p %d --cafile %s -t %s -m \"%s\" %s", mqtt_broker, serverPort, certificate_file, topic, message, retain_flag?"-r":""); break; case PSK: sprintf(cmdString, "mosquitto_pub -h %s -p %d --psk-identity %s --psk %s -t %s -m \"%s\" %s", mqtt_broker, serverPort, psk_identity, psk_password, topic, message, retain_flag?"-r":""); break; } if (!(ppipe = (FILE *)popen(cmdString, "w"))) { retval = false; } if (fputs(cmdString, ppipe) != EOF) { retval = true; } else { retval = false; } fclose(ppipe); return retval; } /*====================================================================== , . . , , NULL ========================================================================*/ void MQTTClient::parseDataBuffer() { topic = dataBuffer; message = dataBuffer; while((*message) != 0) { if ((*message) == 0x20) { // NULL (*message) = 0; message++; break; } else { message++; } } if (strlen(message) == 0) { topic = NULL; message = dataBuffer; } } <h2> </h2>
以前の出版物の1つで、センサーとアクチュエータを備えたセンサーアセンブリのアセンブリについて説明しました。 つまり、これがデバイスの構成要素であり、作成されたものです。
- 動きを検出するモーションセンサー。
- 周囲温度を測定できる温度センサー。
- 光を測定する光センサー。
- ターゲットユーザーのアクションを認識できるコマンドボタン。 この場合、ボタンを押します。
- ボタンを押すとオン/オフする赤色のLED。
- モーションセンサーがトリガーされると点灯する緑色のLED。
Intel Edison Touchノード
MQTTを使用して、さまざまなセンサーのインジケーターを定期的に発行し、同じIntel Edisonシステムで実行されるMosquittoブローカーにメッセージを渡します。 すべてのトピック、つまり「edison /#」を購読します。 さらに、センサーノードのロジックにいくつかの変更を加えます。
- コマンドボタンは、赤色のLEDをオンおよびオフにしなくなります。 これをクリックすると、論理変数の値を変更する信号として機能し、MQTTサブスクライバーに送信されます。
- 赤いLEDは、MQTTメッセージを使用してオンおよびオフになります。 同様のメカニズムが、インターネット経由で制御可能な照明器具のアクセスモジュールの役割を果たすことができます。
- 緑色のLEDの動作は、MQTTを使用して調整できます。 つまり、モーションセンサーがトリガーされたときにオンにすることも、常にオフのままにすることもできます。
基本的なスケッチコードを次に示します。
// : MQTT_IoT_Sensor.ino /****************************************************************************** , Intel Edison ******************************************************************************/ #include <stdio.h> #include <Arduino.h> #include "sensors.h" #include "MQTTClient.h" // unsigned long updateTime = 0; // volatile unsigned long activityMeasure; volatile unsigned long activityStart; volatile boolean motionLED = true; unsigned long resetActivityCounterTime; // boolean toggleLED = false; volatile unsigned long previousEdgeTime = 0; volatile unsigned long count = 0; volatile boolean arm_alarm = false; // MQTT- #define SECURE_MODE 2 MQTTClient mqttClient; char fmtString[256]; // char topicString[64]; // char msgString[64]; // /***************************************************************************** ******************************************************************************/ void setup() { Serial.begin(115200); delay(3000); Serial.println("Ready"); pinMode(RED_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); pinMode(BUTTON, INPUT_PULLUP); pinMode(PIR_SENSOR, INPUT); // . attachInterrupt(BUTTON, buttonISR, RISING); // . attachInterrupt(PIR_SENSOR, pirISR, CHANGE); digitalWrite(RED_LED, HIGH); digitalWrite(GREEN_LED,LOW); resetActivityCounterTime = 0; // MQTTClient #if ( SECURE_MODE == 0 ) Serial.println("No security"); mqttClient.begin("localhost", 1883, OPEN, NULL, NULL, NULL); #elif ( SECURE_MODE == 1 ) Serial.println("SSL security"); mqttClient.begin("localhost", 1994, SSL, "/home/mosquitto/certs/ca.crt", NULL, NULL); #elif ( SECURE_MODE == 2 ) Serial.println("TLS-PSK security"); mqttClient.begin("localhost", 1995, PSK, NULL, "user", "deadbeef"); #endif // edison mqttClient.subscribe("edison/#", mqttCallback); mqttClient.publish("edison/bootMsg","Booted"); digitalWrite(RED_LED, LOW); } /************************************************************************** MQTT **************************************************************************/ void mqttCallback(char* topic, char* message) { sprintf(fmtString, "mqttCallback(), topic: %s, message: %s",topic,message); Serial.print(fmtString); // if (strcmp(topic,"edison/LED") == 0) { // if (message[0] == 'H') { digitalWrite(RED_LED, HIGH); toggleLED = false; } else if (message[0] == 'L') { digitalWrite(RED_LED, LOW); toggleLED = false; } else if (message[0] == 'B') { toggleLED = true; } } if (strcmp(topic, "edison/motionLED") == 0) { // , // . // strncmp , if (strncmp(message, "OFF", 3) == 0) { digitalWrite(GREEN_LED, LOW); motionLED = false; } else if (strncmp(message, "ON", 2) == 0) { motionLED = true; } } } /*********************************************************************** ***********************************************************************/ void loop() { // , mqtt_sub mqttClient.loop(); if (millis() > resetActivityCounterTime) { resetActivityCounterTime = millis() + 60000; // , sprintf(msgString,"%.0f",100.0*activityMeasure/60000.0); mqttClient.publish("edison/ActivityLevel",msgString); activityMeasure = 0; } if (millis() > updateTime) { updateTime = millis() + 10000; // sprintf(msgString,"%.1f",readTemperature(TEMP_SENSOR)); mqttClient.publish("edison/Temperature",msgString); // sprintf(msgString,"%d",readLightSensor(LIGHT_SENSOR)); mqttClient.publish("edison/LightSensor",msgString); // arm_alarm sprintf(msgString,"%s", (arm_alarm == true)? "ARMED" : "NOTARMED"); mqttClient.publish("edison/alarm_status", msgString); } if (toggleLED == true) { digitalWrite(RED_LED, digitalRead(RED_LED) ^ 1); } delay(100); }
. , , , , sensor.h sensor.cpp .
SECURE_MODE Arduino- . , mqttCallback(), , MQTT-. , , , . , , , .
– , IoT- . «edison/LED» , . «edison/motionLED» . , .
// : sensors.h // #define USE_TMP036 0 #define RED_LED 10 // #define GREEN_LED 11 // #define BUTTON 13 // 10K #define PIR_SENSOR 12 // #define LIGHT_SENSOR A0 // #define TEMP_SENSOR A1 // TMP36 LM35 #define MIN_PULSE_SEPARATION 200 // #define ADC_STEPSIZE 4.61 // , . #if (USE_TMP036 == 1) #define TEMP_SENSOR_OFFSET_VOLTAGE 750 #define TEMP_SENSOR_OFFSET_TEMPERATURE 25 #else // LM35 temperature sensor #define TEMP_SENSOR_OFFSET_VOLTAGE 0 #define TEMP_SENSOR_OFFSET_TEMPERATURE 0 #endif // extern unsigned long updateTime; // extern volatile unsigned long activityMeasure; extern volatile unsigned long activityStart; extern volatile boolean motionLED; extern unsigned long resetActivityCounterTime; // extern boolean toggleLED; extern volatile unsigned long previousEdgeTime; extern volatile unsigned long count; extern volatile boolean arm_alarm; float readTemperature(int analogPin); int readLightSensor(int analogPin); void buttonISR(); void pirISR(); // : sensors.cpp #include <Arduino.h> #include "sensors.h" /*********************************************************************************** , , HIGH , . , HIGH 2-3 , LOW. HIGH, . ************************************************************************************/ void pirISR() { int pirReading; unsigned long timestamp; timestamp = millis(); pirReading = digitalRead(PIR_SENSOR); if (pirReading == 1) { // activityStart = timestamp; } else { int pulseWidth = timestamp-activityStart; activityMeasure += pulseWidth; } // , if (motionLED == true) { digitalWrite(GREEN_LED, pirReading); } } /************************************************************************ ************************************************************************/ int readLightSensor(int sensorPin) { return analogRead(sensorPin); } /*********************************************************************** ***********************************************************************/ float readTemperature(int sensorPin) { int sensorReading; float temperature; sensorReading = analogRead(sensorPin); // temperature = sensorReading * ADC_STEPSIZE; // LM35, TMP036, : // 10 // LM35 – 0 , TMP036 - 750 // LM35 – 0 , TMP036 – 25 . temperature = (temperature - TEMP_SENSOR_OFFSET_VOLTAGE)/10.0 + TEMP_SENSOR_OFFSET_TEMPERATURE; // temperature = temperature * 1.8 + 32.0; return temperature; } /************************************************************************* **************************************************************************/ void buttonISR() { // , if ((millis()-previousEdgeTime) >= MIN_PULSE_SEPARATION) { arm_alarm = !arm_alarm; Serial.print("Alarm is: "); if (arm_alarm == true) { Serial.println("ARMED"); } else { Serial.println("NOT ARMED"); } count++; Serial.print("Count: "); Serial.println(count); } previousEdgeTime=millis(); }
テスト中
, , MQTT- , , – , .
Edison SSH mosquitto_sub/pub . -, Mosquitto.
, .
, , :
$> mosquitto_sub –h ipaddr –p 1883 –t edison/# -v
ipaddr – IP- Intel Edison. Edison, IP- «localhost». , 1883. 1994, SSL-. 1995, PSK, . «edison/#» , .
, , «edison/LED», , «edison/motionLED», .
$> mosquitto_pub –h ipaddr –p 1883 –t Edison/LED –m {H, L, B} $> mosquitto_pub –h ipaddr –p 1883 –t Edison/motionLED –m {ON, OFF}
(H, L, B) , .
, , , , ON OFF.
, .
結論
比較的複雑なソフトウェアシステムMosquitto MQTTを使用し、Intel Edisonボード上のLinuxプログラミングメカニズムを使用してスケッチから動作させる方法を学びました。同じ原理は、Arduinoプラットフォーム用に開発され、さまざまなセンサーをサポートするように設計された多くのライブラリへのアプローチを見つけるのに役立ちます。この場合はArduinoプログラムの基盤であるLinuxを使用すると、Linux用に作成されたオープンソースパッケージを簡単に使用できます。