Web系エンジニアのアウトプット練習場

エンジニアリングと書評が中心。たまに全然関係無い話もします。
  • 2017年11月21日

    Google Cloud IoT CoreでMQTTを試す

    Qiita
    動機 以前、AWS IoTを触ったが、 会社の基幹システムがGCPを使用する予定なので、GCPの同系統のサービスを試してみることにした。 目標 Google Cloud IoT Coreを使用し、Raspberry Piから、 MQTTプロトコルでCloud PubSubにメッセージをパブリッシュする。 MQTTについて パブリッシュ・サブスクライブ方式のプロトコル。 IBMのページがよくまとまっている。 GCP側の準備 プロジェクトを作成し、「APIとサービス」から「Google Cloud IoT API」を有効化する。 端末レジストリの作成 メニューから「IoT Core」を選択すると、「端末レジストリ」の作成画面となる。 パラメータ 値 レジストリID 任意の値 Cloudリージョン asia-east1 プロトコル MQTT, HTTP テレメトリーのトピック events デバイス状態のトピック state 上記画面が出るので「続行」を選択する。 端末の追加 端末の追加をクリック。 なお、今回はRaspberry PiをIoT端末として追加する。 パラメータの入力 パラメータ 値 端末ID 任意 端末の通信 許可 公開鍵の形式 後述 公開鍵の値 後述 公開鍵の有効期限 省略(設定しない) 端末メタデータ 省略(設定しない) 公開鍵の登録 公式ドキュメントを参考に、Raspberry Piにて公開鍵を作成する。 opensslを使用するので、インストールされてない場合はインストールする。 $ openssl genrsa -out rsa_private.pem 2048 $ openssl rsa -in rsa_private.pem -pubout -out rsa_cert.pem rsa_cert.pemの内容を「公開鍵の値」に入力する。 rsa_private.pemは端末側に配置して使用する。 Raspberry Pi側の設定 Python環境を準備 サンプルコードをダウンロード こちらからMQTTクライアントのサンプルをダウンロードし、端末に配置。 このサンプルについて 内部でMQTTを使用している。 特にソースコードを弄らなければqos1でメッセージがパブリッシュされる。 また、クライアント証明書が必要なので、以下のコマンドで証明書をRaspberry Piに配置しておく。 $ wget https://pki.goog/roots.pem 必要なライブラリ等をインストール $ sudo apt-get install -y build-essential libssl-dev libffi-dev $ sudo pip install -r requirements.txt $ sudo pip install google-api-python-client $ wget https://pki.goog/roots.pem $ ls cloudiot_mqtt_example.py requirements.txt rsa_private.pem roots.pem トピックにメッセージをパブリッシュ $ python cloudiot_mqtt_example.py --registry_id=iot-gateway --project_id=my_project --device_id=gateway1 --algorithm=RS256 --private_key_file=./rsa_private.pem --cloud_region=asia-east1 Creating JWT using RS256 from private key file ./rsa_private.pem Publishing message 1/100: 'iot-gateway/gateway1-payload-1' ('on_connect', 'Connection Accepted.') on_publish Publishing message 2/100: 'iot-gateway/gateway1-payload-2' on_publish Publishing message 3/100: 'iot-gateway/gateway1-payload-3' on_publish Publishing message 4/100: 'iot-gateway/gateway1-payload-4' on_publish Publishing message 5/100: 'iot-gateway/gateway1-payload-5' on_publish Publishing message 6/100: 'iot-gateway/gateway1-payload-6' on_publish Publishing トピックをサブスクライブ $ gcloud beta pubsub subscriptions create --topic events my-subscriptions $ gcloud beta pubsub subscriptions pull --auto-ack my-subscriptions ┌────────────────────────────────┬─────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ DATA │ MESSAGE_ID │ ATTRIBUTES │ ├────────────────────────────────┼─────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ iot-gateway/gateway1-payload-1 │ 173994752831401 │ deviceId=gateway1 deviceNumId=3104791428628451 deviceRegistryId=iot-gateway deviceRegistryLocation=asia-east1 projectId=factory-iot subFolder= │ └────────────────────────────────┴─────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ まとめ Google Cloud IoT CoreとRaspberry Piを使用して、PubSubにメッセージを送信することができた。 次は取得したデータを閲覧したりできるよう、PubSubと他サービスの連携を行っていきたい。
  • 2017年11月20日

    ArduinoとRaspberry Pi間をZigBeeで接続する

    Qiita
    準備 Arduino Uno Rev3 Raspberry Pi 3 Model B Arduino ワイヤレスSDシールド XBee USBインターフェースボードキット XBeeZB S2Cモジュール ワイヤーアンテナタイプ 2個 Arduino-PC間接続用のUSBケーブル Arduino側がTYPE-B XBee USBインターフェースボードキットと、PCやRaspberry Piの間の接続用のUSBケーブル インターフェースボードキット側がMicro-B 作業用PC MacでもWinでもLinuxでもできるはず 私はMac Book(Sierra)で作業を行った XBee USBインターフェースボードキットの組み立て はんだ付け いつ以来のハンダ付けかわからないため、汚いが勘弁してほしい。 (特にDC端子のとこはひどい・・・) はんだ付けの方法はここを参考にした。 表 裏 PWE-SELにジャンパピンを取り付ける 今回はRaspberry PiとUSBで接続する想定なので、USB側に接続。 XBeeZB S2Cモジュールを取り付ける このモジュールには向きがあるので注意すること。 Raspberry Piの準備 インターネットにWiFiで接続する、もしくは有線で接続する 作業用PCからssh接続するため。 RaspberryPiに直接ディスプレイやキーボードを接続する場合は不要 Pythonの設定 ベースのアップデートと必要なライブラリをインストール # ベースのアップデート $ sudo apt-get update $ sudo apt-get upgrade -y $ sudo apt-get dist-upgrade # 必要なライブラリのインストール $ sudo pip install xbee 手元のRaspberry Piだとpipにsudo付けないとPermission Deniedが出るんだが、 これがデフォルトの挙動なのだろうか。 Arduinoの準備 Arduino IDEを作業PCにインストール ワイヤレスSDシールドの接続 この後、USBケーブルでPCと接続して設定を行うので、下図の赤枠で囲っている箇所にあるSERIAL SELECTのDIPスイッチをUSB側へ倒しておく XBeeモジュールの接続 XCTUのインストール PCにインストールを行う。 XCTU SOFTWAREのDiagnostics, Utilities and MIBsから適切なOS用のインストーラを選びダウンロード。 ダウンロードの際、メンバー登録を促されるので、メンバー登録したくない人はNo thanks, register laterで回避可能。 インストールが完了したら、XCTUを起動する。 起動時に「"XCTU"を開くには、以前のJava SE 6ランタイムをインストールする必要があります。」とエラーが出た場合は、「詳しい情報」からインストールする。 XBee USBの接続 作業PCにVCP DriversページからOSに合ったドライバをダウンロードし、インストール。 この工程が本当に必要かどうかは不明だが、私は一応実行しておいた。 その後、USBでPCに接続する。 ここでPWRのところが青く光らない場合は、はんだ付けやジャンパピンの取り付けが正しく行われていない可能性がある。 XCTUでネットワーク設定 XBeeZB S2CモジュールをPCから認識させる USBポートが2つ以上あるPCの場合は親機(XBee USB)と子機(Arduino)を同時にPCに差して、同時に認識させることが可能。 USBポートが1つしかない場合は、1台ごとに認識させて、設定を行う必要がある。 XBee USB側(親機)のXBeeZB S2Cモジュールの認識 赤枠で囲ったアイコンからモジュールを検索できる。 XBeeモジュールを接続しているPortを選択し、その後の画面を適当にスキップして検索する。 モジュールが見つかるので、「Add selected devices」でモジュールを追加。 Arduino側(子機)のXBeeZB S2Cモジュールの認識 ArduinoをPCに接続し、同じ手順で認識させる。 ただし、Arduinoの信号による干渉のせいか、接続がうまく行かなかったりする場合がある。 以下のトラブルシューティングを参考にどうぞ。 認識されない場合に試すこと 突然XBee USB側のXBeeモジュールがXCTUに認識されなくなった 接続しようとしたところ上記の画面が出て認識されなくなった。 XBeeUSBのResetボタンを押したが、反応がなかったため、キャンセルボタンを押した。 その後、モジュール追加アイコンから再度試すが、同じ画面が。 Resetを押すと今回は反応し、Recoveryアイコンを含む画面が現れたので、Firmwareをリカバリー。 Product familyとFunction setを聞かれたので、それぞれXC24C・ZIGBEE TH Reqを選択した。 リカバリー終了後、再度認識するが試すが、同じ画面が出る。 どうしたものかと思いながら、 何度か抜いたり差したりを繰り返したり、リセットボタンを押してみたりと、 いろいろとやっているうちに認識するようになった。 XBee USBに差してるXBeeモジュールは認識されるが、同じモジュールをArduino側に差したら認識されない XBee USBでとりあえず認識させて、スパナのアイコンのXBee Recoverから、XBee USBを差しているUSBポート、Product family(XC24C)とFunction set(ZIGBEE TH Req)を選択してファームウェアのリカバリーを行う。 リカバリーが完了したら、Arduinoに差し替えて認識させてみると正常に認識された。 と思ったらまたArduino側のXBeeモジュールが認識しなくなった ArduinoのGNDとRSTを接続してショートさせると良いらしい。 ただし、この状態のまま、Arduinoにプログラムを書き込もうとするとエラーがでたので、書き込むときは外すようにした。 理由はわからん。(追記: RSTピンをGNDに落とすというのはArduinoボードに実装されているリセットボタンを押したままにするのと同義なので、その間はArduinoが全く停止してしまうためであるとのこと。) ファームウェアアップデート UpdateアイコンからProduct family/Function set/Versionを選択し、Updateをクリック。 設定 設定を変えたら画面上部のWriteからまとめて書き込むことができる。 ただし、まとめて書き込むと書き込みがうまくいかない場合があったので、私は1つ1つ書き込みを行うようにした。 親機 パラメータ 略名 値 PAN ID ID 任意の値 Cordinator Enable CE Enabled[1] Destination Address High DH 子機のXBeeモジュールのMacアドレス上位4オクテット Destination Address Low DL 子機のXBeeモジュールのMacアドレス下位4オクテット API Enable AP API enabled[1] 子機 パラメータ 略名 値 PAN ID ID 親機と同じPAN ID Cordinator Enable CE Disabled[0] Destination Address High DH 親機のXBeeモジュールのMacアドレス上位4オクテット Destination Address Low DL 親機のXBeeモジュールのMacアドレス下位4オクテット API Enable AP API enabled[1] Arduinoにプログラムを書き込む XBeeライブラリをインストール Arduino IDEの「スケッチ=>ライブラリをインクルード=>ライブラリを管理」でxbeeと検索してインストール。 #include <XBee.h> // Initialize XBee ZB client XBee xbee = XBee(); // Payload byte array uint8_t payload[16]; // Send to coordinator XBeeAddress64 addr64 = XBeeAddress64(0, 0); void set_int_to_payload(int value, int index) { uint8_t *value_array; value_array = reinterpret_cast<uint8_t*>(&value); for(int i=0; i<sizeof(value); i++){ payload[i+index] = value_array[i]; } } void setup() { Serial.begin(9600); xbee.setSerial(Serial); } void loop() { delay(3000); int tid = 13; // 端末ID(テキトー) // 今回はA0から光抵抗センサの値を読み取った int cds = analogRead(0); set_int_to_payload(tid, 0); set_int_to_payload(cds, 8); // Create request for XBee ZB ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload)); xbee.send(zbTx); } SERIAL SELECTの切り替え 書き込み終わったら、PCからUSBを外してワイヤレスシールドのスイッチをMicroの方に切り替える。 この時点でArduinoは作業用PCと切り離しても良い。 Raspberry Piのコーディング 受信用コードを記述 公式ドキュメントを参考にして、受信用コードを書く。 receive.py # coding: utf-8 from xbee import ZigBee import serial import struct import time def parseData(data): data = struct.unpack('qq', data['rf_data']) return data if __name__ == '__main__': # Setup ZigBee PORT = '/dev/ttyUSB0' BAUD_RATE = 9600 myDevice = serial.Serial(PORT, BAUD_RATE) xbee = ZigBee(myDevice) # Continuously read and print packets print(">> Waiting for data...") while True: try: data = parseData(xbee.wait_read_frame()) tid = data[0] cds = data[1] print(tid, cds) except KeyboardInterrupt: break myDevice.close() 実行 作業用PCに接続しているモジュールをRaspberryPiに差し替えて、先程のコードを実行する。 $ python receive.py >> Waiting for data... (13, 404) (13, 404) (13, 407) (13, 403) (13, 406) (13, 404) . . . 上記のように、3秒ごとにデータが送られてくれば成功。 まとめ 以下の手順を行うことで、端末間の通信を行うことができた。 各端末(RaspberryPi, Arduino, XBee USBインターフェースボード)の準備、設定 XCTUでのXBeeモジュール(親機, 子機)の接続、設定 Arduino, RaspberryPiでのコーディング 今まで無線接続といえばWifiとBluetoothしか扱ったことがなかったが、 ZigBeeも1日足らずで通信の成功まで持っていけた。