spot-google-sheets
の解説です。セクションの複数ページをまとめています。 印刷またはPDF形式で保存...
Google スプレッドシートの利用
1 - Google スプレッドシートの利用
spot-google-sheets
の解説です。なお、このスケッチでは ESP32 の Arduino 環境から FreeRTOS の機能を利用しています。本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手
GitHub (monowireless/spot-google-sheets) から入手できます。
システムの概要
TWELITE SPOT は、事前に作成したサービスアカウントを使って自動的にスプレッドシートを作成し、指定したユーザアカウントへ、そのファイルを共有します。
ユーザアカウントへログインすると、Google ドライブの「共有アイテム」ページから、TWELITE SPOT によって作成されたスプレッドシートを閲覧・編集できます。
TWELITE SPOT は、作成したスプレッドシートへデータ行を次々と追加していきます。
2023年5月現在、Google Sheets / Drive API の利用に追加料金はかかりません。
ただし、クエリの数などを定めた使用量上限(Sheets API / Drive API)があります。
例えば Google Sheets API では、リクエストを毎分60回以内に押さえなくてはなりません。超過したリクエストはエラーとなります。
サービスアカウントは、アプリケーションが使用するための Google アカウントです。
詳しくは Google による解説をご覧ください。
開発に必要なもの
-
無線LANゲートウェイ TWELITE SPOT
- 電源用 USB-C ケーブル
- USB AC アダプタ(1A 以上供給できるもの)
-
温湿度センサー無線タグ TWELITE ARIA (お持ちでない場合はご購入ください 👉 販売店一覧)
- CR2032 コイン電池
-
USBアダプター TWELITE R3 (お持ちでない場合はご購入ください 👉 販売店一覧)
- 通信用 USB-C ケーブル
- 💻 開発用コンピュータ
- Google アカウント
本稿では TWELITE ARIA を使用しますが、ソースコードを改変することで TWELITE CUE などの子機にも対応できます。
ただし、シートへ書き込むデータが増える場合は、API の 使用量上限 に気を配る必要があります。
環境整備
IDE とツールチェインの導入
Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入
ESP-Google-Sheet-Client ライブラリ
ライブラリマネージャを開き、検索ボックスに esp-google-sheet
と入力してインストールします。
なお、GitHub (mobizt/ESP-Google-Sheet-Client) からも入手できます。
公式 NTP ライブラリ
ライブラリマネージャを開き、検索ボックスに ntpclient
と入力してインストールします。
TimeLib ライブラリ
ライブラリマネージャを開き、検索ボックスに timelib
と入力してインストールします。
事前準備:API のセットアップ
事前に、API を使用できるように準備する必要があります。Google アカウントを使います。
ここでは、下記の作業を行います。
- Google Cloud プロジェクトの作成
- Google Sheets API の有効化
- Google Drive API の有効化
- サービスアカウントの作成と設定
- サービスアカウントの認証情報の取得
プロジェクトの作成
API を使用するにあたって、まずは Google Cloud プロジェクトを作成します。
Google Cloud プロジェクトは、システム全体を束ねるような存在です。構築するシステムの名称をプロジェクト名にするとよいでしょう。ここでは、仮に SPOT-DEV
とします。
下記のリンクにアクセスし、プロジェクトを作成してください。
https://console.cloud.google.com/projectcreate
Sheets API の有効化
TWELITE SPOT からスプレッドシートを操作するために、Sheets API を有効化します。
下記のリンクにアクセスし、API を有効化してください。
https://console.cloud.google.com/apis/library/sheets.googleapis.com
Drive API の有効化
TWELITE SPOT からスプレッドシートを共有するために、Drive API を有効化します。
下記のリンクにアクセスし、API を有効化してください。
https://console.cloud.google.com/apis/library/drive.googleapis.com
サービスアカウントの作成と設定
TWELITE SPOT からスプレッドシートを作成するために、サービスアカウントを作成します。
下記のリンクにアクセスし、プロジェクト名(ここでは SPOT-DEV
)を選択してサービスアカウント一覧画面を表示したのち、ページ上部のボタンからサービスアカウントの作成を開始します。
https://console.cloud.google.com/iam-admin/serviceaccounts
「① サービスアカウントの詳細」では、サービスアカウントの名称を入力します。
下記の例では、spot-dev-sa
としています。
入力したら、「作成して続行」ボタンを押して次へ進みます。
「② このサービスアカウントにプロジェクトへのアクセスを許可する(省略可)」では、サービスアカウントの権限を設定します。
ここでは、下記の例のようにして「オーナー」を選択してください。
選択したら、「続行」ボタンを押して次へ進みます。
「③ ユーザーにこのサービスアカウントへのアクセスを許可(省略可)」では、何も行わずに「完了」を押してスキップします。
サービスアカウントの作成が完了すると、サービスアカウントの一覧画面へ戻ります。作成したサービスアカウントが表示されていることを確認してください。
サービスアカウントの認証情報の取得
作成したサービスアカウントを確認したら、「メール」列のリンクをクリックし、サービスアカウントの詳細画面へ移ります。
上部の「キー」タブを選択して、サービスアカウントの認証に必要な秘密鍵を管理する画面へ移ります。
「鍵を追加」ボタンから「新しい鍵を作成」を選択し、秘密鍵の作成を開始します。
次の画面では、「JSON」を選択した状態のまま「作成」ボタンを押します。
「作成」ボタンを押すと、秘密鍵ファイル(.json
)が自動的にダウンロードされます。
秘密鍵ファイルをテキストエディタで開くと、下記のような構成になっているはずです。
{
"type": "service_account",
"project_id": "???",
"private_key_id": "???",
"private_key": "-----BEGIN PRIVATE KEY-----\n???\n-----END PRIVATE KEY-----\n",
"client_email": "???@???.iam.gserviceaccount.com",
"client_id": "???",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "???",
"universe_domain": "googleapis.com"
}
上記のうち、project_id
/ private_key
/ client_email
の内容を動作確認で使用します。
動作確認
まずは動作確認を行ってみましょう。
プロジェクトファイルを入手
- GitHub (monowireless/spot-google-sheets) から Zip ファイルをダウンロードします
- Zip ファイルを展開し、フォルダ名を
spot-google-sheets-main
からspot-google-sheets
に変更します - Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:
C:\Users\foo\Documents\Arduino
)にspot-google-sheets
フォルダを配置します
スケッチの設定ファイルを修正
Arduino スケッチ spot-google-sheets.ino を開き、画面上部の config.h
タブを選択して、4-11行目の値を修正してください。
4-5行目は、無線 LAN 関連の設定です。
const char* WIFI_SSID = "YOUR SSID"; // Modify it
const char* WIFI_PASSWORD = "YOUR PASSWORD"; // Modify it
SSID と パスワードを設定しています。
一方、8-11行目はスプレッドシート関連の設定です。
const char* PROJECT_ID = "YOUR-PROJECT-ID"; // Modify it
const char* SERVICE_ACCOUNT_EMAIL = "YOUR-SERVICE-ACCOUNT@YOUR-PROJECT-ID.iam.gserviceaccount.com"; // Modify it
const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY\n-----END PRIVATE KEY-----\n"; // Modify it
const char* USER_ACCOUNT_EMAIL = "YOUR-ACCOUNT@EMAIL"; // Modify it
最初の3項目には .json
ファイルの内容をコピーして、最後の USER_ACCOUNT_EMAIL
にはあなたがログインしている Google アカウントのメールアドレスを入力してください。
スケッチを書き込み
ESP32 へのスケッチの書き込み方法 を参考に、スケッチを書き込んでください。
ツール -> Flash Size の設定が 16MB
でないと正常に動きません。
パーティションテーブルには
paritions.csv
を使用しますが、全体のサイズが小さいと正しく書き込めないからです。
親機と子機を起動
TWELITE SPOT のリセットボタン(ESP32 側)を押してください。
Arduino のシリアルコンソールに以下のような表示がされたら、起動に成功しています。
Initializing queue...
Completed.
Started TWELITE.
Connecting to WiFi ...!...
Connected. IP: xxx.xxx.xxx.xxx
Initializing NTP...Completed. UNIX time: xxxxxxxxxx
Initializing sheets...
Creating sheets...
OAuth2.0 access token on initializing
OAuth2.0 access token on signing
OAuth2.0 access token on exchange request
OAuth2.0 access token ready
Requesting to create...
Succeeded.
Adding headers for ARIA...
Requesting to add header...
Succeeded.
Formatting the sheet for ARIA...
Requesting to format...
Succeeded.
Extending the sheet for ARIA...
Requesting to extend...
Succeeded.
Completed.
TWELITE ARIA(初期設定)にもコイン電池を挿入し、電源を投入します。
TWELITE SPOT が TWELITE ARIA からのパケットを正常に受信し、データ列の追加に成功すると、下記のような表示がなされます。
Got a new packet from ARIA.
Got a new packet from ARIA.
Requesting to add data...
Got a new packet from ARIA.
Succeeded.
ちなみに、上記の例ではリクエスト中にパケットを受信しています。後述のマルチタスクに成功している証です!
Google へアクセス
Google ドライブの 共有アイテム へアクセスし、SPOT Sheet (xxx)
という名前のスプレッドシートを開きます。
以下のような画面が表示されます。
スクロールしていくと、TWELITE ARIA からのデータを確認できるはずです。
Ctrl (⌘) + ↓
を押します。スケッチ解説
Arduino スケッチ spot-google-sheets.ino の解説です。
ライブラリのインクルード
Arduino および ESP32 公式ライブラリ
4-7行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
ヘッダファイル | 内容 | 備考 |
---|---|---|
Arduino.h | Arduino の基本ライブラリ | |
NTPClient.h | NTP を使う | ファイル名と受信時刻に使用 |
WiFi.h | ESP32 の WiFi を使う | |
WiFiUdp.h | UDP を使う | NTPClient に必要 |
サードパーティのライブラリ
10-11行目では、サードパーティのライブラリをインクルードしています。
#include <ESP_Google_Sheet_Client.h>
#include <TimeLib.h>
ヘッダファイル | 内容 | 備考 |
---|---|---|
ESP_Google_Sheet_Client.h | Google へアクセスする | |
TimeLib.h | UNIX 時間をフォーマットする |
MWings ライブラリ
14行目では、MWings ライブラリをインクルードしています。
#include <MWings.h>
ユーザ設定の定義
17行目では、config.h
をインクルードしています。
#include "config.h"
config.h
では、ユーザ設定を定義しています。実行時には、この設定を書き換えてください。無線 LAN 設定の定義
config.h
の4-5行目では、TWELITE SPOT に搭載された ESP32 に適用する無線 LAN 設定を定義します。
const char* WIFI_SSID = "YOUR SSID"; // Modify it
const char* WIFI_PASSWORD = "YOUR PASSWORD"; // Modify it
名称 | 内容 |
---|---|
WIFI_SSID | 接続するネットワークの SSID |
WIFI_PASSWORD | 接続するネットワークの パスワード |
API 設定の定義
config.h
の8-11行目では、API の設定を定義しています。
const char* PROJECT_ID = "YOUR-PROJECT-ID"; // Modify it
const char* SERVICE_ACCOUNT_EMAIL = "YOUR-SERVICE-ACCOUNT@YOUR-PROJECT-ID.iam.gserviceaccount.com"; // Modify it
const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY\n-----END PRIVATE KEY-----\n"; // Modify it
const char* USER_ACCOUNT_EMAIL = "YOUR-ACCOUNT@EMAIL"; // Modify it
名称 | 内容 |
---|---|
PROJECT_ID | プロジェクト ID |
SERVICE_ACCOUNT_EMAIL | サービスアカウントのメールアドレス |
PRIVATE_KEY | 秘密鍵の本体 |
USER_ACCOUNT_EMAIL | スプレッドシートを共有するユーザアカウントのメールアドレス |
ピン番号の定義
20-24行目では、ピン番号を定義しています。
const uint8_t TWE_RST = 5;
const uint8_t TWE_PRG = 4;
const uint8_t LED = 18;
const uint8_t ESP_RXD1 = 16;
const uint8_t ESP_TXD1 = 17;
名称 | 内容 |
---|---|
TWE_RST | TWELITE の RST ピンが接続されているピンの番号 |
TWE_PRG | TWELITE の PRG ピンが接続されているピンの番号 |
LED | 基板上の ESP32 用 LED が接続されているピンの番号 |
ESP_RXD1 | TWELITE の TX ピンが接続されているピンの番号 |
ESP_TXD1 | TWELITE の RX ピンが接続されているピンの番号 |
TWELITE 設定の定義
27-30行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18;
const uint32_t TWE_APPID = 0x67720102;
const uint8_t TWE_RETRY = 2;
const uint8_t TWE_POWER = 3;
名称 | 内容 |
---|---|
TWE_CH | TWELITE の 周波数チャネル |
TWE_APPID | TWELITE の アプリケーション ID |
TWE_RETRY | TWELITE の 再送回数(送信時) |
TWE_POWER | TWELITE の 送信出力 |
シート関連の定義
32-43行目では、シートに関連した情報を定義しています。
const char* SPREADSHEET_TITLE_PREFIX = "SPOT Sheet";
const char* SPREADSHEET_LOCALE = "ja_JP";
const char* SPREADSHEET_TIME_ZONE = "Asia/Tokyo";
const int MIN_REQUEST_INTERVAL = 1000; // 60 requests per minute
const int SHEETS_DEFAULT_ROWS = 1000; // Default length is 1000 rows
const int SHEETS_ROWS = 100000; // Max 1,000,000 rows at 10 columns
const int ARIA_SHEET_ID = 1;
const char* ARIA_SHEET_TITLE = "ARIA";
constexpr int ARIA_BUFFER_PACKETS = 32; // Max number of rows per addition request
名称 | 内容 |
---|---|
SPREADSHEET_TITLE_PREFIX | スプレッドシートのファイル名の固定部分 |
SPREADSHEET_LOCALE | スプレッドシートのロケール |
SPREADSHEET_TIME_ZONE | スプレッドシートのタイムゾーン |
MIN_REQUEST_INTERVAL | リクエスト送信の最小間隔 |
SHEETS_DEFAULT_ROWS | 各シートのデフォルトの行数 |
SHEETS_ROWS | 各シートの行数 |
ARIA_SHEET_ID | ARIA 用シートの ID |
ARIA_SHEET_TITLE | ARIA 用シートの名称 |
ARIA_BUFFER_PACKETS | ARIA からのパケットを格納するキューの長さ |
TWELITE ARIA 以外の子機に対応するときには、同一のスプレッドシート(ワークブック)に別のシートを作成することを推奨します。
したがって、ID、タイトル、キューの長さの3点を付け加える必要があります。
型の宣言
46-50行目では、型を宣言しています。
struct ParsedAppAriaPacketWithTime {
ParsedAppAriaPacket packet;
uint32_t elapsedMillis;
uint32_t unixTime;
};
名称 | 内容 |
---|---|
ParsedAppAriaPacketWithTime | 受信したパケットデータを受信時刻と合わせてキューへ格納するための型 |
elapsedMillis
:パケット受信時の起動からの経過時間(ミリ秒)unixTime
:パケット受信時の UNIX 時間(秒)です。
TWELITE ARIA 以外の子機に対応するときには、新たにキューを作成する必要があります。
したがって、ParsedAppAriaPacketWithTime
のようなキュー格納用の型についても付け加える必要があります。
グローバルオブジェクトの宣言
53-61行目では、グローバルオブジェクトを宣言しています。
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.nict.jp", 32400);
String spreadsheetIdString; // Identifier of newly created file
bool readyForNewRequests = false;
uint32_t lastTimeRequestWasSent = UINT32_MAX;
QueueHandle_t ariaPacketQueue; // Store received data from ARIA
uint32_t rowToAddNewAriaData = 2; // Starting with the Row 2
名称 | 内容 |
---|---|
ntpUDP | NTP のための UDP インタフェース |
timeClient | NTP のインタフェース |
spreadsheetIdString | 作成したスプレッドシートのID |
readyForNewRequests | 新たなリクエストを送信できる状態になったら true |
lastTimeRequestWasSent | 最後にリクエストを送信した時間 |
ariaPacketQueue | ARIA から受信したパケットと受信時刻を格納するキュー |
rowToAddNewAriaData | 次に ARIA から受信したデータを追加する行 |
ariaPacketQueue
は、Arduino core for the ESP32 のベースになっている FreeRTOS の Queue 機能を使います。関数プロトタイプの宣言
64-71行目では、関数プロトタイプを宣言しています。
void anotherLoop();
void waitUntilNewRequestsReady();
String createSpreadsheet();
bool formatSheet(const String spreadsheetId, const int sheetId);
bool extendSheet(const String spreadsheetId, const int sheetId, const int rows);
bool addSheetAriaHeaderRow(const String spreadsheetId, const char* const sheetTitle);
bool addSheetsDataRow(const String spreadsheetId);
名称 | 内容 |
---|---|
anotherLoop() | 非同期で TWELITE の処理を行う、もうひとつの loop() |
waitUntilNewRequestsReady() | 次のリクエストを送信可能になるまで待機する |
createSpreadsheet() | スプレッドシートを新規作成する |
formatSheet() | 指定したシートの書式を設定する |
extendSheet() | 指定したシートの行を増やし、書式を設定する |
addSheetAriaHeaderRow() | 指定したシートへ ARIA 向けのヘッダー行を追加する |
addSheetsDataRow() | シートへデータ行を追加する |
anotherLoop()
を作成し、そのなかで Twelite.update()
を実行しています。TWELITE ARIA 以外の子機に対応するときには、例えば、下記のような方針でリクエストの内容を追加します。
createSpreadsheet()
:スプレッドシートを増やすように改変するformatSheet()
:新たなシートもフォーマットするように改変するextendSheet()
:内容はそのまま、新たなシートに対しても呼び出すaddSheet**HeaderRow()
:関数ごと付け加えるaddSheetsDataRow()
:新たなシートへデータを追加する処理を追加する
キューの設定
82-83行目では、受信したパケットデータを受信時刻と合わせて格納するためのキューを初期化しています。
ariaPacketQueue = xQueueCreate(ARIA_BUFFER_PACKETS, sizeof(ParsedAppAriaPacketWithTime));
if (ariaPacketQueue == 0) { Serial.println("Failed to init a queue."); }
xQueueCreate()
は、ESP32 の内部で動作する FreeRTOS の機能です。マルチタスクに対応したキューを簡単に作成することができます。
TWELITE の設定
88-92行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Serial2.begin(115200, SERIAL_8N1, ESP_RXD1, ESP_TXD1);
if (Twelite.begin(Serial2,
LED, TWE_RST, TWE_PRG,
TWE_CH, TWE_APPID, TWE_RETRY, TWE_POWER)) {
Serial.println("Started TWELITE.");
}
引数 | 型 | 内容 |
---|---|---|
Serial2 | HardwareSerial& | TWELITE との通信に使うシリアルポート |
LED | int | ステータス LED を接続したピンの番号 |
TWE_RST | int | TWELITE の RST ピンを接続したピンの番号 |
TWE_PRG | int | TWELITE の PRG ピンを接続したピンの番号 |
TWE_CHANNEL | uint8_t | TWELITE の 周波数チャネル |
TWE_APP_ID | uint32_t | TWELITE の アプリケーション ID |
TWE_RETRY | uint8_t | TWELITE の 再送回数(送信時) |
TWE_POWER | uint8_t | TWELITE の 送信出力 |
イベントハンドラの登録
94-103行目では、TWELITE ARIA からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("Got a new packet from ARIA.");
ParsedAppAriaPacketWithTime packetWithTime;
packetWithTime.elapsedMillis = millis();
packetWithTime.unixTime = timeClient.getEpochTime();
packetWithTime.packet = packet;
if (not(xQueueSend(ariaPacketQueue, &packetWithTime, 0) == pdPASS)) {
Serial.println("Failed to add packet data to the queue.");
}
});
ここでは、xQueueSend()
により、受信したパケットデータを受信時刻と合わせてキューの末尾へ格納しています。
無線 LAN の設定
106-120行目では、無線 LAN の設定を行っています。
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
static int count = 0;
Serial.print('.');
delay(500);
// Retry every 5 seconds
if (count++ % 10 == 0) {
WiFi.disconnect();
WiFi.reconnect();
Serial.print('!');
}
}
ここでは、無線 LAN 子機として設定したうえで、指定のネットワークへ接続しています。
ネットワークに接続できるまで、while
文を出ません。
上記の実装では、5秒に一度、再接続を試みています。
NTP の設定
126-127行目では、NTP の設定をしています。
timeClient.begin();
timeClient.update();
Google スプレッドシートの設定
132-145行目では、Google スプレッドシートを設定しています。
GSheet.setTokenCallback([](TokenInfo info) {
// Print token initialization states
if (info.status == esp_signer_token_status_error) {
Serial.print("Token error ");
Serial.println(GSheet.getTokenError(info));
}
Serial.print(GSheet.getTokenType(info));
Serial.print(" ");
Serial.println(GSheet.getTokenStatus(info));
});
GSheet.setPrerefreshSeconds(60); // Set refresh rate for auth token
Serial.println("Initializing sheets...");
GSheet.begin(SERVICE_ACCOUNT_EMAIL, PROJECT_ID, PRIVATE_KEY);
132-141行目でサービスアカウントのトークンを取得する際の状態表示の処理を登録したあと、142行目でトークンの再取得間隔を設定、145行目でサービスアカウントの初期化をしています。
また、147-173行目では、スプレッドシートの作成、ARIA 向けヘッダー行の追加、セルの書式設定、そして行の拡張を行っています。
Serial.println("Creating sheets...");
waitUntilNewRequestsReady(); // Wait for token
spreadsheetIdString = createSpreadsheet();
if (not(spreadsheetIdString.length() > 0)) {
Serial.println("Failed to create sheets.");
}
Serial.println("Adding headers for ARIA...");
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not addSheetAriaHeaderRow(spreadsheetIdString, ARIA_SHEET_TITLE)) {
Serial.println("Failed to add headers.");
}
Serial.println("Formatting the sheet for ARIA...");
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not formatSheet(spreadsheetIdString, ARIA_SHEET_ID)) {
Serial.println("Failed to format.");
}
Serial.println("Extending the sheet for ARIA...");
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not extendSheet(spreadsheetIdString, ARIA_SHEET_ID, SHEETS_ROWS - SHEETS_DEFAULT_ROWS)) {
Serial.println("Failed to extend.");
}
デフォルトでは、A-Z 列のセルが 1,000 行続きます。ここでは列を A-J の 10 列に絞り、行数を 100倍の 100,000 行に増やしています。
それでも足りない場合には、さらに行を増やす必要があります。ただし、セルの上限は 10,000,000 個のため、 A-J の10 列の場合、最大 1,000,000 行に制限されます。それ以上はセルを増やせないため、新たなスプレッドシート(ワークブック)を作成する必要があります。
タスクの登録
179-186行目では、TWELITE のデータを非同期で更新するためのタスクを登録しています。
xTaskCreatePinnedToCore(
[](void* params) {
while (true) {
anotherLoop();
vTaskDelay(1);
}
},
"Task for anotherLoop()", 8192, nullptr, 18, nullptr, 0);
xTaskCreatePinnedToCore()
は、FreeRTOS のマルチタスク機能に含まれる関数です。
ここでは、180-185行目のラムダ式を渡し、anotherLoop()
を無限に呼ぶタスクを登録しています。
[](void* params) {
while (true) {
anotherLoop();
vTaskDelay(1); // IMPORTANT for Watchdog
}
},
vTaskDelay(1);
などを挿入し、ウォッチドッグタイマの入る隙を与えてください。タスクの名称は Task for anotherLoop()
で、スタックサイズは 8192
、タスクへのパラメータはなく、優先度は 18
(大きいほど高く、無線 LAN 関連の処理は1個上の 19
)、タスクを操作するインタフェースもなく、実行する CPU コアは無線 LAN などの RF 処理と同じ Core 0
です( loop()
等は Core 1
)。
"Task for anotherLoop()", 8192, nullptr, 18, nullptr, 0); // Priority is 18 (lower than WiFi)
TWELITE のデータの更新
203行目では、anotherLoop()
内にて Twelite.update()
を呼び出しています。
Twelite.update();
Twelite.update()
は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop()
内で繰り返し Twelite.update()
を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に 上記 のようなイベントが呼ばれる仕組みです。delay()
などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。しかし、このスケッチでは FreeRTOS の機能によって anotherLoop()
を切り離しているため、たとえ loop()
内で同期処理があっても問題ありません。スプレッドシートの更新
192-195行目では、スプレッドシートの更新処理を呼び出しています。
if (millis() - lastTimeRequestWasSent > MIN_REQUEST_INTERVAL) {
// Add available data
addSheetsDataRow(spreadsheetIdString);
}
192行目の if 文では、60リクエスト毎分の API 制限を守るために、前回のリクエスト送信から必ず 1 秒以上空けるようにしています(JavaScript の Throttle / Debounce における Throttle に相当します)。
194行目では、必要に応じてスプレッドシートへデータ行を追加します。
addSheetsDataRow(spreadsheetIdString);
API ライブラリの更新
196行目では、Google API 用ライブラリの更新を行い、リクエストの送信可否の状態を取得しています。
readyForNewRequests = GSheet.ready();
NTP ライブラリの更新
197行目では、NTP ライブラリの更新を行っています。
timeClient.update();
スプレッドシートの操作
217行目以降では、Sheets API によるスプレッドシートの操作を行っています。
詳しくは ライブラリの API リファレンス や Sheets API の REST リソース をご覧ください。
関連情報
- Google Cloud コンソール:ようこそ – SPOT-DEV – Google Cloud コンソール
- Sheets REST API リファレンス:Google Sheets API | Google for Developers
- Sheets REST サンプル:サンプル | Google Sheets | Google for Developers
Arduino
- 公式サイト:Arduino - Home
ESP32
- 製品情報:ESP32 Wi-Fi & Bluetooth MCU I Espressif Systems
- データシート:esp32_datasheet_en.pdf
- Arduino 向けツールチェイン:espressif/arduino-esp32: Arduino core for the ESP32
- スタートガイド:Getting Started — Arduino-ESP32 documentation
- 導入方法:Installing — Arduino-ESP32 documentation
- API リファレンス:Libraries — Arduino-ESP32 documentation
- Wi-Fi API:Wi-Fi API — Arduino-ESP32 documentation
- チュートリアル:Tutorials — Arduino-ESP32 documentation
- トラブルシューティング:Troubleshooting — Arduino-ESP32 documentation
- ESP-IDF:espressif/esp-idf: Espressif IoT Development Framework
- ドキュメント:ESP-IDF Programming Guide - ESP32
- APIリファレンス:FreeRTOS (ESP-IDF) - ESP32
- ドキュメント:ESP-IDF Programming Guide - ESP32
コミュニティ
ライブラリ
- Google Sheets / Drive API:mobizt/ESP-Google-Sheet-Client: Arduino Google Sheet REST client library for ESP8266, ESP32 and Raspberry Pi Pico RP2040
- 日付と時刻:PaulStoffregen/Time: Time library for Arduino