IoTのIntel Edison:MQTTを使用してタッチノードをインターネットに安全に接続する

すでにMQTTブローカー、Intel Edisonに基づいてセンサーノードを組み立てる方法について書いています 。 デバイスには、ボタン、モーション、温度、および光センサーが含まれています。 今日、これらすべてをMosquitto MQTTサーバーに接続し、双方向通信を確立し、デザインをモノのインターネットの本格的な一部にします。







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_subh localhostt 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サーバーに接続できます。



  1. 開いているポートを介して、つまり保護なしで。 これは、MQTTデバイスを実際に使用する前に開発およびテストする場合に便利です。 ブローカーとクライアント間のデータは、暗号化されずにプレーンテキストで送信されます。 その結果、それらは簡単に傍受されます。



  2. ユーザー名とパスワードを使用します。 この方法を使用すると、ブローカーはクライアントの信頼性を検証できます。 ただし、データは送信中に暗号化されません。



  3. TLS-PSK暗号化を使用します。 クライアントとブローカーは、安全な接続を確立するために使用される共通の秘密鍵を共有します。 この機能は、Mosquitto 1.3.5以降で使用できます。



  4. 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ソフトウェアが利用可能です。 このアプローチにはいくつかの利点があります。



  1. Arduino用にMQTTクライアントを書き換える必要はありません。 Mosquitto MQTTは、よく知られ、十分にテストされたコードです。 Arduinoスケッチで使用できるように、ラッパークラスを作成する必要があります。



  2. Mosquitto MQTTクライアントは、安全なSSL接続をサポートしています。 同時に、通常のArduinoの低電力マイクロコントローラーは、SSLの計算要件を満たしていません。



  3. より高度な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ブローカーに接続するさまざまな変数を初期化する必要があります。 これらの変数の説明は次のとおりです。





トピックをサブスクライブするには、トピックの名前と、新しいメッセージが到着したときに起動されるコールバック関数を使用して、 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つで、センサーとアクチュエータを備えたセンサーアセンブリのアセンブリについて説明しました。 つまり、これがデバイスの構成要素であり、作成されたものです。



  1. 動きを検出するモーションセンサー。

  2. 周囲温度を測定できる温度センサー。

  3. 光を測定する光センサー。

  4. ターゲットユーザーのアクションを認識できるコマンドボタン。 この場合、ボタンを押します。

  5. ボタンを押すとオン/オフする赤色のLED。

  6. モーションセンサーがトリガーされると点灯する緑色のLED。









Intel Edison Touchノード



MQTTを使用して、さまざまなセンサーのインジケーターを定期的に発行し、同じIntel Edisonシステムで実行されるMosquittoブローカーにメッセージを渡します。 すべてのトピック、つまり「edison /#」を購読します。 さらに、センサーノードのロジックにいくつかの変更を加えます。



  1. コマンドボタンは、赤色のLEDをオンおよびオフにしなくなります。 これをクリックすると、論理変数の値を変更する信号として機能し、MQTTサブスクライバーに送信されます。



  2. 赤いLEDは、MQTTメッセージを使用してオンおよびオフになります。 同様のメカニズムが、インターネット経由で制御可能な照明器具のアクセスモジュールの役割を果たすことができます。



  3. 緑色の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用に作成されたオープンソースパッケージを簡単に使用できます。



All Articles