【GASでIoT】スプレッドシートと連携する「かんたんスマート・カレンダー」を試作する(その4)~スプレッドシートとスクリプト、およびPicoWのスケッチご紹介(続)~
WEBネイティブのアプリである、Googleスプレッドシートは、ネットに繋がる他のデバイスで容易に情報を利用することができます。
そのシンプルな応用例として、スプレッドシートに記載した、イベントが有るか/無いか程度の簡単なカレンダー情報を、LEDの点灯情報で掲示することを試作してみました。
題して「かんたんスマート・カレンダー」です。
このカレンダーのシステムは、サーバ側がGAS、クライアント側がラズベリーパイになっており、ラズベリーパイが発行デバイスを制御して稼働させています。
ラズベリーパイには、安価なPicoWを使用しています。
先回の記事では、この「かんたんスマート・カレンダー」のデータべースとなるスプレッドシートと、GASのプログラムをご紹介しました。
タイトルで提示した、クライアント側である「ラズベリーパイPico W」側の
プログラム(スケッチ)が、まだご紹介できていませんでしたので、今回の記事で取り上げます。
ラズパイPicoWのスケッチ・・・HTTPSクライアントとしてアクセスするためのコード
「かんたんスマート・カレンダー」では、クライアント側として、ラズベリーパイPico Wを使っています。これに発光デバイスであるNeoPixcelを接続して制御します。
本記事では、ラズベリーパイ(ラズパイ)Pico W の開発環境に、メジャーなMicroThonyではなく、ArduinoIDEを使用しています。
これは、筆者の環境では、なぜかMicroThonyでうまく書き込めず、たまたま成功したのがArduinoIDEであったこと、およびHTTPSクライアントとして使う為のサンプルプログラムが、この環境で見つかったためです。
開発環境について
PicoWはマイコンであり、それ自身の中でプログラム開発できないので、PicoWの外部でプログラム開発をしたものを書き込む、という手順を踏みます。
開発環境の構築については、以下の記事をご参照ください。
詳しくは上記をお読みいただきたいのですが、環境構築は以下の3ステップでおこないます。
1.ArduinoIDEのPCへのインストール
開発環境のインストールです
2.ボードマネージャ Raspberry Pi Pico/Rp2040 のインストール
ArduinoUno以外のマイコンを使うためのライブラリをインストールします。この作業はArduinoIDEの「ボードマネージャ」メニューから実施できます。
3.ライブラリ:Adafruit NeoPixcel のインストール
ラズベリーパイに接続する発光デバイスを駆動するライブラリをインストールします。この作業はArduinoIDEの「ライブラリ」メニューから実施できます。
プログラミングの前準備:SSLサイトのルート認証の取得
Googleの各サービスは、HTTPSではじまるURLでアクセスしますが、これらのサイトにアクセスするには、ルート認証という認証コードが必要です。
認証コードは、一般的にはOSやブラウザが処理していますが、ラズベリーパイPico WにはOSがブラウザがないため、プログラム中に明示的に記入しておく必要があります。
このコードは、PCのブラウザで、スプレッドシートなどのURLにアクセスしていただき、ブラウザの鍵マークをクリックすることで取得します。
これについても詳細は、上記の記事にありますので、ご参照ください。
スプレッドシートの公開WEBページのURL
もうひとつ、事前に取得しておくのが、前の記事で公開した、スプレッドシートの公開WEBページのURLです。メモ帳などに控えておいてください。
以上を踏まえて、ArduinoIDE上でスケッチを記述します。
ArduinoIDE上でのスケッチ
少ししたにコードが書いてありますが、各自で打ち替える部分がいくつかありますので、以下を確認しておきましょう。
1.WiFi設定の確認
利用するネットワークのSSIDとPASSを、それぞれスケッチの以下の★SSID★と部分★PASS★に打ち込んでください。
2.ルート認証の確認
HTTPSではじまるURLへのアクセスに必要なものです。
ルート認証コードで、
-----BEGIN CERTIFICATE----- と
-----END CERTIFICATE----- の
間の文字をコピーして貼り付けください、
3.公開WEBページのURLの確認
公開WEBページのURLで、~e/・・・この部分・・・/pubhtml の部分のUテキストを確認し、スケッチの下の方にある、★公開ページのURL★と★公開ページのGID★部分を各自のコードに修正ください。
//----------スプレッドシートのA1セル読み込み----------
if (https.begin("https://docs.google.com/spreadsheets/d/e/★公開ページのURL★/pubhtml?gid=★公開ページのGID★&single=true&range=A1")) {
スケッチ
以下がスケッチです。上記の打ち替えを行ったら、コンパイルしてPicoWに書き込んでみてください。(NeoPixcelの接続はまだ不要です)
/**
作:Particlemethod:2023/05/20
1.ボードマネージャ「arduino-pico(earlephilhower氏作)」を導入してください。
導入後のサンプルにある以下を参考にしています。
BasicHTTPSClient.ino
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino
2.ライブラリ「Adafruit NeoPixel(Adafruit社作)」を導入してください。
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
//----↓NeoPixelライブラリ↓----
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// データ線をPicoWのGPIO1とする
#define PIN 1
// LED素子数を設定する
#define NUMPIXELS 105
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//ピクセルデータの更新間隔(ミリ秒)
#define DELAYVAL 200 // Time (in milliseconds) to pause between pixels
//---↑NeoPixelライブラリ↑----
#ifndef STASSID
#define STASSID "★SSID★"
#define STAPSK "★PASS★"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
//----↓NeoPixelライブラリ↓----
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
pixels.begin(); // INITIALIZE NeoPixel striおp object (REQUIRED)
//---↑NeoPixelライブラリ↑----
}
const char *jigsaw_cert = R"EOF(
-----BEGIN CERTIFICATE-----
★各自の取得したルート認証★
-----END CERTIFICATE-----
)EOF";
static int cnt = 0;
//ループのインターバル
int MyInt = 0;
void loop() {
//======↓↓↓===NeoPixelの初期動作===↓↓↓=========
//--------NeoPixelのクリア---------
pixels.clear(); // Set all pixel colors to 'off'
//----------赤を全点灯:10ポイントずつ輝度アップ----------
for(int iL=0; iL<70; iL=iL+10) {
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(iL, 0, 0));//Increasing Brightness
}
pixels.show();
delay(DELAYVAL); // Pause before next pass through loop
}
pixels.clear(); // Set all pixel colors to 'off'
//----------緑を全点灯:10ポイントずつ輝度アップ----------
for(int iL=0; iL<70; iL=iL+10) {
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, iL, 0));//Increasing Brightness
}
pixels.show();
delay(DELAYVAL); // Pause before next pass through loop
}
pixels.clear(); // Set all pixel colors to 'off'
//----------青を全点灯:10ポイントずつ輝度アップ----------
for(int iL=0; iL<70; iL=iL+10) {
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, iL));//Increasing Brightness
}
pixels.show();
delay(DELAYVAL); // Pause before next pass through loop
}
pixels.clear(); // Set all pixel colors to 'off'
//----------緑を逐次点灯----------
for(int i=0; i<NUMPIXELS; i++) { // For each LED
pixels.setPixelColor(i, pixels.Color(0, 30, 0));
pixels.show(); // Send the updated pixel colors to the hardware.
delay(DELAYVAL); // Pause before next pass through loop
pixels.clear(); // Set all pixel colors to 'off'
}
pixels.clear(); // Set all pixel colors to 'off'
pixels.show(); // Send the updated pixel colors to the hardware.
//----------青を逐次追加点灯----------
for(int i=0; i<NUMPIXELS; i++) { // For each pixel...
pixels.setPixelColor(i, pixels.Color(0, 0, 30));
pixels.show(); // Send the updated pixel colors to the hardware.
delay(DELAYVAL); // Pause before next pass through loop
}
delay(DELAYVAL*2); // Pause before next pass through loop
pixels.clear(); // Set all pixel colors to 'off'
pixels.show(); // Send the updated pixel colors to the hardware.
//======↑↑↑===NeoPixelの初期動作===↑↑↑=========
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient https;
switch (cnt) {
case 0:
Serial.println("[HTTPS] using insecure SSL, not validating certificate");
https.setInsecure(); // Note this is unsafe against MITM attacks
cnt++;
break;
case 1:
Serial.println("[HTTPS] using secure SSL, validating certificate");
https.setCACert(jigsaw_cert);
cnt++;
break;
default:
Serial.println("[HTTPS] not setting any SSL verification settings, will fail");
cnt = 0;
}
Serial.print("[HTTPS] begin...\n");
//----------スプレッドシートのA1セル読み込み----------
if (https.begin("https://docs.google.com/spreadsheets/d/e/★公開ページのURL★/pubhtml?gid=★公開ページのGID★&single=true&range=A1")) { // HTTPS
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
//----------レスポンスの受け取り----------
payload = payload.substring(payload.indexOf("▼▼▼▼"),payload.indexOf("●●●●"));
Serial.println(payload.substring(12));
payload =payload.substring(12);
//----------レスポンスを受け取り損ねたら待機時間1秒、受け取ったら1時間----------
if(payload.substring(0,1)=="D"){MyInt=60*60*1000;}else{MyInt=1000;}
//======↓↓↓===NeoPixelの点灯===↓↓↓=========
for(int iC=1; iC<106; iC++){
//----------0なら消灯----------
if (payload.substring(iC,iC+1) == "0") {
pixels.setPixelColor(iC-1, pixels.Color(0, 0, 0));
pixels.show();
//----------1なら青色----------
} else if (payload.substring(iC,iC+1) == "1") {
pixels.setPixelColor(iC-1, pixels.Color(0, 0, 30));
pixels.show();
//----------2なら水色----------
} else if (payload.substring(iC,iC+1) == "2") {
pixels.setPixelColor(iC-1, pixels.Color(0, 15, 15));
pixels.show();
//----------3なら黄色----------
} else if (payload.substring(iC,iC+1) == "3") {
pixels.setPixelColor(iC-1, pixels.Color(15, 15, 0));
pixels.show();
//----------4なら赤色----------
} else if (payload.substring(iC,iC+1) == "4") {
pixels.setPixelColor(iC-1, pixels.Color(30, 0, 0));
pixels.show();
//----------その他は消灯----------
} else {
pixels.setPixelColor(iC-1, pixels.Color(0, 0, 0));
pixels.show();
}
}
//======↑↑↑===NeoPixelの点灯===↑↑↑=========
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}
//==↓==↓==↓==↓==↓==↓My Code↓==↓==↓==↓====↓==↓==↓==↓
if(MyInt==1000){
//----------レスポンスを取れてない場合は次の試行に入る----------
Serial.println("Wait 10s before next round_InPut...");
delay(MyInt);
}else{
//----------レスポンスを取れていれば1時間待ってリブート----------
Serial.println("Wait 1h before next round_InPut...");
delay(MyInt);
rp2040.reboot();
}
}
うまく作動すれば、ArduinoIDEのシリアルモニタに、得られた文字が表示されるはずです。(以下の例は通信テスト時のものです)
スケッチのポイント
このスケッチは、ラズベリーパイPico Wのボードマネージャを導入した際に添付されていた、HTTPSクライアント用のサンプルスケッチを少しばかり修正したものです。
長いコードですが、実際にプログラムした部分はわずかです。
NeoPixcel制御のためのコード
ライブラリを宣言しています。
ライブラリが提供する、setPixelColor、show という関数で簡単に制御できます。
データの再取得時のコード
ネットワークに接続してから、スプレッドシートの公開ページのレスポンスを得るまでの間に何らかの問題があって、データを取り損なうケースはしばしばあります。
もともとのスケッチには、その様な場合にエラーをトラップして再トライするコードになっています。
しかし、一定時間後に再度データを取得する際は、こうしたエラートラップをかいくぐってしまうことがしばしばあり、悩んだあげく、インターバルを置いてデータを再度取得する場合は、ラズベリーパイPico Wを再起動させることにしました。
スケッチの最後にある以下の短いコードがそれです。
次回は、カレンダー本体である発光デバイスについてご説明します。
この記事が気に入ったらサポートをしてみませんか?