IoTとWebがますます融合する世界において、リアルタイムモニタリングインターフェースを作成する能力は重要になってきています。この実践的なチュートリアルでは、IoT向けのZephyr OSとモダンなWeb技術の力を組み合わせて、完全なトラフィックライトモニタリングシステムの作成を探求します。このプロジェクトは、リアルタイムIoTモニタリングの課題と解決策を理解するための具体的な例として役立ちます。
注: Zephyr OSのエキスパートとして、IoT開発プロジェクトのサポートを提供しています。Zephyr OSに関する質問や組み込み開発のニーズについて、メールまたはLinkedIn、GitHubを通じてお気軽にご連絡ください。
このプロジェクトの完全なソースコードはGitHubで入手可能です。
記事の概要
-
プロジェクト概要
-
IoTパート:トラフィックライトコントローラー
- Zephyr OSの紹介
- C++でのコントローラー実装
- サーバー通信
-
バックエンド:サーバーと通信
- BunによるHTTP API
- リアルタイム用WebSocketサーバー
- Redisによる状態管理
-
フロントエンド:モニタリングインターフェース
- Next.js 15での構築
- リアルタイムReactコンポーネント
- 状態と更新の管理
-
インフラストラクチャとデプロイメント
-
さらなる展開
はじめに
IoTデバイスのリアルタイムモニタリングには、状態管理から双方向通信まで、独自の課題があります。私たちの接続されたトラフィックライトプロジェクトは、これらの問題を完璧に示しています:物理デバイスとWebインターフェース間の信頼性の高い同期をどのように確保し、最適なパフォーマンスを維持するか?
プロジェクトの目的
この教育プロジェクトは以下を目指しています:
- IoTとモダンなWeb技術の統合を実証
- リアルタイム通信パターンの探求
- フルスタック開発のベストプラクティスの実践
- IoT監視の課題の理解
グローバルアーキテクチャ
システムは4つの主要コンポーネントで構成されています:
- IoTコントローラー: Zephyr OSでC++を使用して開発されたトラフィックライトコントローラー
- APIゲートウェイ: コントローラー通信用のHTTPサーバー
- WebSocketサーバー: 状態変更のリアルタイム配信を保証
- Webインターフェース: 可視化と制御のためのNext.jsアプリケーション
シミュレーションに関する重要な注意: このプロジェクトでは、教育目的でIoTデバイスをDockerコンテナでシミュレーションしています。コントローラーは単に状態変更をログに記録します。実際のデプロイメントでは、このコントローラーは実際のIoTデバイス(Raspberry Pi Picoなど)にインストールされ、GPIOを介して物理的にトラフィックライトを制御します。
Raspberry Pi Picoの例
Raspberry Pi Picoは、実際の条件でこのプロジェクトを実装するのに最適な選択です:
- Zephyr OSを公式にサポート
- トラフィックライトLEDを制御するためのGPIO
- 様々な長距離通信モジュール(LoRaWAN、NB-IoT、LTE-M)を介してネットワークに接続可能
- 非常に手頃な価格(約5ユーロ)
シミュレーションから実際のデプロイメントに移行するには:
- ログをGPIOコマンドに置き換え
- デプロイメントコンテキストに応じてWiFiまたは長距離通信モジュール(LoRaWAN、NB-IoT、LTE-M)のネットワーク設定を適応
- 電源供給と耐久性の管理
- 保護ケースの追加
1. プロジェクト概要
グローバルアーキテクチャ
トラフィックライトモニタリングシステムは、IoTデバイスとユーザーインターフェース間の信頼性の高いリアルタイム通信を確保するように設計された、モダンな分散アーキテクチャに依存しています。
データフロー
-
IoTレベル
- Zephyr OSベースのトラフィックライトコントローラーがライトの状態を管理
- 実装では、状態変更はHTTPを介してAPIゲートウェイに送信されますが、他のプロトコルも使用可能:
- より軽量で最適化されたIoT通信用のMQTT
- 制約のあるネットワーク用のCoAP
- 長距離通信用のLoRaWAN
- パフォーマンス向上のためのgRPC
- コントローラーはサーバーとの堅牢な接続を維持
-
バックエンドレベル
- APIゲートウェイが更新を受信しRedisに保存
- Redisが集中状態ストアとして機能
- WebSocketサーバーがRedisイベントを購読
- 変更がリアルタイムで接続クライアントにブロードキャスト
-
フロントエンドレベル
- Next.jsアプリケーションがWebSocket接続を確立
- Reactコンポーネントが自動的に更新
- インターフェースがリアルタイムでライトの状態を表示
使用技術
IoT側
1// Zephyr OSコード例
2void change_traffic_light_state(const char* id, const char* state) {
3 // HTTPで状態を送信
4 http_client.send_traffic_light_state(id, state);
5 // イベントログ
6 LOG_INF("Traffic light %s: %s", id, state);
7}
バックエンドと通信
1// BunによるWebSocketサーバー
2const wsServer = new WebSocketServer({ port: 8001 });
3
4// Redisイベント購読
5subscriber.subscribe('traffic-lights', (message) => {
6 wsConnections.forEach((ws) => {
7 ws.send(JSON.stringify(JSON.parse(message)));
8 });
9});
フロントエンド
1// WebSocket付きNext.jsコンポーネント
2export function Intersection() {
3 const [lights, setLights] = useState<TrafficLightState[]>([]);
4
5 useEffect(() => {
6 const adapter = new TrafficLightAdapter();
7 return adapter.subscribeToUpdates((state) => {
8 setLights(prev => prev.map(light =>
9 light.id === state.id ? { ...light, state: state.state } : light
10 ));
11 });
12 }, []);
13
14 return (/* トラフィックライトのレンダリング */);
15}
学習目標
このプロジェクトは、モダンなIoTとWeb開発の複数の重要な側面をカバーするように設計されています:
1. 組み込みプログラミング
- IoT開発のためのZephyr OSの使用
- C++での状態と遷移の管理
- 組み込みデバイスからのネットワーク通信
2. 分散アーキテクチャ
- 異種システム間の通信
- Redisによる分散状態管理
- リアルタイムメッセージングパターン
3. モダンWeb開発
- Next.jsによるヘキサゴナルアーキテクチャ
- パフォーマンスの高いReactコンポーネント
- TypeScriptと強力な型付け
4. DevOpsとインフラストラクチャ
- Dockerによるコンテナ化
- 自動化スクリプト
- モニタリングとロギング
以降のセクションでは、Zephyr OSベースのIoTコントローラーから始めて、システムの各コンポーネントを詳しく探求していきます。
2. IoTパート:トラフィックライトコントローラー
Zephyr OSの紹介
Zephyr OSは、組み込みおよびIoTシステムに特に適したオープンソースのリアルタイムオペレーティングシステム(RTOS)です。私たちのプロジェクトでは、以下の主要な利点を提供します:
- リアルタイム管理: トラフィックライトの正確な制御に最適
- 堅牢なネットワークスタック: TCP/IPプロトコルのネイティブサポート
- 削減されたメモリフットプリント: 制約のあるデバイスに理想的
- モダンなC++サポート: オブジェクト指向プログラミングを可能に
コントローラーの実装
トラフィックライトコントローラーは、効率的な状態管理と通信のためにZephyr OSの機能を使用して、モダンなC++で実装されています。
コード構造
traffic-lights-orcherstrator/src/main.hpp
1enum class LightState
2{
3 RED,
4 YELLOW,
5 GREEN
6};
7
8struct TrafficLight
9{
10 const char *name;
11 LightState state;
12 k_timer timer;
13};
14
15struct StateChangeEvent
16{
17 int light_index;
18 LightState new_state;
19};
状態管理
traffic-lights-orcherstrator/src/main.cpp
1void change_axis_state(int light1_index, int light2_index, LightState new_state, uint32_t duration_ms)
2{
3 StateChangeEvent evt1 = {light1_index, new_state};
4 StateChangeEvent evt2 = {light2_index, new_state};
5
6 k_msgq_put(&state_change_queue, &evt1, K_NO_WAIT);
7 k_msgq_put(&state_change_queue, &evt2, K_NO_WAIT);
8
9 if (duration_ms > 0)
10 {
11 k_timer_start(&lights[light1_index].timer, K_MSEC(duration_ms), K_NO_WAIT);
12 k_timer_start(&lights[light2_index].timer, K_MSEC(duration_ms), K_NO_WAIT);
13 }
14}
サーバー通信
バックエンドサーバーとの通信は、Zephyr HTTPのAPIを使用する専用クラスによって処理されます。
HTTPクライアント
traffic-lights-orcherstrator/src/http_client.cpp
1void HttpClient::send_traffic_light_state(const char *id, const char *state)
2{
3 // HTTPリクエストの準備
4 struct http_request req;
5 memset(&req, 0, sizeof(req));
6
7 const char *headers[] = {
8 "Content-Type: application/json\r\n",
9 content_len,
10 NULL
11 };
12
13 req.method = HTTP_POST;
14 req.url = "/traffic-light";
15 req.host = SERVER_ADDR;
16 req.protocol = "HTTP/1.1";
17 req.header_fields = headers;
18 req.payload = payload;
19 req.payload_len = strlen(payload);
20}
ロギングとモニタリング
traffic-lights-orcherstrator/src/logger.cpp
1#include <zephyr/logging/log.h>
2
3LOG_MODULE_REGISTER(traffic_lights, LOG_LEVEL_INF);
4
5void log_light_state(const char *name, const char *state)
6{
7 LOG_INF("Traffic light %s: %s", name, state);
8}
トラフィックライト管理アルゴリズム
main.cppに実装されたアルゴリズムは、安全で調整されたトラフィックライトサイクルを管理します。より複雑なユースケースのために拡張可能な、シンプルでデモンストレーション的な実装を選択しました。
-
システム初期化
1void init_traffic_system() {
2 // 各ライトのタイマー初期化
3 for (auto &light : lights) {
4 k_timer_init(&light.timer, timer_expiry_callback, nullptr);
5 }
6 // 通信用HTTPスレッドの作成
7 http_thread_id = k_thread_create(&http_thread_data, ...);
8}
-
メインサイクル
- システムは南北軸と東西軸を交互に切り替え
- 各サイクルは3つのフェーズを含む:
- 緑(30秒)
- 黄(5秒)
- 赤と安全遅延(2秒)
-
状態変更管理
1void change_axis_state(int light1_index, int light2_index,
2 LightState new_state, uint32_t duration_ms) {
3 // 状態変更イベントの送信
4 StateChangeEvent evt1 = {light1_index, new_state};
5 StateChangeEvent evt2 = {light2_index, new_state};
6
7 // 期間が指定されている場合のタイマープログラミング
8 if (duration_ms > 0) {
9 k_timer_start(&lights[light1_index].timer, ...);
10 k_timer_start(&lights[light2_index].timer, ...);
11 }
12}
-
非同期通信
- 専用スレッドがHTTP状態変更の送信を処理
- イベントは
k_msgqを介してキューに入れられる
- HTTPスレッドが非同期で処理
-
安全性と堅牢性
- 軸変更間の安全遅延
- 通信エラー処理
- モニタリング用イベントログ
改善の方向性
この基本的な実装は以下のように拡張可能です:
-
カスタマイズ可能なシナリオ
- 時間ベースの期間設定
- 特別モード(夜間、緊急時、イベント)
- リアルタイムの交通適応
-
高度な交通管理
-
動的設定
- リモートパラメータインターフェース
- オンザフライのシナリオ変更
- 交通パターン機械学習
これらの改善を実装するには:
- シナリオ用の抽象化レイヤーの追加
- 動的設定システムの実装
- センサーと複雑なビジネスルールの統合
- より完全な制御APIの開発
このシンプルなバージョンは、基本的なIoTとリアルタイム通信の概念を実証するのに完璧に適しています。
プロジェクト設定
prj.confファイルは、プロジェクトのためのZephyr OS機能を設定します。この設定は以下を有効にします:
- モダンな言語機能を使用するためのC++とC++17標準サポート
- サーバー通信のためのIPv4とTCPによるネットワーク機能
- 状態更新を送信するためのソケットとHTTPクライアント
- デバッグとモニタリングのためのロギングシステム
これらのオプションは、IoTコントローラーがネットワーク経由で通信し、トラフィックライトの状態変更を中央サーバーに送信するために不可欠です。
traffic-lights-orcherstrator/prj.conf
1CONFIG_CPP=y
2CONFIG_STD_CPP17=y
3CONFIG_NETWORKING=y
4CONFIG_NET_IPV4=y
5CONFIG_NET_TCP=y
6CONFIG_NET_SOCKETS=y
7CONFIG_HTTP_CLIENT=y
8CONFIG_LOG=y
Zephyr OSによる最適化コンパイル
Linuxのような多くのデフォルトモジュールとドライバーを含む従来のオペレーティングシステムとは異なり、Zephyr OSはミニマリストで高度に設定可能なアプローチを使用します。コンパイル時に、厳密に必要なコンポーネントのみが最終イメージに含まれます:
-
従来のOSとの違い
- 従来の組み込みLinuxは数百MBサイズ
- 多くの未使用ドライバーとサービスを含む
- 起動時に多くの不要なコンポーネントをロード
- 攻撃対象領域が大きい
-
Zephyrアプローチの利点
- 最終イメージは数百KBのみ
- 設定されたドライバーとプロトコルのみを含む
- 起動はほぼ瞬時
- 攻撃対象領域が最小限
-
粒度の細かい設定
- 各機能はKconfigモジュール
- 依存関係は自動的に解決
- 最適化は最大化
- リソースは静的に割り当て
この「ゼロから」のアプローチにより、IoTの制約に完璧に適応した、高度に最適化され安全なシステムを得ることができます:
- 限られたリソース(RAM/Flash)
- 最小限のエネルギー消費
- 高速起動
- 削減された攻撃対象領域
コンパイルとデプロイメント
プロジェクトはコンパイルにCMakeを使用します:
traffic-lights-orcherstrator/CMakeLists.txt
1cmake_minimum_required(VERSION 3.20.0)
2
3set(CONF_FILE "prj.conf")
4set(BOARD qemu_x86)
5
6enable_language(C CXX)
7set(CMAKE_CXX_STANDARD 17)
8
9find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10project(traffic-lights-orcherstrator)
11
12target_sources(app PRIVATE
13 src/main.cpp
14 src/logger.cpp
15 src/http_client.cpp
16)
このIoT実装は、いくつかの高度な概念を示しています:
-
イベント駆動プログラミング
- スレッド間通信のためのメッセージキューの使用
- 状態遷移管理のためのタイマー
-
リソース管理
-
堅牢性
次のセクションでは、バックエンドがこれらのIoTコントローラーとの通信を処理し、Webクライアントに更新を配信する方法を見ていきます。
3. バックエンド:サーバーと通信
バックエンドは、IoTコントローラーとWebインターフェース間のスムーズな通信を確保するために協力する複数のサービスで構成されています。
BunによるAPIゲートウェイ
APIゲートウェイは、IoTコントローラーのエントリーポイントです。その優れたパフォーマンスのためにBunで実装され、HTTPリクエストを処理し状態の一貫性を維持します。
リクエスト管理
gateway-http-server-redis/main.ts
1async fetch(req: Request) {
2 const url = new URL(req.url);
3
4 // すべてのレスポンスのCORSヘッダー
5 const corsHeaders = {
6 "Access-Control-Allow-Origin": "*",
7 "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
8 "Access-Control-Allow-Headers": "Content-Type",
9 };
10
11 // トラフィックライト更新を受信するルート
12 if (req.method === "POST" && url.pathname === "/traffic-light") {
13 try {
14 const data = await req.json();
15 const { id, state } = data;
16
17 // 状態の検証
18 const validStates = ["red", "yellow", "green"];
19 if (!validStates.includes(state)) {
20 return new Response("Invalid state", {
21 status: 400,
22 headers: corsHeaders
23 });
24 }
25
26 // RedisへのPublish
27 await redis.publish("traffic-lights", JSON.stringify({ id, state }));
28 // 現在の状態を保存
29 await redis.set(`traffic-light:${id}`, state);
30
31 return new Response(JSON.stringify({ success: true }), {
32 headers: {
33 ...corsHeaders,
34 "Content-Type": "application/json"
35 }
36 });
37 } catch (error) {
38 console.error("Error:", error);
39 return new Response(JSON.stringify({ error: error.message }), {
40 status: 500,
41 headers: corsHeaders
42 });
43 }
44 }
45}
WebSocketサーバー
WebSocketサーバーは、接続されたWebクライアントへの更新のリアルタイム配信を確保します。
サーバー実装
traffic-lights-ws-server/main.ts
1const subscriber = redis.duplicate();
2await subscriber.connect();
3
4await subscriber.subscribe("traffic-lights", (message) => {
5 try {
6 const data = JSON.parse(message);
7 console.log("New traffic light change:", data);
8
9 wsConnections.forEach((ws) => {
10 ws.send(JSON.stringify(data));
11 });
12 } catch (err) {
13 console.error("Error parsing message:", err);
14 }
15});
Redisによる状態管理
Redisは、メッセージブローカーと状態ストアの両方として機能し、アーキテクチャの中心的な役割を果たします。
Redis設定
1services:
2 redis:
3 image: redis:latest
4 ports:
5 - "6379:6379"
6 volumes:
7 - redis-data:/data
8 command: redis-server --appendonly yes
9 networks:
10 zephyr-net:
11 ipv4_address: 10.5.0.3
Redisサブスクライバー
traffic-lights-subscriber/main.ts
1async function main() {
2 const redis = createClient({
3 url: "redis://localhost:6379"
4 });
5
6 redis.on("error", err => console.error("Redis Error:", err));
7 redis.on("connect", () => console.log("Connected to Redis"));
8
9 await redis.connect();
10
11 const subscriber = redis.duplicate();
12 await subscriber.connect();
13
14 await subscriber.subscribe("traffic-lights", (message) => {
15 try {
16 const data = JSON.parse(message);
17 console.log("New traffic light change:", data);
18 } catch (err) {
19 console.error("Error parsing message:", err);
20 }
21 });
22}
通信アーキテクチャ
バックエンドは複数の重要な通信パターンを実装しています:
-
Pub/Subパターン
- メッセージブローカーとしてのRedis
- プロデューサーとコンシューマーの分離
- 効率的な更新配信
-
ゲートウェイパターン
- IoTデバイスの単一エントリーポイント
- データ検証と変換
- 集中化されたエラー処理
-
オブザーバーパターン
- リアルタイムの変更通知
- WebSocket接続の維持
- クライアントへの更新配信
セキュリティとパフォーマンス
セキュリティとパフォーマンスを確保するために、いくつかの対策が講じられています:
-
セキュリティ
- 入力データの検証
- 設定されたCORSヘッダー
- Dockerによるネットワーク分離
-
パフォーマンス
- 最適なパフォーマンスのためのBunの使用
- 永続的なRedis接続
- 効率的なWebSocket管理
-
信頼性
- イベントログ
- 堅牢なエラー処理
- サービスの自動再接続
次のセクションでは、トラフィックライトシステムの可視化と対話を可能にするNext.jsで開発されたユーザーインターフェースを探求します。
4. フロントエンド:モニタリングインターフェース
システムのユーザーインターフェースは、モダンな開発のベストプラクティスとヘキサゴナルアーキテクチャに従ってNext.js 15で構築されています。
フロントエンドアーキテクチャ
アプリケーションは、関心の明確な分離を維持するためにヘキサゴナルアーキテクチャ(ポートとアダプター)に従います:
traffic-lights-monitor/src/domain/traffic-light.ts
1export interface TrafficLightState {
2 id: string;
3 state: "red" | "yellow" | "green";
4}
5
6export interface TrafficLightPort {
7 getInitialStates(): Promise<TrafficLightState[]>;
8 subscribeToUpdates(callback: (state: TrafficLightState) => void): () => void;
9}
アダプター実装
アダプターはWebSocketを介してバックエンドとの通信を処理します:
traffic-lights-monitor/src/infrastructure/adapters/traffic-light.adapter.ts
1export class TrafficLightAdapter implements TrafficLightPort {
2 async getInitialStates(): Promise<TrafficLightState[]> {
3 try {
4 const responses = await Promise.all(
5 ["North", "South", "East", "West"].map((id) =>
6 fetch(`${API_URL}/traffic-light/${id}`).then((res) => res.json())
7 )
8 );
9
10 return responses.map((response) => ({
11 id: response.id,
12 state: response.state,
13 }));
14 } catch (error) {
15 console.error("Error retrieving states:", error);
16 return [
17 { id: "North", state: "red" },
18 { id: "South", state: "red" },
19 { id: "East", state: "red" },
20 { id: "West", state: "red" },
21 ];
22 }
23 }
24
25 subscribeToUpdates(callback: (state: TrafficLightState) => void): () => void {
26 const ws = new WebSocket(WS_URL);
27
28 ws.onmessage = (event) => {
29 try {
30 const data = JSON.parse(event.data);
31 callback(data);
32 } catch (error) {
33 console.error("Error processing WebSocket message:", error);
34 }
35 };
36
37 return () => ws.close();
38 }
39}
Reactコンポーネント
メインページ
1-monitor/src/app/page.tsx
2import { Intersection } from "@/interfaces/components/traffic-lights/intersection";
3
4export default function Home() {
5 return (
6 <div className="min-h-screen flex flex-col items-center justify-center p-8">
7 <h1 className="text-2xl font-bold mb-8">トラフィックライトモニター</h1>
8 <Intersection />
9 </div>
10 );
11}
トラフィックライトコンポーネント
traffic-lights-monitor/src/interfaces/components/traffic-lights/traffic-light.tsx
1"use client";
2
3interface TrafficLightProps extends TrafficLightState {
4 orientation?: "vertical" | "horizontal";
5}
6
7export function TrafficLight({
8 id,
9 state,
10 orientation = "vertical",
11}: TrafficLightProps) {
12 const lights = ["red", "yellow", "green"];
13
14 return (
15 <div className="flex flex-col gap-2 items-center">
16 <h3 className="text-sm font-semibold">{id}</h3>
17 <div
18 className={`bg-gray-800 p-2 rounded-lg flex ${
19 orientation === "horizontal" ? "flex-row" : "flex-col"
20 } gap-2`}
21 >
22 {lights.map((light) => (
23 <div
24 key={light}
25 className={`w-8 h-8 rounded-full ${
26 state === light
27 ? {
28 red: "bg-red-500",
29 yellow: "bg-yellow-500",
30 green: "bg-green-500",
31 }[light]
32 : "bg-gray-700"
33 }`}
34 />
35 ))}
36 </div>
37 </div>
38 );
39}
スタイルと設定
Tailwind設定
traffic-lights-monitor/tailwind.config.ts
1export default {
2 content: [
3 "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
4 "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
5 "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
6 "./src/interfaces/**/*.{js,ts,jsx,tsx,mdx}",
7 ],
8 theme: {
9 extend: {
10 colors: {
11 background: "var(--background)",
12 foreground: "var(--foreground)",
13 },
14 borderSpacing: {
15 'road': '16px'
16 },
17 backgroundImage: {
18 'dashed-white': 'repeating-linear-gradient(90deg, white 0 12px, transparent 12px 32px)',
19 'dashed-white-vertical': 'repeating-linear-gradient(0deg, white 0 12px, transparent 12px 32px)',
20 }
21 },
22 },
23 plugins: [],
24}
最適化とベストプラクティス
-
パフォーマンス
- Reactサーバーコンポーネントの使用
- レンダリングの最適化
- 重要でないコンポーネントの遅延ロード
-
アクセシビリティ
- キーボードサポート
- 適切なARIA属性
- 最適化された色のコントラスト
-
保守性
- ヘキサゴナルアーキテクチャ
- TypeScriptによる厳密な型付け
- 自動化されたテスト
次のセクションでは、アプリケーションのインフラストラクチャとデプロイメントについて説明します。
5. インフラストラクチャとデプロイメント
システムはすべての環境で一貫性のある再現可能なデプロイメントを確保するためにDockerを使用します。
Docker設定
サービス構成
1services:
2 traffic-lights-monitor:
3 image: oven/bun:latest
4 working_dir: /traffic-lights-monitor
5 volumes:
6 - ./traffic-lights-monitor/:/traffic-lights-monitor
7 command: sh -c "bun install && bun run build && bun run start"
8 ports:
9 - "3000:3000"
10 environment:
11 - NEXT_PUBLIC_API_URL=http://zephyr-dev:8000
12 - NEXT_PUBLIC_WS_URL=ws://localhost:8001
13 networks:
14 zephyr-net:
15 ipv4_address: 10.5.0.5
16
17 redis:
18 image: redis:latest
19 ports:
20 - "6379:6379"
21 volumes:
22 - redis-data:/data
23 command: redis-server --appendonly yes
24 networks:
25 zephyr-net:
26 ipv4_address: 10.5.0.3
27
28volumes:
29 redis-data:
30
31networks:
32 zephyr-net:
33 driver: bridge
34 ipam:
35 config:
36 - subnet: 10.5.0.0/24
開発スクリプト
サービス管理スクリプト
1#!/bin/bash
2
3# メッセージの色
4RED='\033[0;31m'
5GREEN='\033[0;32m'
6YELLOW='\033[1;33m'
7NC='\033[0m'
8
9# コンテナが実行中かチェックする関数
10check_containers() {
11 if ! docker compose ps --quiet &>/dev/null; then
12 echo -e "${RED}コンテナが実行されていません。${NC}"
13 echo -e "${YELLOW}コンテナを起動中...${NC}"
14 docker compose up -d
15 fi
16}
17
18# コンテナを起動する関数
19up() {
20 echo -e "${YELLOW}必要に応じてDockerイメージをビルド中...${NC}"
21 docker compose build
22 echo -e "${YELLOW}コンテナを起動中...${NC}"
23 docker compose up -d
24 echo -e "${GREEN}コンテナが正常に起動しました${NC}"
25}
26
27# コンテナを停止する関数
28down() {
29 echo -e "${YELLOW}コンテナを停止中...${NC}"
30 docker compose down
31 echo -e "${GREEN}コンテナが正常に停止しました${NC}"
32}
開発環境設定
Zephyr用Dockerイメージ
1FROM ghcr.io/zephyrproject-rtos/zephyr-build:latest
2
3USER root
4
5RUN apt-get update
6RUN apt-get install -y \
7 net-tools \
8 uml-utilities \
9 bridge-utils \
10 nftables
11
12RUN apt-get install -y qemu-system-x86
13RUN apt-get install -y iputils-ping curl
14RUN apt-get install -y --no-install-recommends git cmake ninja-build gperf \
15 ccache dfu-util device-tree-compiler wget \
16 python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
17 make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1
18
19RUN west init -m https://github.com/zephyrproject-rtos/zephyr --mr main .
20RUN west update
21RUN west zephyr-export
22
23RUN cd /workdir/tools/net-tools && make
24
25RUN curl -fsSL https://bun.sh/install | bash
26ENV PATH="/root/.bun/bin:${PATH}"
27
28COPY gateway-http-server-redis /gateway-http-server-redis
29RUN cd /gateway-http-server-redis && bun install
30
31EXPOSE 8000
32
33USER root
サポートサービス
Dockerサービススクリプト
1#!/bin/bash
2
3/workdir/tools/net-tools/loop-socat.sh & > /dev/null 2>&1
4/workdir/tools/net-tools/loop-slip-tap.sh & > /dev/null 2>&1
5cd /gateway-http-server-redis && bun run main.ts
6/bin/bash
依存関係管理
Next.js設定
traffic-lights-monitor/package.json
1{
2 "name": "traffic-lights-monitor",
3 "version": "0.1.0",
4 "private": true,
5 "scripts": {
6 "dev": "next dev --turbopack",
7 "build": "next build",
8 "start": "next start",
9 "lint": "next lint"
10 },
11 "dependencies": {
12 "react": "^19.0.0",
13 "react-dom": "^19.0.0",
14 "next": "15.1.3"
15 },
16 "devDependencies": {
17 "typescript": "^5.7.2",
18 "@types/node": "^22.10.2",
19 "@types/react": "^19.0.2",
20 "@types/react-dom": "^19.0.2",
21 "postcss": "^8.4.49",
22 "tailwindcss": "^3.4.17",
23 "eslint": "^9.17.0"
24 }
25}
デプロイメントのベストプラクティス
-
シークレット管理
- 環境変数の使用
- 環境ごとの設定の分離
- 安全なシークレットストレージ
-
モニタリング
- 集中化されたロギング
- パフォーマンスメトリクス
- 自動アラート
-
セキュリティ
- ネットワーク分離
- 定期的な依存関係の更新
- 脆弱性スキャン
最後のセクションでは、アプリケーションのテスト戦略とモニタリングについて説明します。
6. さらなる展開
このプロジェクトをより堅牢で本番環境に対応させるために、いくつかの改善分野を検討できます:
1. テストと品質
システムの信頼性を確保するために、以下を実装する必要があります:
IoTコントローラーのテスト
- トラフィックライトステートマシンのユニットテスト
- ネットワーク統合テスト
- エラー条件のシミュレーション
- ライトシーケンスの検証
フロントエンドテスト
- JestとTesting Libraryを使用したReactコンポーネントテスト
- CypressまたはPlaywrightによるエンドツーエンドテスト
- Lighthouseによるパフォーマンステスト
- アクセシビリティの検証
2. モニタリングと可観測性
効果的な本番環境モニタリングのために、以下を追加する必要があります:
-
パフォーマンス
- Prometheus/Grafanaとの統合
- 詳細なWebSocketメトリクス
- IoTリソースモニタリング
-
信頼性
- コントローラーのハートビートシステム
- 自動異常検知
- 自動状態バックアップ
-
セキュリティ
3. 機能改善
システムは以下のように拡張できます:
-
高度なインターフェース
- メンテナンスモード
- 状態変更履歴
- カスタマイズ可能なダッシュボード
-
シナリオ管理
- 時間ベースのスケジューリング
- 特別モード(緊急時、イベント)
- 外部統合API
-
スケーラビリティ
4. バッテリーデプロイメントのためのエネルギー最適化
エネルギーの自律性が必要なプロジェクト(孤立したサイト、主電源のない地域)のために、いくつかの最適化が必要です:
-
電力モード
- 標準動作のための通常モード
- 静かな日のエネルギー節約のためのエコモード
- 輝度を下げた夜間モード
- バッテリー低下時の緊急モード
1enum class PowerMode {
2 NORMAL, // 標準動作
3 ECO, // エネルギー節約モード
4 NIGHT, // 夜間モード
5 EMERGENCY // 緊急モード(バッテリー低下)
6};
-
省エネ戦略
- 状態変更間のCPUスリープ
- ネットワーク送信のグループ化
- LED輝度の動的調整
1void enter_low_power_mode() {
2 // CPU周波数の低下
3 pm_device_action_run(cpu_dev, PM_DEVICE_ACTION_RESUME);
4
5 // タイマーウェイクアップの設定
6 k_timer_start(&wakeup_timer, K_SECONDS(state_duration), K_NO_WAIT);
7
8 // スリープモードに入る
9 k_sleep(K_FOREVER);
10}
-
ソーラーパワー
- 適切なパネルサイジング
- 長寿命のためのLiFePO4バッテリー
- バックアップシステム
-
バッテリーモニタリング
1struct PowerMetrics {
2 float battery_voltage;
3 float current_draw;
4 float temperature;
5 uint32_t uptime;
6};
7
8PowerMetrics getCurrentMetrics() {
9 PowerMetrics metrics;
10 metrics.battery_voltage = adc_read_battery();
11 metrics.current_draw = adc_read_current();
12 metrics.temperature = read_temperature();
13 metrics.uptime = k_uptime_get();
14 return metrics;
15}
成功したデプロイメントのために推奨されること:
- バッテリー健全性の継続的なモニタリング
- 予防的な交換の計画
- ソーラーパネルの定期的な清掃
- バッテリー低下時の劣化モードの実装
- バックアップ信号の提供
結論
このプロジェクトは、リアルタイムモニタリングシステムを作成するためのIoTとモダンなWeb技術の成功した統合を実証しています。主な学びには以下が含まれます:
-
分散アーキテクチャ
- 責任の明確な分離
- 効率的なコンポーネント間通信
- スケーラビリティと保守性
-
モダンな技術
- IoT向けのZephyr OS
- フロントエンド向けのNext.js
- リアルタイム向けのWebSocket
-
ベストプラクティス
- 自動化されたテスト
- 完全なモニタリング
- 詳細なドキュメント
このプロジェクトは、アーキテクチャとパターンを特定のニーズに適応させることで、より複雑なIoTアプリケーションを開発するための基盤として機能します。
実践
このチュートリアルを最大限に活用し、独自のIoTプロジェクトを開発するために、いくつかの実践的な演習を提案します:
1. 小さく始める
-
簡略化バージョン
- まず単一のトラフィックライトを作成
- WebSocketなしの単純なHTTPサーバーを使用
- 基本的なWebページで状態を表示
-
IoTシミュレーション
- 物理ハードウェアなしで開始
- Node.jsスクリプトでコントローラーをシミュレート
- 通信ロジックをテスト
2. 段階的な進化
-
WebSocketsの追加
- リアルタイム更新の実装
- 自動再接続の処理
- フローを理解するためのログの追加
-
Redisの統合
- まず単純な状態を保存
- データ永続性の追加
- pub/subパターンの実装
3. プロジェクトのバリエーション
独自のバージョンを作成するためのいくつかのアイデア:
-
他のユースケース
- 温度/湿度モニター
- スマート照明システム
- 自動灌水制御
-
代替技術
- Zephyr OSをESP32/Arduinoに置き換え
- WebSocketsの代わりにMQTTを使用
- ...
4. 追加リソース
各側面を深く理解するために:
-
公式ドキュメント
-
サンプルリポジトリ
-
コミュニティ