前回の記事で、sakura.ioで通信モジュールやArduinoなどのすべての準備ができました。今回はサンプルプログラムを動作させるところからはじめて、実際に通信してみます。
目次
- 通信モジュールからデータをsakura.ioに送信
- sakura.ioから通信モジュールにデータを送信
- まとめ
1.通信モジュールからデータをsakura.ioに送信
前回、ライブラリをインストールしたので、さっそくサンプルプログラムを動作させてみます。「スケッチ例」-「SakuraIO」-「Shell」を選択して基本的な手動でデータを送信するプログラムを動かしてみます。
SakuraIOのサンプルプログラム
#include <SakuraIO.h> #include "ntshell.h" #include "commands.h" static int func_read(char *buf, int cnt, void *extobj); static int func_write(const char *buf, int cnt, void *extobj); static int func_callback(const char *text, void *extobj); static int ntopt_callback(int argc, char **argv, void *extobj); static void ntshell_poll(ntshell_t *p); ntshell_t ntshell; cmd_list_t cmd_list[] = { {(char*)"version", cmd_version}, {(char*)"serial", cmd_serial}, {(char*)"status", cmd_status}, {(char*)"sqi", cmd_sqi}, {(char*)"unixtime", cmd_unixtime}, {(char*)"update", cmd_update}, {(char*)"reset", cmd_reset}, {(char*)"enqueue", cmd_enqueue}, {(char*)"sendnow", cmd_sendnow}, {(char*)"send", cmd_send}, {(char*)"size", cmd_size}, {(char*)"cleartx", cmd_cleartx}, {(char*)"dequeue", cmd_dequeue}, {(char*)"peek", cmd_peek}, {(char*)"clearrx", cmd_clearrx}, {(char*)"file", cmd_file}, {NULL, NULL} }; //SakuraIO_SPI sakuraio(10); SakuraIO_I2C sakuraio; void setup() { Serial.begin(9600); Serial.println("Hello"); Serial.print(">"); ntshell_init(&ntshell, func_read, func_write, func_callback, (void *)&ntshell); ntshell_set_prompt(&ntshell, ">"); } void loop() { ntshell_poll(&ntshell); } /* NT-Shell */ static int func_read(char *buf, int cnt, void *extobj) { if (Serial.available()) return Serial.readBytes(buf, cnt); else return 0; } static int func_write(const char *buf, int cnt, void *extobj) { return Serial.write(buf, cnt); } static int func_callback(const char *text, void *extobj) { return ntopt_parse((const char *)text, ntopt_callback, extobj); } static int ntopt_callback(int argc, char **argv, void *extobj){ if (argc == 0) { return 0; } int execnt = 0; const cmd_list_t *p = cmd_list; while (p->command != NULL) { if (ntlibc_strcmp((const char *)argv[0], p->command) == 0) { p->func(argc, argv); execnt++; } p++; } if (execnt == 0) { Serial.println("unknown command"); } return 0; } static void ntshell_poll(ntshell_t *p) { if (p->initcode != INITCODE) { return; } unsigned char ch; if(SERIAL_READ(p, (char *)&ch, sizeof(ch)) > 0) vtrecv_execute(&(p->vtrecv), &ch, sizeof(ch)); }
プログラムを書き込んだ後に、シリアルモニタを開きます。シリアルモニタの設定は「9600 bps」で改行コードは「CRのみ」に設定します。
シリアルモニタの準備
シリアルモニタの準備ができたら、データの受信を確認する画面をsakura.ioの管理画面から表示します。前回登録した連携サービスをクリックすると、詳細画面が表示されます。
連携サービスの選択
連携サービス詳細画面
この画面を開いたままで、シリアルモニタに戻ります。
シリアルモニタで「enqueue 0 i 5656」と入力します。
enqueue – 送信キューにデータを格納するコマンド
enqueueの後ろは「0-チャンネル番号、i-送信するデータの型、5656-送信データの内容」となります。
enqueueコマンドを入力
enqueueコマンドを入力するとシリアルモニタに表示されます。次に送信キューにためたデータを実際にsakura.ioに送るために「send」コマンドを入力します。
send – 送信キューにたまったデータをsakura.ioに送信する
sendコマンドを入力
「送信」でsendコマンドを送信
sendコマンドでデータを送信すると、管理画面上にデータが届いたことが確認できれば無事送信が完了です!
Arduinoに載せた通信モジュールからデータがsakura.ioに届いている画面
これで、通信モジュールからsakura.ioへの簡単なデータの送信方法が確認できました。
sakura.ioに届いたデータの利用方法
実際に利用するには、このsakura.ioに届いたデータを上記「サービス連携の編集 WebSocket」の画面の上にあるURLやTokenを使って、別のサーバープログラムからアクセスしてデータを取得したりするようなプログラムを作っていく流れになります。
それらの流れはAPIドキュメントを見ると知ることができます。
2.sakura.ioから通信モジュールにデータを送信
Arduino側の通信モジュールからsakura.ioにデータが送ることができたので、次に逆のsakura.ioからArduino側の通信モジュールにデータを送信する方法を試してみます。
2-1.Incoming Webhookの設定
今回の通信方式はIncoming Webhookを利用します。その前に、Incoming Webhookとは何でしょうか?まずwebhookを簡単に説明すると「アプリなどの更新情報を他のアプリへリアルタイムに通知する仕組みや概念」となります。そしてその通知する仕組みはPOST方式で実行されます。
sakura.ioでIncoming Webhookを使うために、管理画面から連携サービスを登録します。連携サービス「サービス追加」よりWebSocketを追加したときのように追加画面に進みます。
「サービス追加」を選択
Incoming Webhookを選択
Incoming Webhookでは、名前とSecretの2箇所設定する必要があります。Secretは接続する際に必要なSecretキーを設定することができるのですが、今回は名前のみで設定しないで進みます。
Incoming Webhookの登録画面
登録が完了したら、同じように連携サービスのIncoming Webhookの詳細画面を開きます。詳細画面では設定した名前とSecretのほかにTokenとURLという記載が表示されています。
Incoming Webhookの詳細画面
URLには/v1/以降にTokenが表示されていると思いますが、このURLにPOSTデータを送信することで通信モジュールにデータを送ることができます。
2-2.サーバ側のプログラムを用意する
今回のIncoming Webhookの一連の流れは下記の図になります。今回はサーバ側にプログラムを用意して、それをブラウザでアクセスした際に通知するようにしていますが、「ブラウザでアクセス」というのを、別のアプリやシステムに置き換えれば一般的なWebhookとして「他のアプリからの通知を通信モジュールに送信する」という利用が可能になります。
今回このIncoming Webhookを利用している例としてさくらインターネットさんの「さくらのナレッジ」のウェブサイトに「さくらのIoT Platformで、”ヤバい状況であることを光って知らせる装置”をできるだけ安価に作ったお話」一連の実装について紹介例がありますので、今回そのコードを参考に進めていきます。
今回のIncoming Webhookでの通知の流れ
サーバ側はPHPを利用します。PHPプログラムはそれぞれPHPが動作可能なサーバなどに設置してください。下記プログラムのモジュールのIDは管理画面の一覧に表示されているIDを設定します(通信モジュールに書かれているIDではありませんので注意)。tokenは連携サービスに記載されているtokenを設定します。
<?php $digit = htmlspecialchars($_GET["val"], ENT_QUOTES, 'UTF-8'); $module = "[モジュールのIDを記載]"; $token = "[tokenを記載]"; $secret = ""; function send_to_iot($token, $payload, $secret){ $webhook_url = "https://api.sakura.io/incoming/v1/{$token}"; $x_sakura_signature = hash_hmac("sha1", $payload, $secret); $headers = array( 'Content-Type: application/json', 'Accept: application/json', 'X-Sakura-Signature: '. $x_sakura_signature, ); $options = array( 'http' => array( 'method' => 'POST', 'header' => implode("\r\n", $headers), 'content' => $payload, ) ); $response = file_get_contents($webhook_url, false, stream_context_create($options)); return $response === 'ok'; } $data = array( 'type' => 'channels', 'module' => $module, 'payload' => array( 'channels' => array( array( 'channel' => 0, 'type' => 'i', 'value' => intval($digit), ) ) ) ); $payload = json_encode($data); send_to_iot($token, $payload, $secret);
サーバーに設置して下記のように?val=1などとvalのあとに0~9の数値を設定すると通信モジュールに通知されるような仕様になっています。(送信する内容は0~9以外でもよいですが、今回Arduino側で1桁のint型を受けるようにしています)
https://xxx.xxx.xxx/incoming_webhook.php?val=1
2-3.Arduino側のプログラム
次にArduino側のプログラムを用意します。こちらもさくらのナレッジで紹介されている例をもとに今回用に書き換えをしています。主な処理の流れは、sakura.ioからgetRxQueueLength関数で受信できるデータがあるかどうかを確認したのち、データがあればdequeueRx関数で取得して、その内容に合わせて2のLEDを光らせる処理を実施する、という流れになっています。
今回13番ピンにLEDを接続して光らせる・消すという処理を書いていますので、LEDをつけてみてください(LEDがなくてもArduino本体のLEDがついたり消えたりします)
#include <SakuraIO.h> SakuraIO_I2C sakuraio; #define LED 13 int cnt = 0; void setup() { delay(1000); Serial.begin(9600); Serial.print("Waiting to come online"); for (;;) { if ( (sakuraio.getConnectionStatus() & 0x80) == 0x80 ) break; Serial.print("."); delay(1000); } Serial.println(""); pinMode(LED, OUTPUT); } void loop() { uint8_t available; uint8_t queued; boolean signal_flg; boolean blink_flg; cnt++; Serial.print("Count :"); Serial.print(cnt); available = 0; //************************************************************ //* 1.sakura.ioからデータを取得 //************************************************************ if (sakuraio.getRxQueueLength(&available, &queued) != CMD_ERROR_NONE) { Serial.println("[ERR] get rx queue length error"); } if (available > 0){ uint8_t ch, type, value[8]; int64_t offset; sakuraio.dequeueRx(&ch, &type, value, &offset); Serial.print(" Value :"); Serial.println(value[0]); if (value[0] == 1) { signal_flg = 1; }else{ signal_flg = 0; } } //************************************************************ //* 2.取得したデータをもとにLEDを光らせる //************************************************************ if(signal_flg == 1){ //1-光らせる digitalWrite(LED, HIGH); blink_flg = 1; }else{ //0-消す digitalWrite(LED, LOW); blink_flg = 0; } sakuraio.clearRx(); delay(1000); }
実際にArduinoに書き込み、シリアルモニタを表示した状態で先ほどのサーバ側プログラムにval=1やval=0としてアクセスすると、ブラウザ上は真っ白なページが表示されるだけ。変化はありませんが、シリアルモニタに下記のように数値の変化が見られ、Arduino側に接続された通信モジュールに正常に値を送信できていることが確認できますね!
Incoming Webhookでデータを受信
サーバ側プログラムを修正して、ON(val=1)/OFF(val=0)を切り替えるようにしてみました。
これで、手軽に外部からsakura.ioを通じてArduinoを制御することができますね!
まとめ
sakura.ioを使って実際に通信することができました!次回はさらにスマートフォンやほかのアプリから通信モジュールを通じてArduinoを制御するデバイスの作成に取り組んでみたいと思います!