09-CSDN-02-智能家居模块实战总结

简介: 本项目基于React Native 0.75构建智能家居App,融合MQTT实现实时双向控制(灯、空调等),结合Redux统一状态管理与withDevice高阶组件复用逻辑;采用乐观更新保障UI零延迟响应,双通道(内网HTTP/外网MQTT)适配网络环境,完美解决多端同步、状态最终一致等IoT核心难题。(239字)

React Native + MQTT 实战:智能家居模块设计

技术栈:React Native 0.75 + Redux + MQTT
适用:IoT App、智能家居、设备远程控制

一、功能是什么

业主在 App 上控制家里联网的智能设备(灯、空调、窗帘、地暖、新风、摄像头),核心场景:

场景 说明
设备控制 单设备开关/调节(空调模式、灯光亮度等)
场景联动 一键执行"回家/离家/睡觉"等多设备组合动作
设备定时 指定设备在指定时间执行动作
状态实时同步 UI 与设备状态最终一致

关键要求:

  • UI 零延迟响应(用户操作完立即看到变化)
  • 控制指令要实时到达设备
  • 设备状态变化要实时回传到 UI
  • 同一设备多端同步(家里人和业主同时控制)

二、用到的技术栈

技术 角色 为什么用它
MQTT 设备控制 + 状态推送 Pub/Sub 模式天然适合 IoT,Topic 路由一对多,QoS 保证消息到达
NB MQTT SDK(公司自研) MQTT 客户端封装 屏蔽底层细节,提供 exec / fetchDeviceStates / subscribe 三个核心 API
Redux 设备状态总线 多个页面共享同一份设备状态,避免组件间通信
HOC 高阶组件 控制逻辑复用 8 种设备共用一套控制逻辑,只写 UI 不写业务
乐观更新(dispatch UPDATE_STATE) UI 0ms 响应 不等服务器,先变 UI
HTTP API(getHostConfig) 拿设备列表(静态数据) 设备配置是低频数据,走 HTTP 便于 CDN/缓存
WebSocket + 自家后端 不用于智能家居 项目里 WebSocket 只用于云对讲通知

三、核心协议原理(面试必备)

3.1 MQTT 是什么

MQTT = Message Queuing Telemetry Transport

  • 应用层协议,跑在 TCP 之上(也可以走 WebSocket)
  • 设计目标:IoT 设备在低带宽、不稳定网络下通信
  • 三大角色:Publisher(发布者)、Subscriber(订阅者)、Broker(代理服务器)

核心思想:发布/订阅(Pub/Sub),不是客户端-服务端直连。

发布者 ──> Broker ──> 所有订阅了相同 Topic 的订阅者

3.2 Topic 是什么

Topic = 消息的"频道",用 / 分层,类似文件系统路径。

home_001/light_001/status    ← 客厅灯状态
home_001/ac_001/status      ← 空调状态
home_001/+/status            ← + 通配符:home_001 下所有设备状态

订阅 home_001/+/status = 一次订阅所有设备状态变化。

3.3 为什么 IoT 用 MQTT 而不是 WebSocket

维度 MQTT WebSocket
模型 Pub/Sub(一对多) C/S(一对一)
一对多 ✅ Topic 路由天然支持 ❌ 要自己写循环
离线消息 ✅ Broker 暂存 ❌ 断了就丢
消息保留 ✅ 新订阅者能拿最新 ❌ 不支持
QoS ✅ 0/1/2 三级保证 ❌ 没内建
头部大小 2 字节(最小) 2-14 字节
适用 IoT 设备 Web 实时通信

3.4 HTTP vs MQTT 在本项目的取舍

业务 协议 原因
拿设备列表 HTTP 静态数据,一次性
拿设备初始状态 MQTT 一次拿全设备当前状态
订阅设备状态变化 MQTT 实时推送
控制设备 MQTT 实时双向

原则:静态/低频用 HTTP,实时/高频用 MQTT。


四、实现架构

┌─────────────────────────────────────────────────────────────────┐
│                  智能家居模块完整架构                               │
└─────────────────────────────────────────────────────────────────┘

                          手机 App
                              │
                              ▼
              ┌───────────────────────────────┐
              │  withDevice HOC(核心)            │
              │  - 接收 device + control            │
              │  - connect Redux 拿状态            │
              │  - 注入 onControl 函数              │
              └───────────────────────────────┘
                              │
                  用户操作 │ 设备渲染
                              ▼
              ┌───────────────────────────────┐
              │  设备组件(AC/Curtain/DimmingLight..)│
              │  - 只关心 UI 渲染                   │
              │  - 调用 this.props.onControl(...)   │
              └───────────────────────────────┘
                              │
                  onControl │ 乐观更新 + 双通道下发
                              ▼
              ┌────────────────────────────────────┐
              │  外网(99%):NB_SDK.exec(topic, data) │
              │       ↓ MQTT                       │
              │  阿里云 MQTT Broker                  │
              │       ↓                           │
              │  家里智能家居主机                      │
              │       ↓                           │
              │  设备执行 → 状态变化 → MQTT 上报 → │
              │  NB_SDK.on('message') → dispatch    │
              └────────────────────────────────────┘
                              │
                  设备状态最终回到 Redux
                              ▼
              ┌───────────────────────────────┐
              │  totalState.states[DEVICE_ID]    │
              │  UI 自动重渲染(PureComponent)     │
              └───────────────────────────────┘

五、核心实现:withDevice HOC

5.1 完整代码

// src/components/Device/HOC/Device.js
export default withDevice = (WrappedComponent) => {
   
  @connect(({
   totalState, home, intranet}) => ({
   
    states: totalState.states,        // ← 设备实时状态(来自 Redux)
    home,                              // ← 房屋列表 + 当前选中
    isIntranet: intranet.isIntranet,   // ← 是否内网模式
    intranetIp: intranet.intranetIp,
  }))
  class Component extends React.PureComponent {
   
    constructor(props) {
   
      super(props);
      const {
   home: {
   list, current}, device} = props;
      const home = list && list.find(item => item.id == current);
      this.topic = home && home.TOPIC;       // ← MQTT 主题
      this.device = device;                  // ← HOC 自己持有 device
    }

    onControl = (data) => {
   
      const {
   dispatch, intranetIp, isIntranet} = this.props;
      const device = this.device;

      data = {
   deviceId: '' + device.DEVICE_ID, ...data};

      // ① 乐观更新:UI 立即响应(0ms)
      dispatch({
   type: UPDATE_STATE, payload: data});

      // ② 调光灯亮度转 16 进制(协议要求)
      if (data.Brightness != null) {
   
        data.Brightness = data.Brightness.toString(16);
      }

      // ③ 双通道:内网走 HTTP,外网走 MQTT
      if (isIntranet) {
   
        Api.IntranetControlDevice(intranetIp, device.DEVICE_ID, data);
      } else {
   
        NB_SDK.exec(this.topic, {
   
          ...data,
          execMobile: global.phone,
          platform: IS_IOS ? 'iOS' : 'Android',
          appName: '星智家',
          appVersion: global.version,
        });
      }
    };

    render() {
   
      const {
   states, status, ...resetProps} = this.props;
      const state = states[device.DEVICE_ID] || {
   };
      return (
        <WrappedComponent
          device={
   device}                  // ← 透传
          onControl={
   this.onControl}       // ← 注入
          state={
   state}                    // ← 注入
          {
   ...resetProps}                  // ← 其他 props 透传
        />
      );
    }
  }
  return hoistNonReactStatics(Component, WrappedComponent);
};

5.2 HOC 的 4 个核心设计

设计 作用
乐观更新 UI 0ms 响应,不等云端
双通道 内网 HTTP / 外网 MQTT,根据 isIntranet 自动切换
Topic 隔离 每个房屋有自己的 TOPIC,避免指令串扰
PureComponent + hoistNonReactStatics 避免不必要渲染 + 保留静态方法

5.3 设备组件用法

// src/components/Device/AC.js
@withDevice
export default class AC extends PureComponent {
   
  setMode = mode => {
   
    this.props.onControl({
   Mode: mode});  // ← 调用 HOC 注入的
  };
  render() {
   
    const {
   device, state} = this.props;  // ← 从 HOC 透传
    return <View><Text>{
   device.NAME}</Text></View>;
  }
}

关键:8 种设备只用关心 UI,业务逻辑全部在 HOC 里。新增设备类型只需写 UI,零冗余。


六、完整调用流程

6.0 设备控制时序图

mermaid diagram

6.1 MQTT 初始化流程

用户登录成功
   ↓
Api.getHomesByToken(token)
   ↓
返回房屋列表(含 TOPIC、HOME_ID、hostId)
   ↓
dispatch(saveHomes(homes)) → Redux home.list
   ↓
dispatch(changeCurrentHome(homeId))
   ↓
dispatch(fetchTotalInfoAndStatus)
   ↓
┌────────────────────────────────────────────────────┐
│ 1. Api.getMqttConnectInfo(hostId)                  │
│    → 返回 {uri, userName, password, isEmqxCloud}    │
│ 2. NB_SDK.initConnection({uri, clientId, ...})     │
│ 3. NB_SDK.connect({userName, password, ...})       │
│ 4. onConnected 回调                                │
│    ├─ Api.getHostConfig(HOME_ID) → 拿设备列表       │
│    ├─ NB_SDK.fetchDeviceStates(topic) → 拿设备状态   │
│    └─ NB_SDK.connection.subscribe(topic) → 订阅变化  │
└────────────────────────────────────────────────────┘

6.2 设备控制流程

用户点击"调光灯 80%"
   ↓
DeviceCard 点击 → onModal({type, device})
   ↓
Home.js setState({modalProps: {type: 'DimmingLight', device}})
   ↓
<DimmingLight {...modalProps} />  (被 withDevice 包装)
   ↓
HOC 接 props(device, type...)
   ↓
用户操作:调用 this.props.onControl({Brightness: 80})
   ↓
HOC.onControl:
   ├─ dispatch UPDATE_STATE → Redux → UI 立即变 80%(乐观更新)
   └─ NB_SDK.exec(topic, {Brightness: '50'})  ← 16 进制
       ↓
       MQTT Broker → 主机 → 设备 → 状态变化 → MQTT 上报
       ↓
       NB_SDK.on('message') → dispatch UPDATE_STATE → UI 最终一致

七、4 个关键技术参数

参数 来源 作用
uri Api.getMqttConnectInfo(hostId) 返回 MQTT Broker 地址(wss://...)
clientId 自己生成(项目用 GID_newbest@@@XZJ_${timestamp}) 客户端唯一标识
username/password Api.getMqttConnectInfo 返回 MQTT 鉴权
TOPIC 房屋对象里(home.TOPIC) MQTT 主题前缀

TOPIC 是登录返回的房屋列表里就有的,不需要连接 MQTT 后获取。


八、其他项目想做这个功能怎么落地

8.1 技术选型建议

场景 推荐方案
几百-几千设备 MQTT(EMQX / Mosquitto) + Redis 持久化
几万设备 MQTT + Kafka 削峰 + 分级 Topic
设备数 < 100 甚至 WebSocket 都行
需要音视频通话 MQTT + WebRTC(不要混 MQTT 音视频)

8.2 协议设计

Topic 命名规范(推荐分层):

{产品线}/{家庭ID}/{设备类型}/{设备ID}/{动作}
例:smarthome/home_001/light/light_001/cmd
    smarthome/home_001/light/light_001/status

Message 格式(推荐 JSON):

{
   
  "deviceId": "light_001",
  "POWER": "ON",
  "Brightness": 80,
  "timestamp": 1692345678901,
  "execMobile": "13800138000"
}

8.3 实施步骤

第 1 步:搭 MQTT Broker
  - 本地测试:docker run -d -p 1883:1883 eclipse-mosquitto
  - 生产环境:EMQX Cloud / 阿里云 MQTT

第 2 步:定义 Topic 规范 + Message 格式
  - 文档化所有设备类型的字段
  - 定义 Topic 模板

第 3 步:实现设备端 SDK
  - ESP32 / STM32 等用 C SDK(MQTT 库)
  - 订阅自己 Topic 的 cmd 主题
  - 控制硬件 + 上报 status

第 4 步:实现 App 端 SDK
  - RN:react-native-mqtt-paho 或自研
  - 订阅设备 status 主题
  - publish 控制指令

第 5 步:实现控制逻辑
  - 乐观更新(先变 UI)
  - 异步下发指令
  - 订阅推送保证最终一致

第 6 步:HOC 抽象(如有多种设备)
  - 抽出 withXxx 高阶组件
  - 新增设备类型零冗余

第 7 步:监控 + 告警
  - Broker 连接数 / 消息 QPS / 错误率
  - 设备离线检测

8.4 注意事项

注意点 说明
TOPIC 必须后端预分配 App 端不能自己生成,否则串户
消息体不要太大 MQTT 限制 256KB,设备列表走 HTTP
QoS 级别 控制指令用 QoS 1(至少一次),状态推送用 QoS 0(最多一次)
ClientId 必须唯一 否则两个 App 连会被踢
心跳 + 重连 MQTT Broker 默认 60s 心跳,断线要自动重连
离线消息保留 设置 cleanSession: false,离线消息保留
安全 TOPIC 不要用敏感信息,用 UUID 即可
频控 高频控制指令要节流,防止设备执行不过来

九、本项目特殊点(避免踩坑)

坑 解决方案
8 设备代码重复 用 withDevice HOC 抽象
UI 与状态不同步 乐观更新 + 订阅最终一致
调光灯 10/16 进制 dispatch 用 10 进制,NB_SDK 用 16 进制
多个家庭切换 每个家庭独立 TOPIC + 独立 MQTT 连接
设备状态推送频繁 500ms 节流合并更新(项目 home.js 里实现)
多端同时控制同一设备 Redux 是单一数据源,最后一次 dispatch 生效

十、面试问答速记

Q1:智能家居为什么用 MQTT 不用 HTTP?

  • MQTT Pub/Sub 天然支持一对多(一个设备状态变化推送所有订阅者)
  • 内置 QoS 保证消息不丢
  • 头部小(2 字节),IoT 设备带宽友好
  • HTTP 是请求-响应,实时推送需要客户端轮询,效率低

Q2:8 种设备怎么共享一套控制逻辑?
用 withDevice HOC。HOC 内部 connect Redux 拿公共数据,提供 onControl 函数。8 种设备组件只需写 UI,业务逻辑统一。

Q3:乐观更新怎么实现的?

// HOC.onControl
dispatch({
   type: UPDATE_STATE, payload: data});  // ① 立即更新 Redux
NB_SDK.exec(topic, data);                         // ② 异步下发指令
// ③ 设备响应 → MQTT 推送 → 回调 → dispatch UPDATE_STATE(最终一致)

Q4:MQTT Topic 怎么设计?

  • 按业务分层:{产品线}/{家庭ID}/{设备类型}/{设备ID}/{动作}
  • App 端不生成 Topic,必须后端预分配
  • 用 UUID 避免敏感信息泄露

Q5:项目里 MQTT 和 HTTP 是怎么分工的?

  • HTTP:拿设备列表、用户权限、房屋信息(静态/低频数据)
  • MQTT:拿设备状态、订阅状态变化、控制设备(实时/高频数据)

十一、一句话总结

智能家居 = MQTT(实时控制 + 推送) + HTTP(静态数据) + Redux(状态总线) + HOC(逻辑复用) + 乐观更新(0ms 响应)。

十二、系统分层架构

整个项目的部署架构 4 层组成(和云对讲共用):

mermaid diagram


系列文章:① 云对讲模块 ② 智能家居模块(本文)

相关文章
|
2天前
|
人工智能 安全 IDE
自主编码智能体上手|Qoder CN v1.4.1 深度实战,本地环境搭建、多文件工程开发与企业私有化部署
Qoder CN v1.4.1最大的价值,是把AI编码从“代码片段生成”升级为完整Agent式工程任务执行。借助Quest任务引擎、RepoWiki记忆知识库、MCP工具扩展、Hooks安全机制,开发者只需要描述业务需求,智能体自主完成需求拆解、多文件修改、命令执行、测试验证完整链路。同时兼容CLI、IDE、插件多种形态,深度对接百炼平台各类订阅方案,既可以满足个人开发者提升开发效率,也具备完整权限管控、安全拦截、团队知识库能力,支撑企业规模化落地AI研发。
86 0
|
3天前
|
人工智能 自然语言处理 测试技术
Google 开源 ARTEMIS:AI Agent 如何接管 Android 真机测试?
Google开源的ARTEMIS是一款AI驱动的Android自动化测试框架,支持自然语言指令、跨App长流程操作、多模态控件识别(Accessibility+OCR+视觉模型),原生集成MCP协议,可无缝接入Antigravity等AI编程环境,实现“描述目标→自主规划→真机执行→结果分析”闭环,标志着移动端测试迈向AI Agent时代。
|
2天前
|
人工智能 程序员 开发者
请问免费的通义灵码收费后最低档定价59元/月是怎么来的?
请问免费的通义灵码收费后最低档定价59元/月是怎么来的
|
3天前
|
人工智能 数据挖掘 开发工具
RAG 不一定需要大模型重排:Jev 能不能做 Context Filtering?
RAG中检索易召回冗余内容,Jev作为决策层可精准筛选高相关Chunk,替代简单Top-K输入。它支持多维度判断(如版本、时效性),提升Context质量与LLM答案准确性,降低幻觉与Token成本。(239字)
RAG 不一定需要大模型重排:Jev 能不能做 Context Filtering?
|
2天前
|
缓存 API 开发工具
企业级大模型落地指南:Qwen3.8‑Max/Flash/Omni 能力拆解,RAG 知识库、微调、智能体开发与 API 调用全流程
目前生成式AI已经从简单问答对话,进化为可以处理超长文档、图文音视频混合输入、自主拆解目标完成多步骤业务的通用智能底座。通义千问Qwen3.8完整家族形成了分层能力矩阵,覆盖旗舰推理、均衡通用、高速高吞吐、原生全模态视听、专项编程多类基座,既可以普通用户网页端直接交互体验,也可以通过百炼平台API集成进业务系统,同时开放开源权重,支持本地私有化部署,覆盖个人创作者、独立开发者、中小企业、大型政企的差异化诉求。
111 0
|
2天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
932 1
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
3天前
|
数据采集 监控 网络协议
数据采集突然变慢,先别重启:一套四层排障清单
本文分享跨境电商数据采集任务“卡死”排查实战:从吞吐曲线区分“变慢”与“卡死”,依次排查站点限流(含空壳页陷阱)、出口IP池健康度(重试风暴)、代码资源泄漏/无效开销、环境及下游瓶颈。强调打点前置、单变量验证与固定排查顺序,助你快速定位真因。
|
11小时前
|
人工智能 监控 API
阿里云百炼 Token Plan 版本对比:Credits 额度机制、支持模型与适用场景梳理
随着大模型应用开发、AI编程、多模态内容生成需求持续增长,越来越多开发者开始使用百炼平台进行模型调用。Token Plan作为百炼推出的订阅制模型调用方案,采用Credits统一计量的模式,不再需要单独核算每一款模型输入、输出Token单价,文本对话、图像生成、视频生成、语音识别、联网搜索、代码解释器等能力全部统一消耗Credits,极大简化了多模态混合场景下的成本核算工作。Token Plan分为个人版和团队版两大分支,两个版本在额度周期、管理能力、数据安全、高峰期服务保障、支持模型范围上存在明显差异,很多用户在订阅前会陷入版本选择的难题,盲目订阅很容易出现额度不够、团队权限无法管理、高峰期
29 0
|
3天前
|
存储 弹性计算 人工智能
2026阿里云服务器租用全解:流程、优惠、省钱技巧助成本直降
本文针对新手用户梳理2026年阿里云服务器完整租用流程,涵盖账号注册、实名认证、参数配置、下单支付全步骤,详解38元/年轻量服务器、99元/年经济型e实例等特惠机型权益,同步拆解企业专属补贴、实例专项折扣、续费同价规则,配套代金券使用、长周期锁价等实操省钱技巧,帮助用户以最优成本完成上云部署,最高可节省超50%上云开支。
|
11小时前
|
存储 弹性计算 关系型数据库
阿里云最新活动入口在哪?新人云产品大促福利汇总与选购推荐
总而言之,阿里云大促的活动入口分布在官网专场、控制台首页、产品特惠详情页三处,新人登录账号之后优先在主会场领取代金券,再挑选首购特惠机型。在下单前,除了网页查看规格,也可以借助CLI工具查询实例信息,做好前期规划,合理利用新人权益,以较低成本完成上云学习和小型业务部署。
24 0