Cybozu_kintoneのアイコン画像
Cybozu_kintone 2024年11月20日作成 (2024年11月20日更新) © MIT
セットアップや使用方法 セットアップや使用方法 閲覧数 48
Cybozu_kintone 2024年11月20日作成 (2024年11月20日更新) © MIT セットアップや使用方法 セットアップや使用方法 閲覧数 48

SONY Spresense と LTE拡張ボードでkintoneにHTTPリクエストする方法

SONY Spresense と LTE拡張ボードでkintoneにHTTPリクエストする方法

この記事ではSONY SpresenseのLTE 拡張ボードを使い、クラウドサービスのkintoneにHTTPリクエストをする方法を案内します。

SONY Spresenseとは

SONY Spresense (以降、Spresense)は低消費電力でありながら、GPS受信機能とハイレゾリューションオーディオコーデックを搭載したIoT用ボードコンピュータです。この記事ではSpresenseメインボードをLTE拡張ボードにとりつけて、kintoneにHTTPリクエストをする方法を案内します。

この記事で作るもの

この記事ではkintoneでスコアランキングアプリを作り、SpresenseのLTE経由でランキングを取得したり、スコアを追加する方法を案内します。

SpresenseのLTE拡張でkintoneにHTTPリクエストをする

連携の作り方

kintoneアプリの準備

まずはkintone側の準備から説明します。

kintone環境の準備する

kintoneの環境が無い方は、開発者サイトから1年間無償で使用できる『開発者ライセンス』という名のkintone環境を取得出来ます。下記のサイトで『開発者ライセンスを申し込む』をクリックし、フォームに必要事項を入力して下さい。申込後、メールでkintone環境の情報が送られてきます。所要時間はおおよそ10分程度です。

https://cybozu.dev/ja/kintone/developer-license/

kintoneアプリを作成する

kintoneで作るウェブデータベースは『アプリ』と呼ばれます。

まず、ゲームのスコアを管理するためのkintoneアプリを作成します。プレイヤー名、スコア、難易度等、必要な情報をイメージしながら作りましょう。

kintoneアプリに配置するフィールド

この記事で作成するアプリに必要なフィールドは下記のデーブルに記載したので、参考にしてください。フィールドを配置したら、一つ一つ設定を変更することが出来るので、表示名、フィールドコードやオプションなどを変更します。ちなみに表示名はUI上でユーザに見えるフィールドの名前で、フィールドコードはフィールドのユニークな識別子になります。フィールドコードは外部からHTTPリクエストをする際に重要な設定となります。

フィールドタイプ 表示名 フィールドコード その他の設定
文字列(1行) プレイヤー名 playername
数値 スコア score 単位記号に『points』を追加して後ろに付ける
ラジオボタン 難易度 difficulty 選択肢に 『Easy』『Medium』『Hard』 を追加する

フィールドの配置や設定が終わったら、右上の青いボタンからアプリを公開します。

kintoneアプリにレコードを追加する

ウェブデータベースを作成出来ましたが、データがまだ入っていません。適当に手動でいくつかデータ(レコード)を追加しましょう。

レコードが登録されたkintoneアプリ

kintoneアプリからAPIトークンを発行する

他のシステムと連携をするために、kintoneアプリから認証用のトークンを発行します。アプリの設定画面からAPIトークンを生成します。「レコード閲覧」と「レコード追加」のアクセス権にチェックを入れます。APIトークンを手元でメモした後に、設定を保存してアプリを更新します。
適切な権限設定が付与されたAPIトークン

これでkintoneアプリの準備が出来ました。

Spresenseの準備

次に、Spresense側で必要なデバイスや設定を準備していきます。

必要なデバイスを揃える

SpresenseでLTE通信するためには下記のデバイスが必要です:

本記事で使用するSpresenseのパーツ、MicroSDとSIMカード

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近くのメニューから「この接続は保護されています」を選択し、「証明書は有効です」をクリックします。

Chromeでcybozu.comの証明書を取得する場合

続いて「詳細」タブを選択し、一番上のCertification Authorityと記載されてる箇所を選択します。この状態で下のエクスポートボタンをクリックします。このページではデフォルトで違う箇所が選択されるので、間違えてそちらをエクスポートしないように気をつけてください。Certification Authorityと記載されてる方をエクスポートしてください。

正しい証明書を選択してエクスポートする

保存方法が色々と提示されますが、その中から「DER エンコードバイナリ形式の単一の証明書」を選んで保存します。

どのエンコーディングで証明書を保存するかを選択する

証明書がダウンロード出来たら、SDカードをパソコンに接続し、CERTSディレクトリを作成し、その中に証明書ファイルを入れます。証明書のファイル名は好きなものにします。

SDカードリーダー等を使って証明書を保存する

SDカードに保存が出来たら、SDカードをSpresenseのLTE拡張ボード内に差し込みます。LTE拡張ボードにも電源供給をします。

SIMカードとSDカードがセットされ、電源供給されたSpresenseと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アプリを確認すれば、レコードが追加されてるはずです。
Spresense経由で追加された新しいレコード

コードの改良点

通信状況によっては、GETリクエストでJSONのレスポンスが手に入るまで時間がかかるかもしれません。

kintoneのレコード取得のAPIはいくつかのパラメータを付与することが出来ます。これを駆使することにより、返ってくるJSONのサイズを大幅に縮小することができ、手元に返ってくる時間を減らすことが出来ます。

fields パラメータはJSONに返ってくるフィールドを制限することが出来ます。今回の例ではアプリ作成時にフィールドは3つしか設定してませんが、それ以外にもデフォルトで備わっている「作成者」や「更新者」(これは誰がレコードを作ったり更新したかを記録するフィールド)といったフィールド情報がレスポンスに返ってきます。

query パラメータは条件がマッチするレコードだけが取得するように出来ます。また、データの昇順/降順の指定や最大取得件数の指定も出来ます。

レスポンスに含まれるフィールドをplayernamescoredifficultyのみにして、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のアイコン画像
kintoneのサイボウズです! https://kintone-labo.booth.pm/
ログインしてコメントを投稿する