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


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

相关文章
|
3天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
5337 6
|
1天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
825 0
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
15天前
|
人工智能
千问办公官网入口:阿里AI办公QwenWork产品页和免费网页端链接
千问办公官网含两大入口:一是网页端(qwenwork.cn),即开即用,支持浏览器直接访问;二是阿里云产品页 https://t.aliyun.com/U/JNKJuO 提供免费/付费版详情、功能介绍及使用指南。
|
15天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
|
14天前
|
IDE 开发工具
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
Qoder国际版上线全新内置大模型Sonus(/ˈsoʊnəs/),全球领先,专精超长任务执行与电脑操作(Computer Use)。配合Qoder桌面端0.2.3版本,可自主完成编程、金融建模、科研及表格制作等复杂工作。现全面支持Qoder全系产品,效率提升3.2倍。
1732 8
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
|
16天前
|
缓存 人工智能 自然语言处理
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
本文是阿里云百炼平台Qwen3.8-Flash大模型的选型接入指南,作为兼顾性能与响应速度的高性价比多模态模型,它支持百万级上下文窗口、全场景多模态输入与完整智能体能力矩阵,适配编程辅助、智能体协作等核心场景。文中同步梳理了最新下调的阶梯定价、夜间4折等优惠活动,搭配OpenAI兼容流式调用示例,帮助开发者低成本快速落地高并发AI应用。
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
|
9天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1066 1
|
15天前
|
人工智能 API 内存技术
刚刚 DeepSeek V4.1 Flash 开启内测,1 分钟教你用上!
刚刚 DeepSeek 内测群发布了 DeepSeek V4.1 Flash 中间版本内测的消息,这次的模型采用了新的结构,原生支持多模态、能力更强、速度更快、且成本更低。
2012 15