在物联网和网络日益融合的世界中,创建实时监控界面的能力变得至关重要。通过这个实践教程,我们将探索创建一个完整的交通信号灯监控系统,结合 Zephyr OS 物联网的强大功能与现代网络技术。这个项目将作为一个具体示例来理解实时物联网监控的挑战和解决方案。
注意:作为 Zephyr OS 专家,我可以为您的物联网开发项目提供支持。如果您有任何关于 Zephyr OS 的问题或想讨论您的嵌入式开发需求,请随时通过电子邮件或 LinkedIn 或 GitHub 与我联系。
本项目的完整源代码可在 GitHub 上获取。
文章大纲
-
项目概述
-
物联网部分:交通信号灯控制器
- Zephyr OS 简介
- 控制器的 C++ 实现
- 服务器通信
-
后端:服务器和通信
- 使用 Bun 的 HTTP API
- 实时 WebSocket 服务器
- 使用 Redis 进行状态管理
-
前端:监控界面
- 使用 Next.js 15 构建
- 实时 React 组件
- 状态和更新管理
-
基础设施和部署
-
进一步探索
简介
物联网设备的实时监控带来了独特的挑战,从状态管理到双向通信。我们的互联交通信号灯项目完美地说明了这些问题:如何确保物理设备和网络界面之间的可靠同步,同时保持最佳性能?
项目目标
这个教育项目旨在:
- 展示物联网和现代网络技术的集成
- 探索实时通信模式
- 实践全栈开发最佳实践
- 理解物联网监督的挑战
全局架构
我们的系统围绕四个主要组件构建:
- 物联网控制器: 使用 Zephyr OS 和 C++ 开发,模拟交通信号灯控制器
- API 网关: 用于控制器通信的 HTTP 服务器
- WebSocket 服务器: 确保状态变化的实时分发
- Web 界面: 用于可视化和控制的 Next.js 应用程序
关于模拟的重要说明: 在本项目中,我们出于教育目的在 Docker 容器中模拟物联网设备。控制器仅记录状态变化。在实际部署中,该控制器将安装在实际的物联网设备上(如 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. 项目概述
全局架构
我们的交通信号灯监控系统依赖于现代分布式架构,旨在确保物联网设备和用户界面之间的可靠实时通信。
数据流
-
物联网层级
- 基于 Zephyr OS 的交通信号灯控制器管理灯光状态
- 在我们的实现中,状态变化通过 HTTP 传输到 API 网关,但也可以使用其他协议:
- MQTT 用于更轻量和优化的物联网通信
- CoAP 用于受限网络
- LoRaWAN 用于长距离通信
- gRPC 用于提高性能
- 控制器与服务器保持稳定连接
-
后端层级
- API 网关接收更新并将其存储在 Redis 中
- Redis 作为集中式状态存储
- WebSocket 服务器订阅 Redis 事件
- 变更实时广播给已连接的客户端
-
前端层级
- Next.js 应用程序建立 WebSocket 连接
- React 组件自动更新
- 界面显示实时灯光状态
使用的技术
物联网端
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}
学习目标
本项目旨在涵盖现代物联网和网络开发的几个重要方面:
1. 嵌入式编程
- 使用 Zephyr OS 进行物联网开发
- C++ 中的状态和转换管理
- 嵌入式设备的网络通信
2. 分布式架构
- 异构系统之间的通信
- 使用 Redis 的分布式状态管理
- 实时消息传递模式
3. 现代网络开发
- 使用 Next.js 的六边形架构
- 高性能 React 组件
- TypeScript 和强类型
4. DevOps 和基础设施
- 使用 Docker 容器化
- 自动化脚本
- 监控和日志记录
在接下来的章节中,我们将详细探讨系统的每个组件,从基于 Zephyr OS 的物联网控制器开始。
2. 物联网部分:交通信号灯控制器
Zephyr OS 简介
Zephyr OS 是一个开源实时操作系统(RTOS),特别适合嵌入式和物联网系统。在我们的项目中,它提供了几个关键优势:
- 实时管理: 完美适合精确的交通信号灯控制
- 强大的网络栈: 原生 TCP/IP 协议支持
- 减少内存占用: 适合受限设备
- 现代 C++ 支持: 支持面向对象编程
控制器实现
我们的交通信号灯控制器使用现代 C++ 实现,利用 Zephyr OS 功能进行高效的状态管理和通信。
代码结构
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}
-
主循环
- 系统在南北和东西轴之间交替
- 每个周期包括三个阶段:
- 绿灯(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
这个简单版本仍然非常适合演示基本的物联网和实时通信概念。
项目配置
prj.conf 文件为我们的项目配置 Zephyr OS 功能。此配置启用:
- C++ 和 C++17 标准支持以使用现代语言特性
- 网络功能与 IPv4 和 TCP 用于服务器通信
- 套接字和 HTTP 客户端以发送状态更新
- 日志系统用于调试和监控
这些选项对于我们的物联网控制器通过网络通信并向中央服务器发送交通信号灯状态变化至关重要。
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 使用极简且高度可配置的方法。在编译期间,只有严格必要的组件被包含在最终镜像中:
-
与传统操作系统的区别
- 传统嵌入式 Linux 有几百 MB
- 包含许多未使用的驱动程序和服务
- 启动加载许多多余的组件
- 攻击面更大
-
Zephyr 方法的优势
- 最终镜像仅几百 KB
- 仅包含配置的驱动程序和协议
- 启动几乎瞬时完成
- 攻击面最小
-
精细配置
- 每个功能都是一个 Kconfig 模块
- 依赖关系自动解析
- 优化最大化
- 资源静态分配
这种"从零开始"的方法允许获得高度优化和安全的系统,完全适应物联网约束:
- 有限资源(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)
这个物联网实现说明了几个高级概念:
-
事件驱动编程
- 使用消息队列进行线程间通信
- 定时器用于状态转换管理
-
资源管理
-
稳健性
在下一节中,我们将看到后端如何处理与这些物联网控制器的通信并将更新分发给网络客户端。
3. 后端:服务器和通信
我们的后端由多个服务协同工作,以确保物联网控制器和网络界面之间的顺畅通信。
使用 Bun 的 API 网关
API 网关是物联网控制器的入口点。使用 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
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 服务器确保实时将更新分发给已连接的网络客户端。
服务器实现
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}
通信架构
我们的后端实现了几个基本的通信模式:
-
发布/订阅模式
- Redis 作为消息代理
- 生产者和消费者的解耦
- 高效的更新分发
-
网关模式
- 物联网设备的单一入口点
- 数据验证和转换
- 集中式错误处理
-
观察者模式
- 实时变更通知
- 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 组件
主页面
traffic-lights-monitor/src/app/page.tsx
1import { Intersection } from "@/interfaces/components/traffic-lights/intersection";
2
3export default function Home() {
4 return (
5 <div className="min-h-screen flex flex-col items-center justify-center p-8">
6 <h1 className="text-2xl font-bold mb-8">交通信号灯监控</h1>
7 <Intersection />
8 </div>
9 );
10}
交通信号灯组件
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. 测试和质量
为确保系统可靠性,我们应该实现:
物联网控制器测试
- 交通信号灯状态机的单元测试
- 网络集成测试
- 错误条件模拟
- 灯光序列验证
前端测试
- 使用 Jest 和 Testing Library 的 React 组件测试
- 使用 Cypress 或 Playwright 的端到端测试
- 使用 Lighthouse 的性能测试
- 可访问性验证
2. 监控和可观察性
为了有效的生产监控,我们应该添加:
-
性能
- 与 Prometheus/Grafana 集成
- 详细的 WebSocket 指标
- 物联网资源监控
-
可靠性
-
安全性
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}
为了成功部署,建议:
- 持续监控电池健康状况
- 计划预防性更换
- 定期清洁太阳能板
- 实施低电量降级模式
- 提供备用信号
结论
这个项目展示了物联网和现代网络技术的成功集成,创建了一个实时监控系统。主要收获包括:
-
分布式架构
-
现代技术
- 用于物联网的 Zephyr OS
- 用于前端的 Next.js
- 用于实时的 WebSocket
-
最佳实践
这个项目可以作为开发更复杂的物联网应用程序的基础,通过根据您的具体需求调整架构和使用的模式。
实践应用
为了从本教程中获得最大收益并开发您自己的物联网项目,以下是一些实践练习建议:
1. 从小做起
-
简化版本
- 首先创建单个交通信号灯
- 使用不带 WebSocket 的简单 HTTP 服务器
- 在基本网页中显示状态
-
物联网模拟
- 开始时不使用物理硬件
- 用 Node.js 脚本模拟控制器
- 测试通信逻辑
2. 渐进式演进
-
添加 WebSocket
-
集成 Redis
- 首先存储简单状态
- 添加数据持久化
- 实现发布/订阅模式
3. 项目变体
以下是创建您自己版本的一些想法:
-
其他用例
-
替代技术
- 用 ESP32/Arduino 替换 Zephyr OS
- 使用 MQTT 替代 WebSocket
- ...
4. 额外资源
深入了解每个方面:
-
官方文档
-
示例仓库
-
社区