第12章 Googleスプレッドシートへのデータ記録
🔒 研修参加者向け
この章は研修参加者向けです
この章では、DHT11の温湿度データをGoogle Apps Script経由でGoogleスプレッドシートへ記録する方法を扱います。
研修参加者の方は、講師から案内されたパスワードを入力してください。
この教材を利用した研修については、お問い合わせください。
この章の目的
Section titled “この章の目的”第11章では、Pico WをWebサーバーとして動かし、 同じネットワーク内のPCからLEDを操作しました。
この章ではPico Wの役割をクライアントへ戻し、 DHT11で測定した温度・湿度をインターネット上へ送信します。 送信されたデータはGoogle Apps Scriptが受け取り、 Googleスプレッドシートへ1行ずつ記録します。
DHT11で測定 ↓Pico WからHTTPSで送信 ↓Google Apps Scriptが受信 ↓Googleスプレッドシートへ追記 ↓PC・スマートフォンで確認測定値をその場で表示するだけでなく、 時刻とともに蓄積して変化を確認できるようにします。
実機検証について
この章のApps ScriptとPico W側コードは、 章全体を確認できるように作成した検証前の暫定版です。 MicroPythonの版、HTTPライブラリ、Googleアカウントの種類、 Apps Scriptの公開設定、複数台同時送信を実機で確認した後に確定します。
この章でできるようになること
Section titled “この章でできるようになること”- Pico W、Apps Script、Googleスプレッドシートの役割を説明できる
- 測定値をJSON形式に整理できる
- Pico WからHTTPSの
POSTリクエストを送信できる - Apps Scriptの
doPost()で測定値を受け取る仕組みを説明できる - 測定値へクラウド側の受信時刻を付けて記録できる
- 実習機番号を使って複数台のデータを区別できる
- スプレッドシートの表とグラフをPCやスマートフォンで確認できる
- センサー読み取りエラーとクラウド送信エラーを区別できる
使用するもの
Section titled “使用するもの”| 分類 | 使用するもの | 数量・条件 |
|---|---|---|
| 制御用ボード | MicroPython導入済みのRaspberry Pi Pico WまたはPico WH | 1 |
| センサー | 第9章で配線した4端子DHT11 | 1 |
| PC接続 | データ通信対応Micro USBケーブル | 1 |
| 開発環境 | Thonnyを使用できるWindows PC | 1 |
| ネットワーク | インターネットへ接続できる2.4GHz Wi-Fi | 1 |
| クラウド | 講師が準備したGoogleスプレッドシートとApps Script | 1式 |
| 確認端末 | Webブラウザーを使用できるPCまたはスマートフォン | 1 |
この章では新しい電子部品を追加しません。
第9章と同じDHT11を使用し、DATAはGP16へ接続します。
第5章のGP15 LED回路は配線したままでも構いませんが、
この章のプログラムでは使用しません。
接続情報とデータを扱うときの注意
Section titled “接続情報とデータを扱うときの注意”- 実在するWi-Fi情報、送信先URL、研修用トークンを公開しません
- 設定済みコードをGitや公開フォルダーへ保存しません
- 実習機番号には受講者名やメールアドレスを使用しません
- この章では
KIT-01からKIT-99までの形式を使用します - スプレッドシートは閲覧に必要な範囲だけ共有します
- 研修終了後は、講師がWebアプリを無効化するかトークンを変更します
- 業務上の機密情報や個人情報を送信しません
送信先URLと研修用トークンを知っている機器は、 Webアプリへデータを送信できる可能性があります。 この構成は研修用の簡易的な識別であり、 業務システム向けの本格的な認証ではありません。
12-1 クラウドへ記録する仕組み
Section titled “12-1 クラウドへ記録する仕組み”この章では、Pico WがGoogleスプレッドシートを 直接編集するのではありません。
Pico WからGoogle Apps ScriptのWebアプリへ測定値を送り、 Apps Scriptがスプレッドシートへ書き込みます。
| 構成要素 | この章での役割 |
|---|---|
| DHT11 | 温度と湿度を測定する |
| Pico W | 測定値を整理し、HTTPSで送信するクライアント |
| Apps Script | 受信内容を検査し、記録処理を実行するWebアプリ |
| Googleスプレッドシート | 時刻と測定値を表として蓄積する |
| PC・スマートフォン | 表やグラフを確認する |
図12-1 温湿度データをGoogleスプレッドシートへ記録する流れ
第11章との役割の違いを確認します。
| 項目 | 第11章 | 第12章 |
|---|---|---|
| Pico Wの役割 | Webサーバー | Webクライアント |
| 通信相手 | 同じネットワーク内のPC | インターネット上のWebアプリ |
| 主なHTTPメソッド | ブラウザーからGET・POST | Pico WからPOST |
| データ保存 | 行わない | スプレッドシートへ記録 |
| 確認範囲 | 同一ネットワーク内 | 共有設定に応じてPC・スマートフォンから確認 |
12-2 送信するデータを整理する
Section titled “12-2 送信するデータを整理する”Pico Wは、1回の測定結果を次のJSON形式で送信します。
{ "token": "研修用トークン", "kit_id": "KIT-01", "temperature": 24, "humidity": 55, "state": "通常"}| 項目 | 内容 | スプレッドシートへの記録 |
|---|---|---|
token | 研修用の送信トークン | 記録しない |
kit_id | データを送った実習機番号 | 記録する |
temperature | DHT11で測定した温度 | 記録する |
humidity | DHT11で測定した相対湿度 | 記録する |
state | 研修用しきい値による判定 | 記録する |
記録日時はPico Wから送りません。 Apps Scriptがデータを受け取ったときに、 クラウド側で現在時刻を追加します。
これにより、Pico Wの時計合わせをこの章へ追加せずに、 測定値を時系列データとして保存できます。
12-3 スプレッドシートを準備する
Section titled “12-3 スプレッドシートを準備する”ここから12-4節までは、講師が研修前に行う準備です。 受講者は完成済みのWebアプリを使用します。
Googleスプレッドシートを1つ作成し、 シート名を次のとおり変更します。
sensor_log1行目へ、左から次の見出しを入力します。
| A列 | B列 | C列 | D列 | E列 |
|---|---|---|---|---|
| 記録日時 | 実習機 | 温度(℃) | 湿度(%) | 状態 |
この章では、全実習機の測定値を1枚のシートへ記録し、
KIT-01などの実習機番号で区別します。
スプレッドシートIDを確認する
Section titled “スプレッドシートIDを確認する”スプレッドシートのURLは、次のような形です。
https://docs.google.com/spreadsheets/d/スプレッドシートID/edit/d/と/editの間がスプレッドシートIDです。
この値はApps Scriptへ設定します。
URL全体を教材、画面共有、提出物へ記載しません。
12-4 Apps ScriptのWebアプリを準備する
Section titled “12-4 Apps ScriptのWebアプリを準備する”スプレッドシートに関連付けたApps Scriptプロジェクトを開き、
次のコードをCode.gsへ保存します。
SPREADSHEET_IDとWRITE_TOKENは、
講師が準備した実際の値へ置き換えます。
本文や受講者向け配布物へ実際の値を掲載しません。
const SPREADSHEET_ID = "YOUR_SPREADSHEET_ID";const SHEET_NAME = "sensor_log";const WRITE_TOKEN = "YOUR_WRITE_TOKEN";
function doGet() { return createJsonResponse({ ok: true, service: "pico-dx-logger", });}
function doPost(event) { try { const payload = JSON.parse(event.postData.contents);
if (String(payload.token || "") !== WRITE_TOKEN) { return createJsonResponse({ ok: false, error: "unauthorized", }); }
const kitId = String(payload.kit_id || ""); const temperature = Number(payload.temperature); const humidity = Number(payload.humidity); const state = String(payload.state || "");
if (!/^KIT-[0-9]{2}$/.test(kitId)) { throw new Error("invalid kit_id"); }
if ( !Number.isFinite(temperature) || temperature < -20 || temperature > 60 ) { throw new Error("invalid temperature"); }
if ( !Number.isFinite(humidity) || humidity < 0 || humidity > 100 ) { throw new Error("invalid humidity"); }
if (state !== "通常" && state !== "注意") { throw new Error("invalid state"); }
const lock = LockService.getScriptLock(); if (!lock.tryLock(5000)) { return createJsonResponse({ ok: false, error: "busy", }); }
const recordedAt = new Date();
try { const spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID); const sheet = spreadsheet.getSheetByName(SHEET_NAME);
if (sheet === null) { throw new Error("sheet not found"); }
sheet.appendRow([ recordedAt, kitId, temperature, humidity, state, ]); } finally { lock.releaseLock(); }
return createJsonResponse({ ok: true, recorded_at: recordedAt.toISOString(), }); } catch (error) { return createJsonResponse({ ok: false, error: String(error.message || error), }); }}
function createJsonResponse(value) { return ContentService .createTextOutput(JSON.stringify(value)) .setMimeType(ContentService.MimeType.JSON);}doGet()で稼働を確認する
Section titled “doGet()で稼働を確認する”WebアプリのURLをブラウザーで開くと、
Apps ScriptはdoGet()を実行します。
{"ok":true,"service":"pico-dx-logger"}この表示はWebアプリが応答していることを確認するもので、 スプレッドシートへ測定値を追加しません。
doPost()で測定値を受け取る
Section titled “doPost()で測定値を受け取る”Pico WがPOSTリクエストを送ると、
Apps ScriptはdoPost()を実行します。
受信したJSONから実習機番号、温度、湿度、状態を取り出し、
形式と値を確認してからappendRow()で1行追加します。
同時書き込みを順番に処理する
Section titled “同時書き込みを順番に処理する”複数のPico Wから同じ時刻にデータが届く可能性があります。
const lock = LockService.getScriptLock();if (!lock.tryLock(5000)) {LockServiceを使い、共有シートを書き換える部分を
一度に1つの処理だけが実行するようにします。
5秒以内に順番が回ってこない場合は、
busyを返して書き込みを行いません。
同時利用台数と待ち時間は実機検証後に調整します。
Webアプリとしてデプロイする
Section titled “Webアプリとしてデプロイする”Apps ScriptをWebアプリとしてデプロイします。 現行画面では、概ね次の内容を設定します。
- 新しいデプロイを作成します
- 種類としてWebアプリを選択します
- スクリプト所有者の権限で実行する設定を選びます
- 研修用Pico Wからアクセスできる公開範囲を選びます
- 初回の権限確認を完了します
/execで終わるWebアプリURLを控えます
Google Workspaceの管理設定によっては、 認証なしでアクセスできる公開範囲を選択できない場合があります。 その場合、この方式を研修で使用できるとは限りません。
/devで終わるURLは編集権限を持つ利用者向けのテスト用です。
Pico Wからの送信には、デプロイ後の/execで終わるURLを使用します。
12-5 Pico WのHTTPライブラリを確認する
Section titled “12-5 Pico WのHTTPライブラリを確認する”MicroPythonからHTTPリクエストを送るため、
requestsまたはurequestsを使用します。
次の2行をThonnyのShellで順番に試し、 どちらかがエラーなく読み込めることを確認します。
import requestsimport urequestsどちらも使用できない場合は、
講師の指示に従ってMicroPython用のrequestsパッケージを導入します。
ネットワークへ接続した状態でmipを利用する場合は、
次のように実行します。
import mipmip.install("requests")使用するMicroPythonファームウェアに HTTPライブラリが含まれているかは、研修前に確認します。 受講者が研修中に個別インストールしなくてよい状態を基本とします。
12-6 温湿度を30秒ごとに送信する
Section titled “12-6 温湿度を30秒ごとに送信する”第9章のDHT11配線を確認します。
| 接続元 | 接続先 |
|---|---|
DHT11の1番端子VCC | 3V3(OUT) |
DHT11の2番端子DATA | GP16 |
DHT11の3番端子NC | 接続しない |
DHT11の4番端子GND | GND |
| 4.7kΩ抵抗 | DHT11のVCCとDATAの間 |
回路図と詳しい配線手順は、 第9章の図9-1と9-3節を 参照してください。
次のプログラムをch12_01_google_sheets_logger.pyとして
PC側へ保存します。
実行前に次の4項目を講師から指定された値へ置き換えます。
WIFI_SSIDWIFI_PASSWORDWEB_APP_URLWRITE_TOKEN
自分の実習機に割り当てられたKIT_IDも確認します。
WebアプリURLには、/execで終わる完全なURLを指定します。
from machine import Pinimport dhtimport jsonimport networkimport time
try: import requestsexcept ImportError: import urequests as requests
WIFI_SSID = "YOUR_SSID"WIFI_PASSWORD = "YOUR_PASSWORD"WEB_APP_URL = ( "https://script.google.com/macros/s/" "YOUR_DEPLOYMENT_ID/exec")WRITE_TOKEN = "YOUR_WRITE_TOKEN"KIT_ID = "KIT-01"
DHT_PIN = 16SEND_INTERVAL = 30CONNECT_TIMEOUT_MS = 20000TEMP_WARNING = 28HUMIDITY_WARNING = 70
def connect_wifi(): wlan = network.WLAN(network.WLAN.IF_STA)
wlan.active(False) time.sleep(1) wlan.active(True)
print("Wi-Fiへ接続します...") wlan.connect(WIFI_SSID, WIFI_PASSWORD) start_time = time.ticks_ms()
while not wlan.isconnected(): status = wlan.status()
if status in ( network.STAT_WRONG_PASSWORD, network.STAT_NO_AP_FOUND, network.STAT_CONNECT_FAIL, ): wlan.active(False) raise RuntimeError( "Wi-Fi接続に失敗しました。status={}".format(status) )
elapsed = time.ticks_diff( time.ticks_ms(), start_time, ) if elapsed >= CONNECT_TIMEOUT_MS: wlan.active(False) raise RuntimeError( "Wi-Fi接続がタイムアウトしました。" "status={}".format(status) )
print("接続待ち... status={}".format(status)) time.sleep(1)
print("Wi-Fi接続成功:", wlan.ifconfig()[0]) return wlan
def send_reading(temperature, humidity, state): payload = { "token": WRITE_TOKEN, "kit_id": KIT_ID, "temperature": temperature, "humidity": humidity, "state": state, } headers = { "Content-Type": "application/json", }
response = None
try: response = requests.post( WEB_APP_URL, data=json.dumps(payload), headers=headers, )
if response.status_code != 200: raise RuntimeError( "HTTP status={}".format(response.status_code) )
result = response.json() if not result.get("ok"): raise RuntimeError( "Apps Script error={}".format( result.get("error", "unknown") ) )
print( "クラウド送信成功:", result.get("recorded_at", ""), ) finally: if response is not None: response.close()
sensor = dht.DHT11(Pin(DHT_PIN))wlan = Nonetime.sleep(2)
try: wlan = connect_wifi()
while True: try: sensor.measure() temperature = sensor.temperature() humidity = sensor.humidity()
if ( temperature >= TEMP_WARNING or humidity >= HUMIDITY_WARNING ): state = "注意" else: state = "通常"
print( "温度:", temperature, "℃", "湿度:", humidity, "%", "状態:", state, ) except OSError as error: print("センサー読み取りエラー:", error) else: try: if not wlan.isconnected(): wlan = connect_wifi()
send_reading( temperature, humidity, state, ) except Exception as error: print("クラウド送信エラー:", error)
time.sleep(SEND_INTERVAL)except KeyboardInterrupt: print("データ送信を停止します")finally: if wlan is not None: wlan.active(False)実行すると、Shellへ測定値と送信結果が表示されます。
Wi-Fiへ接続します...Wi-Fi接続成功: 192.168.10.42温度: 24 ℃ 湿度: 55 % 状態: 通常クラウド送信成功: 2026-07-27T05:30:12.345ZIPアドレス、測定値、日時は実行環境によって異なります。 Apps Scriptが返す日時はUTC表記になる場合がありますが、 スプレッドシートではファイルのタイムゾーンに従って表示されます。
30秒ごとに送信する
Section titled “30秒ごとに送信する”SEND_INTERVAL = 30第9章ではDHT11を2秒ごとに測定しました。 クラウドへ毎回送信すると記録件数と通信回数が増えるため、 この章では30秒ごとに測定・送信します。
送信間隔は、利用台数、研修時間、 Apps Scriptの制限を確認して最終決定します。
JSONをHTTPSで送信する
Section titled “JSONをHTTPSで送信する”response = requests.post( WEB_APP_URL, data=json.dumps(payload), headers=headers,)json.dumps()で辞書をJSON文字列へ変換し、
POSTリクエストの本文として送信します。
Content-Typeにapplication/jsonを指定し、
受信側へJSON形式であることを伝えます。
Apps ScriptのContent Serviceは、 応答を別のURLへリダイレクトします。 使用するHTTPライブラリがHTTPSとリダイレクトへ 対応していることを実機で確認します。
応答を確認して必ず閉じる
Section titled “応答を確認して必ず閉じる”result = response.json()if not result.get("ok"): raise RuntimeError( "Apps Script error={}".format( result.get("error", "unknown") ) )HTTP通信に成功しただけでなく、
Apps Scriptがok: trueを返したことを確認します。
処理が終わったら、finallyでresponse.close()を実行します。
繰り返し通信で応答を閉じないままにすると、
Pico Wの限られたメモリーや通信資源を消費します。
エラーの種類を分ける
Section titled “エラーの種類を分ける”このプログラムでは、次の2つを別に表示します。
| 表示 | 主な原因 |
|---|---|
| センサー読み取りエラー | DHT11の配線、接触、測定タイミング |
| クラウド送信エラー | Wi-Fi、インターネット、URL、トークン、Apps Script |
送信に失敗しても、直前の測定値を 成功したデータとしてスプレッドシートへ追加しません。 30秒後に次の測定と送信を試します。
12-7 記録されたデータを確認する
Section titled “12-7 記録されたデータを確認する”Pico Wからの送信に成功すると、
sensor_logシートへ次のように行が追加されます。
| 記録日時 | 実習機 | 温度(℃) | 湿度(%) | 状態 |
|---|---|---|---|---|
| 2026/07/27 14:30:12 | KIT-01 | 24 | 55 | 通常 |
| 2026/07/27 14:30:42 | KIT-02 | 26 | 61 | 通常 |
| 2026/07/27 14:31:12 | KIT-01 | 28 | 58 | 注意 |
同じシートへ複数台のデータが入るため、
実習機列で自分のKIT_IDを確認します。
記録日時は、Pico Wが測定した厳密な時刻ではなく、 Apps Scriptがデータを受け取った時刻です。 通信の遅延や再送があるシステムでは、 測定時刻と受信時刻を分けて記録する場合があります。
12-8 グラフとスマートフォンで確認する
Section titled “12-8 グラフとスマートフォンで確認する”記録されたデータから、温度の変化を折れ線グラフにします。 実際の画面表記は、検証時点のGoogleスプレッドシートで確認します。
- 実習機列を使って、確認する
KIT_IDへ絞り込みます - 記録日時列と温度列を選択します
- グラフを挿入します
- グラフの種類として折れ線グラフを選択します
- 横軸が記録日時、縦軸が温度になっていることを確認します
湿度についても同じようにグラフを作成できます。 短時間の演習では変化が小さい場合があるため、 表の数値とグラフの両方を確認します。
講師から共有された閲覧用URLをスマートフォンで開き、 記録された表またはグラフを確認します。
スマートフォンでは編集を行わず、 自分の実習機番号と最新の記録時刻を確認します。 共有範囲や端末の状態によっては、 Googleアカウントへのログインが必要になる場合があります。
変更してみる
Section titled “変更してみる”現在の温度がしきい値より低い場合は、
TEMP_WARNINGを現在値より1℃低い値へ一時的に変更します。
TEMP_WARNING = 23次の送信で状態が注意として記録されることを確認します。
確認後は元の28へ戻します。
この確認では、送信間隔、WebアプリURL、 研修用トークンを変更しません。
確認チェック
Section titled “確認チェック”- 第9章と同じDHT11配線を確認した
- Pico Wをインターネットへ接続できた
- 自分の実習機番号を
KIT_IDへ設定した - WebアプリURLが
/execで終わっている - Wi-Fi情報、URL、トークンを公開ファイルへ保存していない
- Shellへ温度、湿度、状態が表示された
- Shellへ
クラウド送信成功と表示された - スプレッドシートへ記録日時と測定値が追加された
- 自分と他の実習機を
KIT_IDで区別できた - 表またはグラフをスマートフォンで確認できた
- センサーエラーとクラウド送信エラーを区別できた
よくある問題と確認方法
Section titled “よくある問題と確認方法”| 状況 | 主な確認箇所 |
|---|---|
requestsとurequestsの両方を読み込めない | MicroPythonの版、パッケージの事前導入、Pico W側へ保存されたライブラリ |
| Wi-Fi接続に失敗する | SSID、パスワード、2.4GHz帯、会場ネットワーク |
HTTP statusが表示される | WebアプリURL、インターネット接続、Google側の応答 |
unauthorizedと表示される | Pico W側とApps Script側の研修用トークン |
invalid kit_idと表示される | KIT-01形式になっているか |
busyと表示される | 同時送信が集中している。次の送信を待ち、講師へ報告 |
sheet not foundと表示される | シート名がSHEET_NAMEと一致しているか |
| 送信成功だが行が見つからない | sensor_logシート、末尾の行、フィルター状態、KIT_ID |
| 同じ実習機の行が増えない | SEND_INTERVAL、プログラムが実行中か、Shellのエラー |
| スマートフォンで開けない | 共有設定、閲覧用URL、ログイン要否、端末の通信状態 |
| 時刻が想定と異なる | スプレッドシートのタイムゾーン、Apps Scriptの受信時刻 |
HTTPS接続やリダイレクトでエラーになる場合は、 URLを短縮したりHTTPへ変更したりせず、講師へ報告します。 使用するMicroPythonとHTTPライブラリの組み合わせを確認します。
12-9 データ活用の流れを確認する
Section titled “12-9 データ活用の流れを確認する”第1章のデータ活用の流れと対応させます。
| 段階 | この章で行うこと |
|---|---|
| 現場の状態 | 周囲の温度と湿度 |
| 取得 | DHT11で測定 |
| 整理 | 実習機番号、温度、湿度、状態をJSONへまとめる |
| 保存 | Apps Scriptを介してスプレッドシートへ追記 |
| 可視化 | 表と折れ線グラフで確認 |
| 判断 | 通常・注意と、時間による変化を確認 |
| 行動 | 状況に応じた確認や対応を検討 |
| 改善 | 測定間隔、判定条件、表示方法を見直す |
データをクラウドへ保存すると、 その場の1回の値だけでなく、 過去から現在までの変化を確認できます。
一方で、記録件数、通信回数、公開範囲、 障害時の扱いを考える必要も生じます。 クラウドへ送れば自動的に安全で便利になるのではなく、 目的に合わせた運用設計が必要です。
- Pico Wは、クラウドへデータを送るWebクライアントとして動作できます
- Apps ScriptのWebアプリが、Pico Wとスプレッドシートを中継します
- 測定値は、実習機番号、温度、湿度、状態を含むJSONとして送信します
- 記録日時はApps Script側で追加するため、Pico Wの時計合わせは不要です
doPost()でJSONを受け取り、appendRow()で1行ずつ追加します- 複数台の同時書き込みは
LockServiceで順番に処理します - Pico Wは30秒ごとに測定・送信し、応答を確認して閉じます
- センサー読み取りエラーとクラウド送信エラーは分けて扱います
- 実習機番号を使うと、共有シート内で複数台のデータを区別できます
- 表とグラフをPCやスマートフォンから確認できます
- URLとトークンによる識別は研修用の簡易構成であり、本格的な認証ではありません
- コード、公開設定、HTTPS、リダイレクト、同時送信は実機検証後に確定します
- Google公式「Web Apps」
- Google公式「Content Service」
- Google公式「Class Sheet」
- Google公式「Class LockService」
- Google公式「Quotas for Google Services」
- MicroPython公式「Package management」
- Raspberry Pi公式「Connecting to the Internet with Raspberry Pi Pico W-series」(PDF)
- ASAIR公式「DHT11製品マニュアル」(PDF)
次の第13章では、スマートフォンからクラウドへ操作指示を送り、 Pico WのLEDへ反映する研修用サービスを扱う予定です。
Googleスプレッドシートへの記録とは分けて、 複数の受講者が同時に参加できる構成を設計・検証します。