これまで下記の記事などで、Arduino UNO Qでセンサ値をブラウザに表示する構成について調査してきた。それらの構成では、Web UIのBrickを利用していた例を紹介していたが、本記事では、Web UIのBrickを利用しない構成も検討し、さまざまな拡張を行う上でどちらが有利かを検討した。
また、現場での実使用に耐えるための追加機能を検討し、それらの追加機能を実現するための変更内容をそれぞれの構成で検討したので紹介する。
さらに、Bricksのバージョンアップにより将来問題が発生する可能性について調べた。

(注)本記事の内容は正確性を保証するものではない。
(2026年1月12日 追記)YouTube動画を追加しました。 https://youtu.be/J-je9bKyGOo

Web UIのBrickを利用する場合と利用しない場合の最小雛形の比較
Arduino UNO QのApp Labで、センサ値をリアルタイムにブラウザに表示させるアプリのプログラム構成を検討したいと思います。下記の2つの構成の最小雛形を作成して比較してください。
1.App LabのWeb UI Blickを利用する構成
2.WEb UI Blickを使わずに、一般的な外部ライブラリを使った構成
ChatGPT 5.2 Thinkingの回答
以下は 「UNO Q(MCU)→Python(MPU)→ブラウザ」 でセンサ値を“リアルタイム表示”するための 最小雛形(2構成) です。
(※UNO Q の App Lab は app.yaml が Python エントリポイントや Bricks を束ねる“マニフェスト”です。
(Shawn Hymel))
1) Web UI Brick(WebUI – HTML)を使う最小雛形(push / socket.io)
フォルダ構成(最小)
my_app/
app.yaml
python/
main.py
sketch/
sketch.ino
assets/
index.html
app.js
libs/
socket.io.min.js ← 例の構成に合わせて置く(後述)
app.yaml(Brick を有効化)
name: Sensor WebUI (Brick)
description: Minimal realtime sensor UI using WebUI brick
ports: []
bricks:
- arduino:web_ui: {}
WebUI Brick は UNO Q の ポート 7000 で UI を提供する前提の例が多いです。 (docs.edgeimpulse.com)
sketch/sketch.ino(MCU:ダミー値を notify)
#include <Arduino_RouterBridge.h>
void setup() {
Bridge.begin();
}
void loop() {
// 例:センサ値の代わりにダミーで増加させる
static float v = 20.0;
v += 0.1;
// Python 側の "on_value" を呼ぶ(非同期通知)
Bridge.notify("on_value", v);
delay(200); // 5Hz 更新(適宜)
}
Bridge.notify(...) で Python 側へイベント通知する流れは、UNO Q の Bridge の基本形です。 (Arduino Forum)
python/main.py(Python:notify受信 → send_messageでUIへpush)
from arduino.app_utils import App, Bridge
from arduino.app_bricks.web_ui import WebUI
import time
ui = WebUI()
def on_value(v: float):
ui.send_message("sensor", {
"value": float(v),
"ts": int(time.time() * 1000)
})
Bridge.provide("on_value", on_value)
App.run()
WebUI() を作り send_message(...) でブラウザへ push し、Bridge.provide(...) で MCU からの notify を受けます。
assets/index.html(ブラウザ:socket.io を読む)
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>UNO Q Sensor (WebUI Brick)</title>
</head>
<body>
<h1>Sensor</h1>
<p>Value: <strong><span id="v">--</span></strong></p>
<p><small id="ts">--</small></p>
<!-- 例の構成:assets/libs/socket.io.min.js -->
<script src="libs/socket.io.min.js"></script>
<script src="app.js"></script>
</body>
</html>
assets/app.js(ブラウザ:push受信してDOM更新)
const socket = io(`http://${window.location.host}`);
const vEl = document.getElementById("v");
const tsEl = document.getElementById("ts");
// Python: ui.send_message("sensor", {...}) を受信
socket.on("sensor", (data) => {
vEl.textContent = data.value.toFixed(2);
tsEl.textContent = new Date(data.ts).toLocaleString();
});
この「socket.io でイベント名(ここでは “sensor”)を購読して更新」という形が WebUI Brick 側の最小パターンです。
socket.io.min.jsは WebUI Brick のサンプル由来でassets/libs/に置く前提の例があります。
(同様の読み方が使われています)
もし手元の雛形に無い場合は、App Lab の WebUI サンプルからassets/libs/をコピーしてくるのが手堅いです。
起動・アクセス
- App Lab で Deploy → ブラウザで
http://<UNO Q のIPアドレス>:7000/
(WebUI Brick の UI アクセスは 7000 を案内する資料が複数あります。 (docs.edgeimpulse.com))
2) Web UI Brick を使わず、一般的ライブラリ(Flask + ポーリング)で作る最小雛形
“リアルタイム”を 最小実装で成立させるため、まずは ポーリングにしています。
(WebSocket化は次段で拡張しやすいです)。
フォルダ構成(最小)
my_app/
app.yaml
python/
main.py
sketch/
sketch.ino
assets/
index.html
app.js
app.yaml(Brickなし、外部サーバ用にポート公開)
name: Sensor Web (No Brick)
description: Minimal realtime sensor UI without WebUI brick (Flask polling)
ports: [8000]
bricks: []
ports: は Edge Impulse の App Lab 例でも app.yaml に存在し、アプリ側が使うポート情報として扱われています。 (docs.edgeimpulse.com)
sketch/sketch.ino(MCU:1)と同じでOK)
#include <Arduino_RouterBridge.h>
void setup() {
Bridge.begin();
}
void loop() {
static float v = 20.0;
v += 0.1;
Bridge.notify("on_value", v);
delay(200);
}
python/main.py(Flaskを別スレッドで起動、Bridgeは App.run())
from arduino.app_utils import App, Bridge
import time, threading
# --- 受信した最新値を保持 ---
latest = {"value": None, "ts": None}
def on_value(v: float):
latest["value"] = float(v)
latest["ts"] = int(time.time() * 1000)
Bridge.provide("on_value", on_value)
# --- Webサーバ(Flask) ---
from flask import Flask, jsonify
web = Flask(__name__, static_folder="assets", static_url_path="")
@web.get("/")
def index():
return web.send_static_file("index.html")
@web.get("/api/value")
def api_value():
return jsonify(latest)
def run_web():
web.run(host="0.0.0.0", port=8000, debug=False, use_reloader=False)
threading.Thread(target=run_web, daemon=True).start()
# Bridge のイベントループを回す
App.run()
assets/index.html(ポーリングで表示)
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>UNO Q Sensor (No Brick)</title>
</head>
<body>
<h1>Sensor</h1>
<p>Value: <strong><span id="v">--</span></strong></p>
<p><small id="ts">--</small></p>
<script src="app.js"></script>
</body>
</html>
assets/app.js(200msごとに /api/value を取得)
const vEl = document.getElementById("v");
const tsEl = document.getElementById("ts");
async function tick() {
const res = await fetch("/api/value");
const j = await res.json();
if (j.value == null) return;
vEl.textContent = Number(j.value).toFixed(2);
tsEl.textContent = new Date(j.ts).toLocaleString();
}
setInterval(tick, 200);
tick();
起動・アクセス
- Deploy →
http://<UNO Q のIPアドレス>:8000/
2構成の“最小雛形”としての比較(まず押さえる差分)
| 観点 | 1) Web UI Brick | 2) 非Brick(Flask例) |
|---|---|---|
| ブラウザ更新 | push(socket.io)で即時反映 | pull(ポーリング)で準リアルタイム |
| Python側 | WebUI() + send_message() が中心 | Flaskで GET /api/value を自前実装 |
| app.yaml | arduino:web_ui を宣言 (docs.edgeimpulse.com) | ports:[8000] 等を自前で管理 (docs.edgeimpulse.com) |
| フロント資産 | socket.io.min.js 等の前提が出がち | 素のJSだけでも成立 |
| UNO Q との連携 | どちらも Bridge.notify → Bridge.provide が基本 (Arduino Forum) | 同左 |
次の質問(拡張性)では、たとえば
- 複数センサ / 履歴保存 / グラフ化
- 通信方式(push/pull混在、WebSocket化、SSE化)
- エラー時の再接続、レート制限、バックオフ
- UI を複数画面に分割、API設計
あたりを「どちらの構成が伸ばしやすいか」で具体比較できます。
拡張性比較
下記の各観点で、2つの構成の拡張性を評価してください
・複数センサ / 履歴保存 / グラフ化
・通信方式(push/pull混在、WebSocket化、SSE化)
・エラー時の再接続、レート制限、バックオフ
・UI を複数画面に分割、API設計
ChatGPT 5.2 Thinkingの回答
了解です。4観点ごとに「WebUI Brick構成」と「非Brick(外部ライブラリ)構成」の拡張手筋・難所・おすすめ方針を並べ、どちらが有利か結論も添えます。必要なら最新の公式ドキュメントも確認します。
以下、4観点ごとに (1) Web UI Brick 利用 と (2) 非Brick(Flask/FastAPI等の一般ライブラリ) の拡張性を評価します。
前提として UNO Q は MCU↔Python を Bridge(非同期RPC)で中継し、Router が MessagePack RPC のルータとして動く構造です。 (GitHub)
1) 複数センサ / 履歴保存 / グラフ化
Web UI Brick 構成(拡張しやすい)
- 複数センサ:センサごとに ui.send_message(“<channel>”, {…}) を増やすだけで push チャンネルを増やせます(Weather Station 例では温度/湿度/気圧/照度…をそれぞれ push)。 (Arduino Project Hub)
- 履歴保存:Brick 側に TimeSeriesStore のような保存機構が用意されており、実例でも db.write_sample(…) で複数系列を保存しています。 (Arduino Project Hub)
- グラフ化:フロントは assets のJSで Chart.js 等を使って描画し、
- 直近は send_message(push)
- 過去は
expose_apiでGET /get_samples/...(pull)
の二段構えにすると綺麗に分離できます(実例あり)。 (Arduino Project Hub)
評価:複数センサ〜履歴〜グラフまで、Brickの“定番ルート”が揃っていて伸ばしやすい。
非Brick 構成(自由度は高いが設計が必要)
- 複数センサ:データモデル(辞書/クラス/スキーマ)を自前設計。拡張はできますが最初に整備が必要。
- 履歴保存:SQLite/CSV/Parquet/TimescaleDB など何でも選べる反面、
- 書き込み頻度
- ローテーション(保持期間)
- 集計(downsample)
を自分で決めます。
- グラフ化:UI/取得APIとも自由。将来 SPA や別クライアント(スマホアプリ等)へ出すなら強い。
評価:長期的な自由度は最大。ただし「履歴の保存・集計・取得」を自前で作る分、最小構成からの拡張コストは高め。
2) 通信方式(push/pull混在、WebSocket化、SSE化)
Web UI Brick 構成
- push:ui.send_message(…) がそのまま push になります(実例あり)。 (Arduino Project Hub)
- pull:ui.expose_api(“GET”, “/get_samples/{…}”, …) の形でHTTP APIを生やせます(実例あり)。 (Arduino Project Hub)
- push/pull混在:上の2つで自然に混在可能(リアルタイム=push、履歴=pull が王道)。
- WebSocketを別系統で増やす:他Brick(例:Streamlit)等と併用すると デフォルトポート 7000 の競合が起きうるため、ポート設計が必要です(WebUIを7001にずらす等の実例)。 (Arduino Forum)
- SSE化:Brickの範囲で“SSEを第一級機能として使う”より、必要なら 別サーバ(FastAPI等)を追加してSSE/WebSocketを持たせる方が現実的。
評価:push/pullの混在は強い。プロトコルを“好き放題”増やす用途は、追加サーバ前提になりやすい。
質問:「SSE化」とは?
ChatGPT 5.2 Thinkingの回答:
「SSE化」は、ここでは ブラウザへのリアルタイム更新(push)を “SSE(Server-Sent Events)方式に置き換える/追加する” という意味で使っています。
HTTP接続を1本張りっぱなしにして、サーバ→ブラウザへ一方向にイベントを流し続ける仕組みです。
・ブラウザ側は標準APIの EventSource で受け取る
・サーバ側は Content-Type: text/event-stream で、改行区切りのイベントを送る
・特徴:自動再接続(ブラウザが基本やってくれる)、実装が比較的シンプル
イメージは「WebSocketより軽めの“通知専用ストリーム”」です。
非Brick 構成
- 通信方式の選択が自由:
- WebSocket(FastAPI/Starlette 等)
- SSE
- ロングポーリング
- MQTT/ZeroMQ など
目的に合わせて最適化可能。
- 複数クライアント(ブラウザ以外も含む)を早期から想定するなら、API/プロトコルを統一しやすい。
評価:通信方式の拡張性は圧倒的にこちらが上。
3) エラー時の再接続、レート制限、バックオフ
Web UI Brick 構成
- Bridge側の落とし穴(重要):Bridgeは非同期で、Pythonが ready になる前に MCU が notify すると取りこぼすことがあるため、loop() 側に寄せる/開始時に待つ等の対策が必要です。 (Arduino Forum)
- レート制限:Pythonで簡単に実装できます
(Weather Station 実例では更新間隔を見て一定時間未満なら return して間引き)。 (Arduino Project Hub) - バックオフ/再接続:
- ブラウザ側(JS)で「切断→待つ→再接続」「失敗時はポーリングにフォールバック」などの戦略を組むのが現実的。
- Brickの枠内だけで“万能のリトライ基盤”が用意されている、とは限らないので、方針をUI側に置くのがおすすめ。
評価:センサ→Pythonの安定化(取りこぼし防止)と、UI側のフォールバック設計が鍵。レート制限はやりやすい。
非Brick 構成
- 再接続/バックオフ:採用するフレームワーク・クライアント次第で、ミドルウェア/共通部品として整備しやすい。
(例:HTTPクライアント再試行、指数バックオフ、サーキットブレーカなど)。 - レート制限:APIゲート(middleware)で統一的に掛けやすい(トークンバケット等)。
評価:運用を見据えた堅牢化(再試行・バックオフ・制限)を“体系的に”作るならこちらが上。
4) UI を複数画面に分割、API設計
Web UI Brick 構成
- 複数画面:assets に複数HTMLを置く/SPA化するのは可能(静的フロントとしては普通に拡張できる)。
- API設計:ui.expose_api() で REST 風の取得APIを生やせます。
実例では パスパラメータ付きでGET /get_samples/{resource}/{start}/{aggr_window}を公開しています。 (Arduino Project Hub) - 設計の癖:UI配信(7000)+API(expose_api)+push(send_message)を同一Brickに寄せると速い反面、肥大化したときに責務分割を意識しないと“全部main.py”になりがち。
評価:小〜中規模のダッシュボードなら十分に伸びる。APIを体系化(バージョニング、OpenAPI、認証など)する段階で限界が見えやすい。
非Brick 構成
- 複数画面/SPA:React/Vue 等を含めて自由。ビルド成果物を配る構成や、別ポート/別ホストも選べる。
- API設計:FastAPIなら OpenAPI 自動生成、依存注入、認証、バージョニング等が最初から作りやすい。
評価:UI分割・APIの長期運用(仕様固定、互換維持)まで考えるならこちらが強い。
まとめ(観点別の結論)
- 複数センサ/履歴/グラフ:Web UI Brick が有利(TimeSeriesStore+send_message+expose_api の実例が揃っている)。 (Arduino Project Hub)
- 通信方式の自由度(SSE/独自WS等):非Brick が有利。
- 堅牢化(再接続・制限・バックオフを体系化):非Brick が有利。ただし Brick でも間引き等は簡単。
(Arduino Project Hub) - UI分割・API設計の拡張:小〜中規模は Brick で十分、長期のAPI運用は非Brickが有利。 (Arduino Project Hub)
必要なら、あなたの想定(例:センサ数、更新周期、保存期間、表示はPCだけか/スマホもか)に合わせて、どちらで行くべきか「推奨アーキテクチャ(ディレクトリ分割案+責務分離)」まで落として提案します。
通信方式を変えたり、堅牢性を高めたりする必要がなければ、Web UI Brick で十分対応できることが確認できた。
通信方式には、WebSocket(FastAPI/Starlette 等)、SSE、ロングポーリング、MQTT/ZeroMQ などがあることが分かり、拡張する際、どのような通信方式を調査すべきかの手がかりが得られた。
最小雛形からの拡張の方向性のヒントが得られた。
現場での実使用に耐えるための機能を容易に追加できるかの比較
2つの構成の拡張性について検討してもらいましたが、今度は、現場での実使用に耐えるために必要な機能にはどのようなものがあるかを検討し、それぞれの構成でそれらを実現するための変更内容を検討・比較してください
ChatGPT 5.2 Thinkingの回答
以下は「現場で実使用に耐える」ために、最低限そろえておきたい機能を洗い出し、(1) Web UI Brick 構成 と (2) 非Brick(一般Webフレームワーク)構成 で“何をどう変更するか”を比較したものです。
※UNO Q の Bridge は非同期で Router が仲介するため、取りこぼし・再起動・接続断を前提に設計するのが重要です。 (Arduino Forum)
まず必要になる機能セット(現場向けチェックリスト)
A. 信頼性(落ちない/取りこぼさない)
- サンプル取りこぼし対策(Pythonがready前にMCUがnotifyして落ちる/消える)
- バッファリング(瞬断・処理遅延でもデータを捨てない)
- 時刻の扱い(MCU側タイムスタンプ or MPU側付与、時刻ズレ検出)
- ヘルスチェック(最終更新時刻、センサ断線/異常値、CPU負荷など最低限)
B. データ管理(後で使える形に残す)
- 履歴保存(永続化、ローテーション、保存粒度の間引き)
- エクスポート(CSV/JSON、指定期間でダウンロード)
- スキーマ拡張(センサ追加しても壊れない)
C. 通信とUX(現場で“見える/復旧する”)
- 再接続(ブラウザ側、Python側)
- push/pull併用(最新値はpush、履歴はpullが現場で強い)
- 状態表示(オフライン、遅延、欠測、警告)
D. 運用(原因が追える/設定を変えられる)
- ログ(イベント・エラー・通信断・センサ異常)
- レート制限/バックオフ(外部API連携や高頻度更新時)
- 設定管理(サンプリング周期、しきい値、保存期間をUIから変更)
E. セキュリティ(LANでも最低限)
- 認証(最低でも簡易トークン)
- API保護(入力検証、CORS、過負荷対策)
構成ごとの変更内容比較(やることが具体的に分かる形)
下は「機能 → 変更点(Brick / 非Brick)」の形で並べます。
1) 取りこぼし対策・バッファリング・時刻
必要機能
- Pythonが落ちたり再起動しても、MCUが一定量保持して再送できる
- データに 連番(seq) + ts を付けて欠測検出
(1) Web UI Brick 構成:変更内容
- MCU側:リングバッファ(例:直近N件)+ seq 付与
- Python側:
Bridge.provide("on_value", ...)受信時にseqの欠番を検出して「欠測」フラグをUIへ送る- 永続化(後述)
- 起動同期:
- MCUが起動直後に一定時間待つ、または
- Pythonが ready になったら MCU に「ready」コール(ハンドシェイク)
Bridge が非同期で Router が仲介する前提なので、ここを入れると事故が激減します。 (Arduino Forum)
(2) 非Brick 構成:変更内容
- 基本は同じ(リングバッファ+seq+欠測検出)
- さらに余裕があれば、MPU側で 受信キュー(asyncio Queue / deque) を置いて、
- 受信処理(Bridge)
- 保存処理(DB)
- 配信処理(Web)
を分離し、ピーク負荷でも取りこぼしにくくします。
比較:どちらでも実装必須。非Brickの方が“並列化・負荷分散の作り込み”はやりやすい。
2) 履歴保存・ローテーション・エクスポート
必要機能
- 「現場で起きたこと」を後から追えるよう 最低でも数日〜数週間の履歴
- データ量が増えるので 間引き(downsample) と 保存上限 が必要
(1) Web UI Brick 構成:変更内容
- TimeSeriesStore を導入してセンサごとに write_sample()(実例あり)。 (Arduino Project Hub)
- 履歴取得は ui.expose_api() で期間・集計窓を受ける
(実例の/get_samples/{resource}/{start}/{aggr_window}がそのまま使える)。 (Arduino Project Hub) - エクスポート用に
expose_api("GET", "/export?...")を追加(CSV/JSON) - ローテーションは
- 保存期間で削除(定期処理)
- もしくは “高頻度は短期、集計値は長期” の二層保存
を追加(TimeSeriesStoreの読み書きパターンを踏襲)
(2) 非Brick 構成:変更内容
- DB選定(例:SQLiteで開始→必要なら時系列DBへ)
- APIとして
GET /samples?metric=&from=&to=&agg=GET /export?...
を定義し、UIはここだけ叩く
- ローテーション・圧縮・バックアップを実装(cron相当の定期タスク)
比較:最短で“履歴+集計+API”まで行くなら Brick が速い(実例が揃っている)。 (Arduino Project Hub)
長期運用でDBを差し替えたり、分析基盤へ送るなら非Brickが強い。
3) 通信(push/pull併用・再接続・フォールバック)
必要機能
- ブラウザが再読み込みしても 自動復帰
- pushが切れたら pullにフォールバック(現場で強い)
(1) Web UI Brick 構成:変更内容
- push:ui.send_message(“sensor”, payload) を継続(実例はSocket.IOで受信)。 (Arduino Project Hub)
- pull:ui.expose_api() で最新値 /api/latest と履歴 /get_samples/… を提供(実例あり)。
(Arduino Project Hub) - フロント(assets/app.js):
- socket切断検知 → 再接続(待ち時間を増やす指数バックオフ)
- 一定時間pushが来なければ /api/latest をポーリング
- 「最終更新時刻」「遅延ms」「欠測」表示
(2) 非Brick 構成:変更内容
- FastAPI/Starlette等で
- WebSocket(push)
- SSE(push寄り)
- REST(pull)
を正式サポート
- クライアントは状態機械(connected / degraded / offline)を持たせ、通信方式を切替
比較:通信方式の拡張は非Brickが圧勝。
ただし“push+pullの王道”だけなら Brick でも十分組めます(実例あり)。 (Arduino Project Hub)
4) エラー処理(レート制限・バックオフ・過負荷)
必要機能
- 高頻度サンプルでUIが重くならない
- 外部API連携が入ると、429/一時障害が必ず起きる
(1) Web UI Brick 構成:変更内容
- Python側で間引き:更新間隔を見て return(実例でも
last_update_timeで制御)。 (Arduino Project Hub) - キュー溢れ対策:
- UI送信は最新値だけ残す(古い値は捨てる)
- 履歴保存は別スレッド/別タスクに分離(保存遅延でUIが止まらない)
- API側の簡易レート制限:expose_apiハンドラ内でIP単位に頻度制限
(2) 非Brick 構成:変更内容
- ミドルウェアでレート制限・認証・エラーハンドリングを一括
- 外部APIクライアントに標準のリトライ(指数バックオフ、サーキットブレーカ)を導入
- 監視用にメトリクス(リクエスト数/遅延/エラー率)を追加しやすい
比較:現場運用の“守り”を体系的に作るなら非Brickが有利。Brickは「必要最小限を手早く」向き。
5) UI分割・API設計・設定変更(現場で必ず欲しくなる)
必要機能
- 画面:ダッシュボード / 履歴 / 設定 / アラートログ
- 設定:サンプル周期、しきい値、保存期間、校正値
(1) Web UI Brick 構成:変更内容
- assets を
index.html(ダッシュボード)history.html(履歴・グラフ)settings.html(設定)
に分割(またはSPA化)
- APIは
ui.expose_api()でGET /configPOST /configGET /alerts
を追加(実例の expose_api パターンを踏襲) (Arduino Project Hub)
- 設定はファイル(JSON/YAML)に保存し、起動時ロード
(2) 非Brick 構成:変更内容
- APIを最初から整理(例)
GET /v1/latestGET /v1/samplesPOST /v1/configGET /v1/health
- OpenAPI(自動ドキュメント)、認証、スキーマ(Pydantic等)で破壊的変更を防ぐ
- UIはSPA(React等)を別ビルドでも可
比較:小〜中規模のUI分割はBrickで十分。APIを長期保守するなら非Brickの方が設計が楽。
結論:現場向けにする時の“おすすめ改造方針”
- 最短で実用(履歴・グラフ・push/pull・簡易APIまで):
→ Web UI Brick を軸に、- seq+欠測表示
- TimeSeriesStore+履歴API
- 再接続+フォールバック
を足すのが最速です。 (Arduino Project Hub)
- 長期運用・多端末・堅牢化・セキュリティ重視:
→ 非Brick で FastAPI 等に寄せ、WebSocket/SSE/REST、認証、レート制限、監視を“正規のWebアプリ”として整備するのが強い。
もし「現場」の前提(例:センサ数、更新周期、保存期間、同時閲覧人数、ネットワークが不安定か、外部API連携の有無)が分かれば、上の機能を Must/Should/Nice に優先度付けして、両構成それぞれの具体的なファイル差分(どのファイルに何を追加するか)まで落として提示します。
現場での実使用に耐えるためにどのような点を強化すれば良いか、どのような機能を追加すれば良いかの手がかりが得られた。これにより、機能追加の方法をAIに質問する際、その専門用語を知っているので、より的確な指示ができ、効率化が図れる。
先の回答では、pull(ポーリング)でのブラウザ構成の例が示されたので、2) 非Brick(Flask例)でpushの更新を行う構成との比較を指示した。
Brick利用構成と非Brick(Flask例)でpushの更新を行う構成との比較
2) 非Brick(Flask例)でpushの更新を行う構成を検討し、1) Web UI Brick(WebUI – HTML)の構成と比較してください。
ChatGPT 5.2 Thinkingの回答
了解です。非Brick側を「WebSocket(またはSSE)でpush配信」する最小構成に組み替え、WebUI Brick側(send_message/socket.io)と同じ観点で違い・利点欠点・実装変更点を並べます。
必要なら最新のUNO QのBrick仕様も確認します。
以下では、2) 非Brick(Flask例)でも“push更新”を実現する構成を、SSE(EventSource)方式を軸にまとめ、1) Web UI Brick(WebUI – HTML)(=WebUI Brickが用意する WebSocket 相当の仕組み)と比較します。
※UNO Q の Bridge は非同期で、Python側が ready になる前に MCU が送ると取りこぼすことがあるので、どちらの構成でも「送信タイミング(setupで送らない/遅延させる)」は必須の作法です。 (Arduino Forum)
まず前提:Web UI Brick 側の “push” は何か
Edge Impulse の App Lab 解説でも、WebUI – HTML は Webアプリをホストし、API や WebSockets を公開できる、とされています(UIは ポート7000 で開く案内)。 (docs.edgeimpulse.com)
つまり WebUI Brick 構成は「Brickが Webサーバ+push配信の土台を持っていて、Pythonは send_message で流す」寄りの設計です。
2) 非Brick(Flask例)で push 更新する:おすすめ最小案は SSE
WebSocket を Flask でやる場合は Flask-SocketIO 等の追加依存(eventlet/gevent等)が絡みやすいので、“追加ライブラリ最小”で push を成立させるなら SSE が堅いです。
構成(SSE)
- Python(Flask)
/静的配信(index.html)/events…text/event-streamでサーバ→ブラウザへ push/api/latest… つながった直後の初期表示やフォールバック用
- MCU→Python は従来通り
Bridge.notify→Bridge.provide
変更点(app.yaml)
- WebUI Brick を外し、Flask用ポートを公開(例:8000)
ports: [8000]bricks: []
変更点(python/main.py:要点だけ)
latest(最新値)を保持- “接続中のブラウザ”ごとにキューを作り、Bridgeで受けた値を全員に配信
(thread-safe なqueue.Queue+Lockがシンプル)
変更点(assets/app.js)
EventSource("/events")で受信してDOM更新- 切断時はブラウザが自動再接続(SSEの標準挙動)。必要なら自前で待ち時間制御も可能。
もし WebSocket が必須なら(非Brick・Flaskでの現実的な選択肢)
- Flask-SocketIO を使う
- ただし環境により
eventlet/geventなどが必要になりがちで、UNO Q の App Lab 実行環境でそのまま通るかは事前確認が必要です(依存導入が前提になる可能性)。
- ただし環境により
- 依存を抑えたいなら、Flaskにこだわらず FastAPI/Starlette に寄せたほうが WebSocket は素直です(ただ、今回は「Flask例」なので詳細は割愛します)。
1) Web UI Brick(WebUI – HTML) vs 2) 非Brick(Flask+SSE push)の比較
① 実装の手間・壊れにくさ
- Web UI Brick
- Webホスト+pushの土台が既にある(Pythonはメッセージを流す側に寄る)
- 「UIを7000で開く」「WebUIがWebSockets/APIを提供」などの定番導線がある (docs.edgeimpulse.com)
- 非Brick(Flask+SSE)
- 接続管理(クライアント一覧、キュー、切断掃除)を自前実装
- ただしSSEはブラウザ標準で扱いやすく、追加JSライブラリも不要
結論:最短で安定稼働に寄せるなら WebUI Brick が有利。SSEは“依存少なくpushしたい”場合に強い。
② “push”の性質(遅延・双方向・フォールバック)
- Web UI Brick
- push(WebSocket系)で低遅延・双方向も作りやすい
- さらに履歴は API(expose_api)で pull、という二段構えがやりやすい(Brick思想) (docs.edgeimpulse.com)
- 非Brick(Flask+SSE)
- 基本は片方向(サーバ→ブラウザ)
- ブラウザ→サーバの操作は REST(POST)で補うのが王道
- 切断時の再接続はSSE標準である程度自動
結論:双方向が濃い(UIからMCUを頻繁に操作する)なら WebUI Brick/WS が楽。表示中心ならSSEで十分強い。
③ App Lab / UNO Q 特有の注意点(どちらにも共通)
- Bridge は非同期で、Pythonが ready になる前の notify が落ちることがある
→setup()で送らずloop()に移す/開始時に遅延・ハンドシェイクを入れるのが推奨 (Arduino Forum) - Router は MsgPack RPC のルータとして振る舞う(複数クライアントを中継) (GitHub)
→ “取りこぼし対策(seq/欠測検出/バッファ)”は構成に関係なく効きます。
④ 拡張(認証、レート制限、監視、プロトコル追加)
- Web UI Brick
- “Brick流”の範囲は速いが、枠外(独自Auth方式、複雑なレート制限、別プロトコル併用)をやり始めると追加実装が必要になりがち
- 非Brick(Flask+SSE)
- ふつうのWebアプリとして、Auth/RateLimit/監視/ログ整備を設計しやすい
- ただし最初から作り込み量は増える
どっちを選ぶべきか(判断の目安)
- WebUI Brick を選ぶ:
- 「UNO Q/App Lab の作法に乗って最短で動かす」
- 「WebSockets/双方向UIも視野」 (docs.edgeimpulse.com)
- 非Brick(Flask+SSE push)を選ぶ:
- 「追加依存を増やさず push したい」
- 「Web標準(EventSource)でシンプルに運用したい」
- 「将来、認証やAPI設計を“普通のWebアプリ”として固めたい」
Bricksのバージョンアップについて
Beicksの将来のバージョンアップについての情報を探してください。今まで動作していたBrickが、そのBrickで使われているモジュールのバージョンアップによって動かなくなるというような可能性があるかを知りたいと思います
ChatGPT 5.2 Thinkingの回答
了解です。Edge Impulse App Lab/Arduino UNO QのBricksについて、公式ドキュメントやリリースノート、互換性ポリシー(破壊的変更の扱い)をWebで確認し、動かなくなるリスクと対策を整理します。
調べた範囲の結論から言うと、「将来のアップデートで、いま動いているBrick(またはBrickが依存する環境)が動かなくなる可能性」は現実にあります。
ただし、対策(“壊れにくい作り方”と“更新を前提にした運用”)でかなり抑えられます。
分かったこと(公式・一次情報ベース)
1) App Lab は定期的に更新され、更新チェックは(現状)必須
Arduinoのサポート記事では、App Lab は定期的に更新され、ボード接続時や単体起動時に更新チェックが必要で、スキップ機能は将来リリースで予定と書かれています。さらに、更新は PC側のApp Lab と ボード側のソフト(UNO Q上のApp Lab環境) の両方に影響します。(Arduinoヘルプセンター)
→ つまり「気づいたら基盤側の実行環境が更新されていた」が起こり得ます。
2) Brick は “Pythonコード + (必要なら)Dockerサービス” で構成され、コンテナはバージョンを持つ
Arduino公式の Brick 実装リポジトリ(app-bricks-py)の README によると、Bricks は再利用可能なモジュールで、必要に応じて Docker Compose でインフラ(サービス)を起動する設計です。
さらに brick_compose.yaml で参照する イメージのバージョンを APPSLAB_VERSION で上書きできる、と明記されています。(GitHub)
また、リリースはタグ(例:release/x.y.z)で行い、コンテナとPythonライブラリ(wheel)がリリースされること、そして重要なのが、“ベースイメージはライブラリとは別頻度で更新される”と明記されています。(GitHub)
→ 「Brick本体を変えていなくても、下のベースイメージ更新で挙動が変わる」余地があります。
3) UNO Q の App 管理側(arduino-app-cli)も “他コンポーネントを自動更新” すると明記
UNO Q上でAppsを管理する arduino-app-cli は 自分自身と他のコンポーネントを自動更新すると README に書かれています。(GitHub)
4) 実際に「アップデート後にPythonパッケージ周りが壊れた」報告がある
Arduino Forum では「昨日は pip3 install で動いたのに、今朝のアップデート後に壊れた」という報告があり、さらに App LabのPythonはDockerコンテナ内で動くため、adb shell の環境とは別、という説明もされています。(Arduino Forum)
→ 依存パッケージや実行環境の更新が、動作に影響する“実例”です。
「壊れる」としたら、どのパターンが多いか
現場で起きやすいのはだいたい次の4系統です:
- Brickの公開API変更(関数名・引数・イベント名の変更、非推奨化)
- コンテナ/ベースイメージ更新による差分(Pythonのバージョン、OSパッケージ、ライブラリの挙動、依存の解決方法)
- requirements.txt の依存解決が変わる(ピン留めしないと、新しい版が入って突然挙動が変わる)
- App Lab本体/管理CLIの更新で周辺仕様が変わる(起動順、設定チェック、必須パラメータ検証など)
App Lab 0.3.2 で「依存の自動管理」や「Brickの必須パラメータ事前チェック」などが入った、という話もあり、更新で“以前は通っていたものが弾かれる”方向の変化も起こり得ます。(Arduino Blog)
じゃあ、どう備えるのが現実的か(おすすめ順)
A. 依存を固定する(最重要)
- requirements.txt は バージョン固定(例:package==1.2.3)を基本にする
- 可能なら ハッシュ固定(pipの –require-hashes) までやると強い
(“勝手に新しい版が入る”事故を防ぎます)
B. “Brickの内部”ではなく“公開APIだけ”に依存する
Brickの内部モジュールや未ドキュメントな挙動に依存すると、更新で壊れやすいです。
C. 更新を前提に「検証→本番」の段取りを作る
App Lab側は更新チェックが必須で、スキップは将来予定なので(Arduinoヘルプセンター)、更新ゼロ運用は現状やりにくいです。
そこで、
- 検証用UNO Qを1台用意して先に更新
- “スモークテスト”(起動、Brick初期化、センサ1分、UI表示、ログ保存)を自動化
- OKなら本番機を更新
が効きます。
D. “現状のバージョン情報”を必ず記録する
問題が起きたときの切り分け速度が段違いになります。app-bricks-py では SBOM(コンテナ内のパッケージ一覧)を用意している、と書かれているので(GitHub)、同等の情報(App Lab版、Brick版、Python版、主要pip一覧)を控えるのが有効です。
E. ミッションクリティカルなら「Brick依存を薄くする」設計も検討
- Brickの便利機能は使いつつ、コア処理は自前(非Brick)に寄せる
- あるいは、更新影響を受けにくい外部サーバへ寄せる(ログ/DB/グラフなど)
“結局、動かなくなる可能性はある?”への回答
あります。 理由は以下が一次情報で確認できるからです。
- App Labは更新チェックが必須で、PC/ボード側が更新される(Arduinoヘルプセンター)
- BrickはDocker/ベースイメージを含む構成で、ベースは別頻度で更新される(GitHub)
- 実際に「アップデート後にPython依存が壊れた」報告がある(Arduino Forum)
- 管理CLIも他コンポーネントを自動更新すると明記(GitHub)
もしよければ次は、あなたの想定(例:arduino:web_ui を使う、使わない、どのBrickを使う、requirements.txtの有無)に合わせて、「壊れやすいポイントのチェックリスト」と「更新後の自動スモークテスト手順(最小)」を2構成(Brick / 非Brick)で作ります。
今後のバージョンアップによって、Bricksなどをブラックボックスとしておけない可能性もありそうだ。
