Translate

2015年7月27日月曜日

PubSubClientライブラリを使ってArduino YUNをMQTTのSubscriberにする




ArduinoでIoTする場合、MQTT Publisherとして動作させる
わけだが、水位が30%を切ったらモータを動かすなどの処理を書く場合は
MQTT Subscriberとして実装し無くてはならない。

PubSubClientライブラリはSubと名前にも入っているとおり
Subscriberとして動作する場合の実装にも利用可能である。

以下のサンプルコードは、IBM IoT Foudationに到着するデータのうち
チケット名が「iot-2/type/arduino/id/ffffffffffff/evt/status/fmt/json」である
もののみ受け取るSubscriberとして実装する例である。

MQTTブローカとのアクセスにはPubSubClientライブラリを、
http://knolleary.net/arduino-client-for-mqtt/
受信JSONデータをparseするためにArduinoJsonライブラリを
https://github.com/bblanchon/ArduinoJson
それぞれダウンロードして使用している。

1点注意。以下のコードはArduino YUN(Bridgeライブラリ)ベースで記述しているので
環境にあわせてWiFiライブラリやEthernet2ライブラリに書きなおして
動作させること。

2015/11/20 追記)
ヘッダファイル名がそっくり消えてしまってました。すみません。


#include <SPI.h>
#include <Bridge.h>
#include
<YunClient.h>
#include <PubSubClient.h>
#include
<ArduinoJson.h>

// MQTTブローカ
char server[] = "hogehoge.messaging.internetofthings.ibmcloud.com";

// Subscriberとして認証
// IoT FoundationでAPIキー生成
char username[] = "a-hogehoge-xxxxxxxxxx";
char password[] = "xxxxxxxxxxxxxxxxx";

//アプリケーションtiger1用クライアントID
//
char clientid[] = "a:hogehoge:subtest";

//購読対象デバイスのトピック名
char topicname[] = "iot-2/type/arduino/id/ffffffffffff/evt/status/fmt/json";

// callback関数プロトタイプ宣言
void callback(char* topic, byte* payload, unsigned int length);

// Arduino YUNにおけるEthernetClient代替オブジェクト
YunClient c;
// PubSubClientライブラリクライアントオブジェクト
PubSubClient client(server, 1883, callback, c);

/*
  初期処理
*/
void setup() {
  // シリアルポート開始
  Serial.begin(9600);
  while(!Serial){
    ;
  }
  Serial.println("setup started");

  // L13点灯
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);

  // ブリッジ開始
  Bridge.begin();
  Serial.println("bridge begun");
  delay(2000);

  // MQTTブローカ接続
  while (!client.connected()) {
    Serial.println("connecting...");
    client.connect(clientid, username, password);
    delay(1000);
  }
  Serial.print("connected ");
  Serial.print(clientid);
  Serial.print(" ");
  Serial.print(username);
  Serial.print(" ");
  Serial.println(password);

  // Subscribe登録
  Serial.println("subscribing...");
  while(!client.subscribe(topicname)){
    Serial.println("subscribe failed");
    delay(1000);
    Serial.println("re-subscribing...");
  }
  Serial.print("subscribed ");
  Serial.println(topicname);


  // L13消灯
  digitalWrite(13, LOW);
  Serial.println("setup finished");
}

/*
 ループ処理
*/
void loop() {
  // PubSubClientループ処理
  if(!client.loop()){
    Serial.println("loop failed");
  }
}

/*
Subscribe対象がpublishされた時呼び出されるCallback関数
*/
void callback(char* topic, byte* payload, unsigned int length) {
  // 処理開始、L13点灯
  Serial.println("callback started");
  digitalWrite(13, HIGH);

  // JSONデータの後ろにゴミデータがある場合の対策
  char* json = (char*)malloc(length+1);
  memcpy(json, payload, length+1);
  json[length] = '\0';

  Serial.println(json);

  // JSONデータparse
  StaticJsonBuffer<100> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(json);
  if (!root.success()) {
    Serial.println("parseObject() failed");
    free(json);
    digitalWrite(13, LOW);
    return;
  }
  JsonObject& d = (JsonObject&)root["d"];

  // 変数dからデータを取り出し、Outputピンなどを操作
  // する処理を書く


  // メモリ解放
  free(json);

  // 処理終了
  digitalWrite(13, LOW);
}




受信データはおそらくJSON形式となるためArduinoJsonライブラリを使って
可能な限りオブジェクト構造を崩さないように利用できるようにしている。

setup/loop関数は、ほぼ決まった書き方になっている。
setupでsubscribeするトピック名を引数にして渡す。
loopは基本決め打ちの書き方で、callback関数上にデータ受信時の処理を書く。

MQTT Subscriberは常に待ち受けとなるので、
このサンプルコードを逸脱した書き方にはおそらくならないはず。






また、クライアントIDは、IoT Foundationのドキュメントにフォーマットが書かれており、
a:<組織ID>:<アプリID>」となる。
組織IDは、IoT Foundationへ登録した際に決まる組織IDをそのまま使う。
アプリIDは基本自由でほかのデバイスとかぶらないように名前をつける。

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...