0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RON-V #17 — SQLiteからGoogle Sheetsへ非同期同期し、通信障害でも観測を止めない

0
Last updated at Posted at 2026-10-20

[!NOTE]
2026-09-23 現行GitHub同期メモ

現在の google_sync_worker.py は summary / L0 / L1 / L2 / L3_INDEX / L4_INDEX / SYNC を扱います。#17執筆時に将来用だった L3/L4 INDEX も現行実装では同期対象です。Google障害時に観測を止めない「ローカルファースト」の方針は現在も変わっていません。

RON-V 連載リンク
← 前の記事:#16 — Google Sheets・Looker Studioの準備
→ 次の記事:#18 — LTEのL3/L4とGoogle Drive転送

L0〜L4の定義追記(2026-10-25)

本文中のコード・試験結果は執筆当時の記録として残しています。画像AI・音声を関連付ける現在の定義は次のとおりです。

レベル 残す内容
L0 Meshtastic向けの23バイト短報。画像AIの候補通知は任意設定
L1 個別の観測・撮影/録音/認識の状態と、詳細への参照
L2 一定時間の観測件数・分類別候補などの集計
L3 画像AIの詳細、録音情報、文字起こし全文
L4 元画像JPEG、元音声WAV、LTEのraw logなど

L0の警報欄は1バイト=8ビットです。新しいversion=2の定義は、倒木 0x01、冠水 0x02、煙 0x04、道路上の障害物 0x08、路面の穴 0x10。残り3ビットは未割り当てです。0x03は倒木と冠水の組み合わせで、煙の番号ではありません。0x00はL0上では未判定で、安全を示しません。 候補ありでは元イベントの時刻・位置を使い、現在地と混同しません。

発信元はnode_uid、根拠は画像・音声などです。「処理成功」「災害の候補」「人の確認済み」を分けます。初期の確認状態はunreviewed。画像AIの検出0件を「危険なし」とせず、音声の否定も全文へ残します。人が補足・訂正する画面と、音声からの災害自動分類は今後の実装です。

10月25日にL1の関連付け・L2の集計・音声L3/L4の転送処理をコードへ追加しました。新連携の実機確認はこれからです。音声転送とL0候補通知は初期設定では無効で、個別に有効化します。従来のL0 version=1へ、この分類の意味を遡って付けません。

Looker Studioで使用中のSheets summaryはRF測定から直接出力する既存の10列で、L2とは別です。今回の追加で列名・順序・値の意味、既存Grafanaの参照項目は変えません。L1のMesh送信、写真・音声のMesh転送、自動公開は実装していません。

詳細と設定手順:データレベルの定義(リポジトリの閲覧権限が必要です)。

はじめに

RON-Vの観測結果は、最初にRaspberry Pi 5内のSQLiteへ保存します。

Google Sheetsは便利ですが一次保存先ではありません。

設計上の中心は、

Googleへ接続できなくても観測を止めない

ことです。

現在のデータフローは、

RF / LTE / Vehicle / GNSS / Mesh
             ↓
          SQLite
             ↓
   Google Sync Worker
             ↓
       Google Sheets

です。


1. 同期対象

現行 google_sync_worker.py は次の7系統を扱います。

summary
L0
L1
L2
L3_INDEX
L4_INDEX
SYNC

#17初期実装時にはL3/L4は未実装でしたが、現在は #18 のEvidence生成・rclone配送と連携し、INDEXも同期対象です。


2. Google同期Worker

実装は、

app/integration/google_sync_worker.py

です。

基本動作は、

SQLite
 ↓
未同期データを取得
 ↓
Google Sheetsへappend
 ↓
成功
 ↓
cursor / export状態を更新

です。

Google APIで例外が発生した場合、測定側のSQLite保存とは独立しているため、RF/LTE/Vehicle測定には影響しません。


3. 設定

実環境では、

[google]
enabled = true
spreadsheet_id = "<SPREADSHEET_ID>"
credentials_file = "/home/ronv/.config/ronv/secrets/google-service-account.json"

を設定します。

認証JSONやSpreadsheet IDはGitHubへ登録しません。


4. cursorによる差分同期

Google同期では sync_cursors を利用します。

現行の主なcursorは、

google_summary_rf
google_l0
google_l1
google_l2
google_l3
google_l4

です。

たとえばL0では、最後に送った l0_beacons.id を保持し、次回はそれより新しい行だけを取得します。

L1 / L2 / INDEXでは、複数のデータ種別を1本の順序で扱えるよう、sync_objects.rowid をcursorとして利用する箇所があります。


5. summary

summary はLooker Studio向けの平坦な表です。

現行では rf_measurements のうち status='ok' のデータを対象にし、

band
timestamp
lat_lon
peak_count
burst_count
max_power
field_activity_index

などを書き出します。

CAN系の列もWorksheet側に用意していますが、未取得項目は空欄として扱います。


6. L0

L0では、

object_uid
packet_hex
created_at_jst

をGoogleへ出します。

Google側の重複確認キーは object_uid です。


7. L1

L1は sync_objects の、

level = 1

を対象にします。

現在は代表的に、

Vehicle Fact
LTE Fact
RF Fact

を扱います。

Googleへは、

object_uid
event_time_jst
data_type
source_table
source_id
priority
payload_json
created_at_jst

を出します。


8. L2

L2は level = 2 のCycle Summaryです。

現在のL2には、

Vehicle
LTE
RF
Mesh
latest L0
service state

などの時間窓情報が含まれます。

Google Sheetsの change_summary 列には構造化payloadを保存し、AI文章要約はまだ別機能として実装していません。


9. L3_INDEX / L4_INDEX

L3/L4のファイル本体はGoogle Sheetsには入れません。

L3 JSON
L4 raw log / JPEG

はローカルEvidenceとして生成し、rcloneでGoogle Driveへ配送します。

Google Sheetsには、

object_uid
level
event_time_jst
data_type
source_table
source_id
file_path
mime_type
bytes
sha256
upload_transport
upload_state
remote_id

などのINDEXだけを出します。

これにより、

Sheets = 検索・索引
Drive  = Evidence本体

という役割分担になります。


10. SYNC

SYNC は配送状態をGoogle側から確認するためのシートです。

元データは主に sync_deliveries です。

pending
retry
inflight
sent
acked
held
failed
cancelled

などの配送状態を扱えます。

Meshtasticでは、

packet_id
ack_type
ack_from
ack_error

も保持します。

rclone配送では、

remote_id
bytes
sha256
latency
status

などを追跡できます。


11. 重複防止

Google APIでは、

append成功
 ↓
Pi電源断
 ↓
cursor更新前

というケースを考慮する必要があります。

そのため現行workerでは、単にcursorだけに依存せず、Google側の最近のキーを確認して同一キーを再appendしない処理があります。

また、INDEX / SYNCの送信済み管理には、

google_sync_exports

を利用します。

概念的には、

(stream, source_id)

を主キーにし、同じ対象を二重にexportしない構造です。


12. dry-run

送信前にはdry-runできます。

cd /home/ronv/ronv

/home/ronv/.venvs/ronv/bin/python \
  -m app.integration.google_sync_worker \
  --batch-size 20 \
  --dry-run

SQLiteから何件取得されるかを確認してから、実送信へ進められます。


13. systemd化

Google同期は観測serviceから直接呼びません。

現行serviceは、

[Unit]
Description=RON-V Google Sheets Sync
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=ronv
Group=ronv
WorkingDirectory=/home/ronv/ronv
Environment=PYTHONUNBUFFERED=1
Environment=RONV_CONFIG=/home/ronv/ronv/config/ronv.toml
ExecStart=/home/ronv/.venvs/ronv/bin/python -m app.integration.google_sync_worker --batch-size 200
TimeoutStartSec=90
Nice=10

timerは、

[Timer]
OnBootSec=2min
OnUnitInactiveSec=5min
AccuracySec=5s
Unit=ronv-google-sync.service

です。

5分ごとに独立して同期します。


14. 通信障害時

Googleが使えない場合でも、

Google NG
  ↓
Google Sync失敗
  ↓
SQLiteは保持
  ↓
RF / LTE / Vehicle観測継続

となります。

通信復旧後にworkerが再度起動すると、残っている対象を順番に処理します。

これはRON-Vの重要な設計条件です。


15. 現在の動作確認

状態確認は、

systemctl status \
  ronv-google-sync.timer \
  --no-pager

journalctl \
  -u ronv-google-sync.service \
  -n 100 \
  --no-pager

で行います。

Google側の構造確認は、

/home/ronv/.venvs/ronv/bin/python \
  -m app.integration.google_sheet_check

を使用します。


まとめ

RON-VのGoogle同期は、

測定
 ↓
SQLite
 ↓
非同期Worker
 ↓
Google Sheets

です。

Googleは一次保存先ではありません。

現在は、

summary
L0
L1
L2
L3_INDEX
L4_INDEX
SYNC

まで同期対象となっています。

次の #18 では、L3/L4 Evidence本体を作り、rcloneでGoogle Driveへ非同期配送する仕組みを扱います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?