SONY Spresense と LTE拡張ボードでkintoneにHTTPリクエストする方法
この記事ではSONY SpresenseのLTE 拡張ボードを使い、クラウドサービスのkintoneにHTTPリクエストをする方法を案内します。
SONY Spresenseとは
SONY Spresense (以降、Spresense)は低消費電力でありながら、GPS受信機能とハイレゾリューションオーディオコーデックを搭載したIoT用ボードコンピュータです。この記事ではSpresenseメインボードをLTE拡張ボードにとりつけて、kintoneにHTTPリクエストをする方法を案内します。
この記事で作るもの
この記事ではkintoneでスコアランキングアプリを作り、SpresenseのLTE経由でランキングを取得したり、スコアを追加する方法を案内します。
連携の作り方
kintoneアプリの準備
まずはkintone側の準備から説明します。
kintone環境の準備する
kintoneの環境が無い方は、開発者サイトから1年間無償で使用できる『開発者ライセンス』という名のkintone環境を取得出来ます。下記のサイトで『開発者ライセンスを申し込む』をクリックし、フォームに必要事項を入力して下さい。申込後、メールでkintone環境の情報が送られてきます。所要時間はおおよそ10分程度です。
https://cybozu.dev/ja/kintone/developer-license/
kintoneアプリを作成する
kintoneで作るウェブデータベースは『アプリ』と呼ばれます。
まず、ゲームのスコアを管理するためのkintoneアプリを作成します。プレイヤー名、スコア、難易度等、必要な情報をイメージしながら作りましょう。
この記事で作成するアプリに必要なフィールドは下記のデーブルに記載したので、参考にしてください。フィールドを配置したら、一つ一つ設定を変更することが出来るので、表示名、フィールドコードやオプションなどを変更します。ちなみに表示名はUI上でユーザに見えるフィールドの名前で、フィールドコードはフィールドのユニークな識別子になります。フィールドコードは外部からHTTPリクエストをする際に重要な設定となります。
フィールドタイプ | 表示名 | フィールドコード | その他の設定 |
---|---|---|---|
文字列(1行) | プレイヤー名 | playername | |
数値 | スコア | score | 単位記号に『points』を追加して後ろに付ける |
ラジオボタン | 難易度 | difficulty | 選択肢に 『Easy』『Medium』『Hard』 を追加する |
フィールドの配置や設定が終わったら、右上の青いボタンからアプリを公開します。
kintoneアプリにレコードを追加する
ウェブデータベースを作成出来ましたが、データがまだ入っていません。適当に手動でいくつかデータ(レコード)を追加しましょう。
kintoneアプリからAPIトークンを発行する
他のシステムと連携をするために、kintoneアプリから認証用のトークンを発行します。アプリの設定画面からAPIトークンを生成します。「レコード閲覧」と「レコード追加」のアクセス権にチェックを入れます。APIトークンを手元でメモした後に、設定を保存してアプリを更新します。
これでkintoneアプリの準備が出来ました。
Spresenseの準備
次に、Spresense側で必要なデバイスや設定を準備していきます。
必要なデバイスを揃える
SpresenseでLTE通信するためには下記のデバイスが必要です:
- SPRESENSE メインボード
- SPRESENSE LTE拡張ボード
- MicroSDカード
- nanoSIMカード
SIMカードをアクティベートする
まずはSIMカードで通信が出来るようにアクティベートをしましょう。アクティベートする方法は各社で方法が異なるので、SIMカードのマニュアルの説明を良く読んでアクティベートをします。
この記事では『さくらのセキュアモバイルコネクト』を使用しており、さくらのクラウドアカウントからモバイルゲートウェイを作成してからSIMカードをアクティベートする必要がありました。
SIMカードのアクティベートが出来たら、LTE拡張ボードに差し込みます。
Spresenseの開発環境を準備する
Spresense Arduino スタートガイドに沿ってSpresense Arduino Libraryをインストールし、 Arduino IDE 、USB ドライバとSpresense Arduino board packageをインストールします。プログラミング環境の設定をし、LEDのスケッチを動かすところまで進めて、ボードへの書き込みがきちんと出来るかを確認します。
https://developer.sony.com/spresense/development-guides/arduino_set_up_ja.html
LTE環境関連のスケッチを動かす
ここからは、Spresenseの開発サイトで案内されているLTEチュートリアルを元にいくつかのスケッチを試し、少しずつ動作確認をしていきます。
https://developer.sony.com/spresense/development-guides/arduino_tutorials_ja.html#_tutorial_lte
各スケッチは【ファイル】→【スケッチ例】→【LTE】から開くことが出来ます。また、各スケッチの結果はシリアルモニタに表示されるので、【ツール】→【シリアルモニタ】でArduino IDEに表示させましょう。
LteTestModem のスケッチ例を動かす
LteTestModemのスケッチを動かします。特にコードに変更は必要ありません。Spresenseに書き込みをしたら、シリアルモニタに下記のような情報が出力されます。
IMEI: 351521105181572
VERSION: RK_03_00_00_22_13151_002
RAT: LTE-M (LTE Cat-M1)
LteScanNetworks.ino のスケッチ例を動かす
LteScanNetworksのスケッチを動かします。コード内のAPN情報を、自分のSIMカードに合わせたものに変更します。
// APN name
#define APP_LTE_APN "sakura"
Spresenseに書き込みをし、しばらくしたらコンソールに下記のような情報が定期的に出力されます。
Current carrier: SAKURA Internet
Signal Strength: -78 [dBm]
LTE networks scanner
=========== APN information ===========
Access Point Name : sakura
Authentication Type: CHAP
User Name :
Password :
attach succeeded.
IP address: xxx.xxx.x.x
Current carrier: SAKURA Internet
Signal Strength: -78 [dBm]
LteWebClient のスケッチ例を動かす
LteWebClientのスケッチを動かします。こちらもコード内のAPN情報を自分のSIMカードに合わせたものに変更します。
// APN name
#define APP_LTE_APN "sakura"
Spresenseに書き込みをし、しばらくしたらコンソールに色々な情報が出力されます。
;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;;
;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;;
,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;;
;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;.
;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;`
,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;;
;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;;
;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;;
今までのスケッチ例で別の情報が出力された場合、SIMカードが正しく動作してない可能性があります。
ここまで問題なく出力されたら、Spresenseの準備は出来たので、次に進みましょう。
SpresenseからkintoneにHTTPリクエスト
Spresenseからkintoneに対してHTTPリクエストを行いますが、kintoneが稼働しているcybozu.comのサーバにはHTTPではなくHTTPSで通信を行う必要があります。Spresenseにcybozu.comのサーバが安全なサーバだと伝えるために、cybozu.comの証明書をSpresenseに保管する必要があります。
証明書の準備をする
ブラウザによって証明書の取得方法がことなります。この記事ではChromeブラウザで入手する方法を案内します。
まずkintoneにログインし、URL近くのメニューから「この接続は保護されています」を選択し、「証明書は有効です」をクリックします。
続いて「詳細」タブを選択し、一番上のCertification Authorityと記載されてる箇所を選択します。この状態で下のエクスポートボタンをクリックします。このページではデフォルトで違う箇所が選択されるので、間違えてそちらをエクスポートしないように気をつけてください。Certification Authorityと記載されてる方をエクスポートしてください。
保存方法が色々と提示されますが、その中から「DER エンコードバイナリ形式の単一の証明書」を選んで保存します。
証明書がダウンロード出来たら、SDカードをパソコンに接続し、CERTSディレクトリを作成し、その中に証明書ファイルを入れます。証明書のファイル名は好きなものにします。
SDカードに保存が出来たら、SDカードをSpresenseのLTE拡張ボード内に差し込みます。LTE拡張ボードにも電源供給をします。
コードの下準備をする
スケッチ例からLteHTTPSecureClientを選択します。ArduinoHttpClientライブラリ、Arduino_JSONライブラリとURLEncodeライブラリをインストールし、コードの上部にライブラリをincludeします。
#include <ArduinoHttpClient.h>
#include <Arduino_JSON.h>
#include <UrlEncode.h>
他のスケッチ例のように、APN情報を更新します
// APN name
#define APP_LTE_APN "sakura"
SDカード内の証明書のパスを更新します
#define ROOTCA_FILE "CERTS/cybozu.cer"
URLやパスを指定する箇所でご自身のkintone環境のサブドメインを含めたcybozu.comのサーバURLを指定し、getやpostのパスをコメントアウトします。
char server[] = "cy-hwg.cybozu.com";
//char getPath[] = "/get";
//char postPath[] = "/post";
レコードの取得をする
まずはkintoneの複数のレコードを取得するAPIを使って複数のレコードをアプリから取得します。
loop内の処理を下記のように書き換えます。接続先のcybozu.comのサブドメイン、アプリIDやAPIトークンは自分のものに変更して下さい。
void loop()
{
// Set certifications via a file on the SD card before connecting to the server
File rootCertsFile = theSD.open(ROOTCA_FILE, FILE_READ);
tlsClient.setCACert(rootCertsFile, rootCertsFile.available());
rootCertsFile.close();
// HTTP GET method
Serial.println("Starting GET request...");
client.beginRequest();
Serial.println("Begenning request");
//Create endpoint URL for kintone Get Records API
String baseURL = "https://cy-hwg.cybozu.com/k/v1/records.json";
String appURL = "?app=70";
String GETURL = baseURL + appURL;
Serial.println(GETURL);
//Make API request
client.get(GETURL);
client.sendHeader("X-Cybozu-API-Token", "edtlR7VzFTiQY7ODPOihoCHmeALwYoJYy6Mk8akw");
Serial.println("Ending request...");
client.endRequest();
Serial.println("Request has ended");
// read the status code and body of the response
Serial.println("Reading status code...");
int statusCode = client.responseStatusCode();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.println("Reading response...");
String response = client.responseBody();
Serial.println("Response: " + response);
Serial.println("Wait five seconds");
sleep(5);
}
シリアルモニタに情報が出力され、しばらくするとレコード情報が入ったJSONのレスポンスも出力されます。
Starting GET request...
Begenning request
https://cy-hwg.cybozu.com/k/v1/records.json?app=70
Ending request...
Request has ended
Reading status code...
Status code: 200
Reading response...
Response: {"records":[{"difficulty":{"type":"RADIO_BUTTON","value":"Medium"},"score":{"type":"NUMBER","value":"23000"},"レコード番号":{"type":"RECORD_NUMBER","value":"5"},"更新者":{"type":"MODIFIER","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"作成者":{"type":"CREATOR","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"playername":{"type":"SINGLE_LINE_TEXT","value":"QED"},"$revision":{"type":"__REVISION__","value":"1"},"更新日時":{"type":"UPDATED_TIME","value":"2024-06-18T04:34:00Z"},"作成日時":{"type":"CREATED_TIME","value":"2024-06-18T04:34:00Z"},"$id":{"type":"__ID__","value":"5"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Easy"},"score":{"type":"NUMBER","value":"13000"},"レコード番号":{"type":"RECORD_NUMBER","value":"4"},"更新者":{"type":"MODIFIER","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"作成者":{"type":"CREATOR","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"playername":{"type":"SINGLE_LINE_TEXT","value":"Kiri"},"$revision":{"type":"__REVISION__","value":"1"},"更新日時":{"type":"UPDATED_TIME","value":"2024-06-18T04:34:00Z"},"作成日時":{"type":"CREATED_TIME","value":"2024-06-18T04:34:00Z"},"$id":{"type":"__ID__","value":"4"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Hard"},"score":{"type":"NUMBER","value":"35000"},"レコード番号":{"type":"RECORD_NUMBER","value":"3"},"更新者":{"type":"MODIFIER","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"作成者":{"type":"CREATOR","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"playername":{"type":"SINGLE_LINE_TEXT","value":"ボブ"},"$revision":{"type":"__REVISION__","value":"1"},"更新日時":{"type":"UPDATED_TIME","value":"2024-06-18T04:34:00Z"},"作成日時":{"type":"CREATED_TIME","value":"2024-06-18T04:34:00Z"},"$id":{"type":"__ID__","value":"3"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Hard"},"score":{"type":"NUMBER","value":"34000"},"レコード番号":{"type":"RECORD_NUMBER","value":"2"},"更新者":{"type":"MODIFIER","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"作成者":{"type":"CREATOR","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"playername":{"type":"SINGLE_LINE_TEXT","value":"HAL"},"$revision":{"type":"__REVISION__","value":"1"},"更新日時":{"type":"UPDATED_TIME","value":"2024-06-18T04:34:00Z"},"作成日時":{"type":"CREATED_TIME","value":"2024-06-18T04:34:00Z"},"$id":{"type":"__ID__","value":"2"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Easy"},"score":{"type":"NUMBER","value":"23000"},"レコード番号":{"type":"RECORD_NUMBER","value":"1"},"更新者":{"type":"MODIFIER","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"作成者":{"type":"CREATOR","value":{"code":"cy-pioneer","name":"cy-pioneer"}},"playername":{"type":"SINGLE_LINE_TEXT","value":"ゆき"},"$revision":{"type":"__REVISION__","value":"1"},"更新日時":{"type":"UPDATED_TIME","value":"2024-06-18T04:34:00Z"},"作成日時":{"type":"CREATED_TIME","value":"2024-06-18T04:34:00Z"},"$id":{"type":"__ID__","value":"1"}}],"totalCount":null}
Wait five seconds
取得する件数が多かったり、通信環境の影響でレコード情報を取得するまでの時間がかかる場合、後述するコードの改良点を参考にして下さい。
レコードを追加する
kintoneの1件のレコードを登録するAPIを使ってレコードを追加します。
loop内の処理を下記のように書き換えます。接続先のcybozu.comのサブドメイン、アプリIDややAPIトークンは自分のものに変更して下さい。
void loop()
{
// Set certifications via a file on the SD card before connecting to the server
File rootCertsFile = theSD.open(ROOTCA_FILE, FILE_READ);
tlsClient.setCACert(rootCertsFile, rootCertsFile.available());
rootCertsFile.close();
// Make JSON Request Body
JSONVar jsonbody;
jsonbody["app"] = 70;
jsonbody["record"]["playername"]["value"] = "Gyozadon";
jsonbody["record"]["difficulty"]["value"] = "Hard";
jsonbody["record"]["score"]["value"] = "52000";
String jsonbody_string = JSON.stringify(jsonbody);
Serial.println("Post Body: " + jsonbody_string);
// HTTP POST method
Serial.println("Starting POST request...");
client.beginRequest();
Serial.println("Begenning request");
//Create endpoint URL for kintone Add Record API
String POSTURL = "https://cy-hwg.cybozu.com/k/v1/record.json";
//Make API request
client.post(POSTURL);
client.sendHeader("X-Cybozu-API-Token", "edtlR7VzFTiQY7ODPOihoCHmeALwYoJYy6Mk8akw");
client.sendHeader("Content-Type", "application/json");
client.sendHeader("Content-length",jsonbody_string.length());
client.beginBody();
client.print(jsonbody_string);
Serial.println("Ending request...");
client.endRequest();
Serial.println("Request has ended");
// read the status code and body of the response
Serial.println("Reading status code...");
int statusCode = client.responseStatusCode();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.println("Reading response...");
String response = client.responseBody();
Serial.println("Response: " + response);
Serial.println("Wait five seconds");
sleep(5);
}
シリアルモニタに情報が出力され、しばらくするとレコードIDが入ったJSONもレスポンスされます。
Post Body: {"app":70,"record":{"playername":{"value":"Gyozadon"},"difficulty":{"value":"Hard"},"score":{"value":"52000"}}}
Starting POST request...
Begenning request
Ending request...
Request has ended
Reading status code...
Status code: 200
Reading response...
Response: {"id":"27","revision":"1"}
ブラウザ上のkintoneアプリを確認すれば、レコードが追加されてるはずです。
コードの改良点
通信状況によっては、GETリクエストでJSONのレスポンスが手に入るまで時間がかかるかもしれません。
kintoneのレコード取得のAPIはいくつかのパラメータを付与することが出来ます。これを駆使することにより、返ってくるJSONのサイズを大幅に縮小することができ、手元に返ってくる時間を減らすことが出来ます。
fields
パラメータはJSONに返ってくるフィールドを制限することが出来ます。今回の例ではアプリ作成時にフィールドは3つしか設定してませんが、それ以外にもデフォルトで備わっている「作成者」や「更新者」(これは誰がレコードを作ったり更新したかを記録するフィールド)といったフィールド情報がレスポンスに返ってきます。
query
パラメータは条件がマッチするレコードだけが取得するように出来ます。また、データの昇順/降順の指定や最大取得件数の指定も出来ます。
レスポンスに含まれるフィールドをplayername
、score
とdifficulty
のみにして、difficultyに「Hard」が含まれ、scoreの高い順に2件だけレコードを取得する場合、コードでURLを指定する部分を下記のように変更出来ます:
String baseURL = "https://cy-hwg.cybozu.com/k/v1/records.json";
String appURL = "?app=70";
String fieldsparam = "&fields[0]=playername&fields[1]=difficulty&fields[2]&";
String queryparam = urlEncode("difficulty in ( \"Hard \") order by score desc limit 2");
String GETURL = baseURL + appURL + fieldsparam + queryparam;
Serial.println(GETURL);
下記のような制限された情報のJSONが出力されるので、レスポンス時間を短縮することが出来ます。
{"records":[{"difficulty":{"type":"RADIO_BUTTON","value":"Hard"},"playername":{"type":"SINGLE_LINE_TEXT","value":"Gyozadon"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Medium"},"playername":{"type":"SINGLE_LINE_TEXT","value":"QED"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Easy"},"playername":{"type":"SINGLE_LINE_TEXT","value":"Kiri"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Hard"},"playername":{"type":"SINGLE_LINE_TEXT","value":"ボブ"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Hard"},"playername":{"type":"SINGLE_LINE_TEXT","value":"HAL"}},{"difficulty":{"type":"RADIO_BUTTON","value":"Easy"},"playername":{"type":"SINGLE_LINE_TEXT","value":"ゆき"}}],"totalCount":null}
状況に合わせて、最低限の情報の取得で済ませられるように調整してみましょう!
-
Cybozu_kintone
さんが
前の水曜日の19:55
に
編集
をしました。
(メッセージ: 初版)
-
Cybozu_kintone
さんが
前の水曜日の21:27
に
編集
をしました。
-
Cybozu_kintone
さんが
前の水曜日の21:44
に
編集
をしました。
ログインしてコメントを投稿する