云计算百科
云计算领域专业知识百科平台

MQTT智能插座如何接入Home Assistant,从零开始完整工程实现(Java+Angular)

GemeOpen GSPM1B × Home Assistant × Java(Spring Boot) + Angular Demo

把 GemeOpen GSPM1B 智能转换器插座 接入 Home Assistant,实现 通断电控制 与 电压 / 电流 / 功率 / 累计用电量 采集;并附一套 Java(Spring Boot) + Angular 的完整自研 Demo。

面向程序员初学者:文档从零讲起,每一步都可直接复制执行。 本工程与 Python + React 版为姊妹工程,MQTT 协议与接口契约完全一致。


开发者文档

https://www.smart-bird.cn/doc/product/GSPM/device/GSPM1B/command

源码下载地址

https://smart-bird-oss.smart-bird.cn/document/2026/09/28/1127495749059821.zip

✨ 能力一览

能力Home Assistant自研 Demo
通断电开关 ✅ switch ✅ Web 开关
实时电压/电流/功率 ✅ sensor ✅ 实时卡片
累计用电量 ✅ sensor(能源面板) ✅ 卡片
历史曲线 ✅ History graph ✅ SVG 折线
实时推送 — ✅ WebSocket
需要写代码 ❌ 仅 YAML ✅ Java + Angular

🏗 架构

GSPM1B ──MQTT──► Mosquitto Broker ◄──MQTT── Home Assistant (路径 A, 零代码)
▲
└──MQTT── Java 后端(Spring Boot) ──REST/WS── Angular 前端 (路径 B, 自研 Demo)

🧰 技术栈

层技术
设备通信 MQTT(Eclipse Paho Java Client)
后端 Java 17 · Spring Boot 3.2 · 原生 WebSocket · Maven
前端 Angular 17(standalone)· RxJS · 原生 SVG 图表
部署 Docker Compose · Nginx · Eclipse Mosquitto 2

📁 目录结构

gemeopen-ha-java-demo/
├── README.md # 本文件
├── docker-compose.yml # 一键启动 Mosquitto + 后端 + 前端
├── docs/ # 全部中文文档
│ ├── 00-architecture.md # 架构与接口契约(基准)
│ ├── 01-overview.md # 方案总览(先读)
│ ├── 02-device-setup.md # 设备端 MQTT 配置
│ ├── 03-homeassistant.md # Home Assistant 接入
│ ├── 04-backend.md # Java 后端说明
│ ├── 05-frontend.md # Angular 前端说明
│ ├── 06-deploy-ops.md # 部署与运维
│ └── 07-troubleshooting.md # 排错手册
├── homeassistant/ # HA 配置片段
│ ├── mqtt-gspm1b.yaml # switch + sensor 实体
│ └── dashboard.yaml # Lovelace 仪表盘
├── backend/ # Java Spring Boot 后端
│ └── src/main/java/com/gemeopen/demo/
│ ├── mqtt/MqttClientService.java # MQTT 连接/解析/下发
│ ├── store/DeviceStore.java # 状态与历史
│ ├── ws/TelemetryWebSocketHandler.java
│ └── web/DeviceController.java # REST 端点
├── frontend/ # Angular 前端
│ └── src/app/
│ ├── services/{api,telemetry}.service.ts
│ └── components/{switch-control,realtime-metrics,energy-total,history-chart}/
├── scripts/ # 设备配置脚本
│ ├── configure_device.py
│ └── device_switch.example.json
└── mosquitto/ # MQTT Broker 配置
└── mosquitto.conf

🚀 快速开始

# 1) 启动 Broker + 后端 + 前端
docker compose up -d –build

# 2) 把设备切换到你的 Broker(编辑 scripts/device_switch.json 后执行)
cd scripts && cp device_switch.example.json device_switch.json
python3 configure_device.py –config device_switch.json
# 成功后给设备断电重启

# 3) 开启设备定时上报(示例 15 秒)
mosquitto_pub -h <你的IP> -p 1883 \\
-t 'gemeopen/gspm1b/<MAC>/command' \\
-m '{"messageId":"1","timerEnable":1,"timerInterval":15,"type":"setting"}'

# 4) 打开自研 Demo
# http://<你的IP>:8080

# 5) 接入 Home Assistant:见 docs/03-homeassistant.md

📖 文档路线(建议顺序)

  • [01 · 方案总览] 01-overview.md
  • [02 · 设备端配置] 02-device-setup.md
  • 按需选择:
    • Home Assistant 用户 → [03 · HA 接入] 03-homeassistant.md
    • Java 开发者 → [04 · Java 后端] 04-backend.md、[05 · Angular 前端] 05-frontend.md
  • 上线 → [06 · 部署与运维] 06-deploy-ops.md
  • 遇问题 → [07 · 排错手册] 07-troubleshooting.md
  • ⚠️ 三个最重要的提醒

  • 主题语义反直觉:设备 publish 主题是你要订阅的;设备 subcribe 主题是你要发布指令的。
  • Broker 地址设备要能访问:设备端填的必须是你服务器的局域网 IP / 公网域名,不能是 localhost。
  • 切换 MQTT 后需重启设备生效。
  • 🔧 环境要求

    组件版本
    JDK 17+
    Maven 3.8+
    Node / npm 18+ / 20+(Angular 17 要求 Node ≥ 18.13)
    Docker / Compose 24+
    Home Assistant 任意近期版本

    📄 说明

    • 本工程为教学示例,生产使用请参考 [06 · 部署与运维] 06-deploy-ops.md 的安全清单。
    • 设备型号协议以 GemeOpen 官方开发文档为准。

    00-architecture.md

    00 · 架构与接口契约(基准文档)

    本文是整个工程的基准契约。所有子模块(Home Assistant 配置、Python 后端、React 前端)都必须严格遵守本文件定义的主题名、消息格式与 API 字段名。

    1. 总体架构

    ┌─────────────┐ MQTT ┌──────────────────┐ MQTT ┌──────────────────────┐
    │ GSPM1B │ ────────► │ Mosquitto │ ◄──────── │ Home Assistant │
    │ 智能插座 │ ◄──────── │ (自建 Broker) │ ────────► │ MQTT 集成 │
    └─────────────┘ │ │ │ switch + sensor │
    │ │ └──────────────────────┘
    │ │ MQTT ┌──────────────────────┐
    │ │ ◄──────── │ Python 后端 (FastAPI)│
    │ │ ────────► │ MQTT ⇄ REST/WebSocket│
    └──────────────────┘ └──────────┬───────────┘
    │ HTTP / WS
    ┌──────────▼───────────┐
    │ React 前端 (Vite) │
    └──────────────────────┘

    两条并行的消费路径(互不影响):

    • 路径 A(面向最终用户):Home Assistant 直接通过 MQTT 集成接入,无需自研代码。
    • 路径 B(面向二次开发):Python + React Demo,演示如何自建一套 Web 控制台。

    2. 设备通信配置(出厂默认 → 自建 Broker)

    设备出厂默认连接 GemeOpen 厂家 MQTT 服务器。接入自建 Broker 需在原厂通道下发 setting-mqtt 指令(详见 docs/02-device-setup.md)。

    setting-mqtt 指令:

    {
    "clientId": "gspm1b-28372fcbbbb8",
    "messageId": "20260520120000001",
    "password": "device-pass",
    "port": "1883",
    "protocol": "mqtt",
    "publish": "gemeopen/gspm1b/28372fcbbbb8/report",
    "server": "192.168.1.10",
    "subcribe": "gemeopen/gspm1b/28372fcbbbb8/command",
    "type": "custom",
    "username": "device"
    }

    ⚠️ 语义(易错,务必按此理解)

    • publish = 设备发布数据的主题 → 服务端订阅它来接收上报(本项目记作 reportTopic)。
    • subcribe = 设备订阅的主题 → 服务端发布指令到它来控制设备(本项目记作 commandTopic)。

    3. MQTT 主题约定

    名称默认值方向
    reportTopic gemeopen/gspm1b/{mac}/report 设备 → 服务端(上行,服务端订阅)
    commandTopic gemeopen/gspm1b/{mac}/command 服务端 → 设备(下行,服务端发布)

    HA 与 Python 后端使用同一套主题;两者各自用独立 clientId 连接 Broker。

    4. 指令与消息契约(JSON)

    4.1 下行指令(服务端 → 设备,发到 commandTopic)

    功能payload说明
    通断电控制 {"key":1,"messageId":"<id>","type":"event"} key=1 通电,key=0 断电
    查询实时电量 {"messageId":"<id>","type":"statistic"} 触发一次实时数据回传
    设置上报频率 {"messageId":"<id>","timerEnable":1,"timerInterval":15,"type":"setting"} 自动上报开关与周期(5~86400 秒)
    获取设备信息 {"messageId":"<id>","type":"info"} 返回固件、IP、信号等
    恢复出厂 {"messageId":"<id>","system":"reset","type":"setting"} 谨慎

    4.2 上行消息(设备 → 服务端,来自 reportTopic)

    A. 定时自动上报(device-timer-task)

    {
    "commandName": "device-timer-task",
    "mac": "28372fcbbbb8",
    "messageId": "",
    "source": "auto",
    "key": 1,
    "voltage": 226.024,
    "current": 0.501,
    "power": 113.4,
    "energy": 25.047
    }

    B. 指令响应(controller-event / info-statistic / info-all)

    {
    "commandName": "info-statistic",
    "mac": "28372fcbbbb8",
    "messageId": "20260520120000001",
    "source": "command",
    "key": 1,
    "voltage": 226.024,
    "current": 0.501,
    "power": 113.4,
    "energy": 25.047
    }

    字段语义与单位

    设备字段含义单位归一化字段(本项目统一命名)
    key 通断电状态(1 通电 / 0 断电) — relayOn (boolean)
    voltage 电压 V voltageV
    current 电流 A currentA
    power 有功功率 W activePowerW
    energy 累计用电量(断电不归零) kW·h energyKwh
    signal 信号强度 dBm signalDbm
    commandName 指令名 — commandName
    source 来源 command/auto/button — source

    5. Python 后端 API 契约(供 React 前端调用)

    Base URL:http://<host>:8000

    5.1 GET /api/health

    { "status": "ok", "mqttConnected": true, "deviceOnline": true }

    5.2 GET /api/device

    返回当前设备状态快照 DeviceState:

    {
    "mac": "28372fcbbbb8",
    "online": true,
    "relayOn": true,
    "voltageV": 226.024,
    "currentA": 0.501,
    "activePowerW": 113.4,
    "energyKwh": 25.047,
    "signalDbm": –75,
    "source": "auto",
    "lastUpdate": 1787992225
    }

    lastUpdate 为秒级 Unix 时间戳;无数据时各数值字段为 null。

    5.3 POST /api/device/switch

    请求:{ "on": true } → 响应:{ "success": true, "state": <DeviceState> }

    5.4 POST /api/device/refresh

    触发一轮 info + statistic 查询,响应:{ "success": true }

    5.5 GET /api/device/history?limit=200

    返回采样历史(时间升序):

    [ { "ts": 1787992225, "voltageV": 226.024, "currentA": 0.501, "activePowerW": 113.4, "energyKwh": 25.047, "relayOn": true } ]

    5.6 GET /api/config

    返回非敏感运行配置:{ "reportTopic": "…", "commandTopic": "…", "mac": "…" }

    5.7 WS /ws/telemetry

    WebSocket,每次设备状态更新时推送一帧 DeviceState(与 5.2 同结构)。

    6. 后端环境变量(.env)

    变量默认值说明
    MQTT_HOST 127.0.0.1 Broker 地址
    MQTT_PORT 1883 Broker 端口
    MQTT_USERNAME backend 后端连接 Broker 的用户名
    MQTT_PASSWORD backend-pass 后端密码
    MQTT_CLIENT_ID gemeopen-backend 后端 clientId(唯一)
    MQTT_REPORT_TOPIC gemeopen/gspm1b/+/report 订阅(+ 通配单设备)
    MQTT_COMMAND_TOPIC gemeopen/gspm1b/{mac}/command 发布指令
    DEVICE_MAC 28372fcbbbb8 目标设备 MAC
    HISTORY_SIZE 2000 内存中保留的采样条数
    CORS_ORIGINS * 允许的前端来源

    7. 前端约定

    • 构建工具:Vite + React 18
    • 状态来源:REST 轮询(/api/device)+ WebSocket(/ws/telemetry)实时推送
    • API Base:环境变量 VITE_API_BASE(默认 http://localhost:8000)
    • 展示内容:通断电开关、电压/电流/功率实时值、累计用电量、在线状态、简易历史曲线

    8. 目录结构

    gemeopen-ha-demo/
    ├── README.md # 总览与快速开始
    ├── docker-compose.yml # Mosquitto + 后端 + 前端
    ├── docs/
    │ ├── 00-architecture.md # 本文件(契约)
    │ ├── 01-overview.md # 方案总览(初学者向)
    │ ├── 02-device-setup.md # 设备端 MQTT 配置
    │ ├── 03-homeassistant.md # Home Assistant 接入
    │ ├── 04-backend.md # Python 后端说明
    │ ├── 05-frontend.md # React 前端说明
    │ ├── 06-deploy-ops.md # 部署与运维
    │ └── 07-troubleshooting.md # 排错手册
    ├── homeassistant/ # HA 配置片段
    ├── backend/ # Python FastAPI 后端
    ├── frontend/ # React 前端
    ├── scripts/ # 设备配置脚本
    └── mosquitto/ # Broker 配置

    01-overview.md

    01 · 方案总览(Java + Angular 版)

    1. 这个项目要解决什么?

    把 GemeOpen GSPM1B 智能转换器插座 接入 Home Assistant,实现:

    • ✅ 通断电控制(开 / 关)
    • ✅ 实时电压、电流、功率采集
    • ✅ 累计用电量查询
    • ✅(加分)一套 Java(Spring Boot) + Angular 的自研 Demo

    本工程与 Python + React 版是「姊妹工程」,MQTT 协议、主题、接口契约完全一致,只是把二次开发的技术栈换成了 Java + Angular。

    2. 两条接入路径

    ┌──────────────────────────────────────────┐
    GSPM1B ──MQTT─┤ Mosquitto Broker │
    (设备) └───────┬───────────────────────┬───────────┘
    │ MQTT │ MQTT
    ┌────────▼─────────┐ ┌────────▼──────────────┐
    │ 路径 A │ │ 路径 B │
    │ Home Assistant │ │ Java 后端 (Spring Boot)│
    │ MQTT 集成 │ │ ⇅ REST / WebSocket │
    │ switch + sensor │ │ Angular 前端 │
    └──────────────────┘ └────────────────────────┘
    无需写代码 适合 Java 开发者学习

    3. 技术栈

    层技术
    设备通信 MQTT(Eclipse Paho Java Client)
    后端 Java 17 + Spring Boot 3.2 + Spring Web + 原生 WebSocket
    前端 Angular 17(standalone components)+ RxJS + 原生 SVG 图表
    Broker Eclipse Mosquitto 2
    部署 Docker / Docker Compose + Nginx

    4. 快速开始(5 步)

    # ① 启动 Broker + 后端 + 前端
    cd gemeopen-ha-java-demo
    docker compose up -d –build

    # ② 把设备切到你的 Broker(编辑 scripts/device_switch.json 后执行)
    cd scripts && cp device_switch.example.json device_switch.json
    python3 configure_device.py –config device_switch.json
    # 成功后给设备断电重启

    # ③ 让设备定时上报(示例 15 秒)
    mosquitto_pub -h <你的IP> -p 1883 -t 'gemeopen/gspm1b/<MAC>/command' \\
    -m '{"messageId":"1","timerEnable":1,"timerInterval":15,"type":"setting"}'

    # ④ 打开自研 Demo:浏览器访问 http://<你的IP>:8080

    # ⑤ 接入 Home Assistant:见 docs/03-homeassistant.md

    5. 文档导航

    文档内容
    [02 · 设备端配置] 02-device-setup.md 把设备指向自建 Broker(必读)
    [03 · Home Assistant 接入] 03-homeassistant.md HA 集成 + 实体 + 仪表盘 + 自动化
    [04 · Java 后端] 04-backend.md Spring Boot + MQTT 代码说明
    [05 · Angular 前端] 05-frontend.md 组件结构、服务、运行方式
    [06 · 部署与运维] 06-deploy-ops.md 三种部署方式、备份、监控
    [07 · 排错手册] 07-troubleshooting.md 按症状排查
    [00 · 架构与契约] 00-architecture.md 主题/消息/API 契约(基准)

    6. 关键概念 30 秒速通

    • MQTT:轻量发布/订阅协议。设备“发布”数据到“主题”,程序“订阅”该主题即收到。
    • Broker(Mosquitto):消息中转站;设备、HA、后端都连它。
    • Topic:类似“频道名”,本项目用 gemeopen/gspm1b/<mac>/report(设备发)与 …/command(设备收)。
    • Home Assistant:开源智能家居平台,通过 MQTT 集成把设备变成可控“实体”。

    ⚠️ 最容易踩的坑:文档里 publish / subcribe 与直觉相反——设备的 publish 主题是你要订阅的,subcribe 主题是你要发布指令的。详见 [02] 02-device-setup.md 。


    02-device-setup.md

    02 · 设备端 MQTT 配置(把 GSPM1B 指向自建 Broker)

    目标:让 GSPM1B 把数据发到你自己的 MQTT Broker(Mosquitto),这样 Home Assistant 和 Python 后端才能读到数据、发出控制指令。

    1. 为什么需要这一步?

    GSPM1B 出厂时默认连接 GemeOpen 厂家测试服务器(mqtt.smart-bird.cn:1883),免费供调试。要让 HA 接管,就需要把设备改为连接你自己的 Broker。

    设备提供了专门的指令 setting-mqtt(自定义 MQTT 参数)来完成这件事。

    2. 准备工作

    你需要先知道设备当前所在 Broker 的连接信息,通过设备指令 info-protocol 获取:

    字段含义用途
    server / port 当前 Broker 地址/端口 连接它来下发切换指令
    username 当前 Broker 用户名 连接凭据
    publish 设备发布主题(服务端订阅它收数据) 记为 report_topic
    subcribe 设备订阅主题(服务端向它发指令) 记为 command_topic

    ⚠️ 注意 publish / subcribe(原文拼写)的语义与直觉相反:

    • 设备把数据 publish 到 publish 主题 → 所以你要订阅它。
    • 设备 subscribe 了 subcribe 主题 → 所以你要往它发布指令。

    获取方式:

  • GemeOpen 控制台:登录后在设备详情页查看;
  • 设备指令:往设备发 {"type":"info","messageId":"…"}(info-protocol 需按其文档说明触发),返回里含上述字段;
  • 向厂家/销售索取:测试服务器的连接凭据(username/password)通常需要厂家提供。
  • 3. 一键切换脚本

    工程提供了脚本 scripts/configure_device.py:

    cd scripts
    cp device_switch.example.json device_switch.json
    # 编辑 device_switch.json,填入 current(当前 Broker)与 target(你的自建 Broker)
    pip install paho-mqtt==2.1.0
    python3 configure_device.py –config device_switch.json

    配置模板关键字段:

    {
    "current": { // 设备“现在”所在的 Broker
    "server": "mqtt.smart-bird.cn",
    "port": 1883,
    "username": "<平台用户名>",
    "password": "<平台密码>",
    "report_topic": "<info-protocol 的 publish>",
    "command_topic": "<info-protocol 的 subcribe>"
    },
    "target": { // 要切换到的“自建” Broker
    "server": "192.168.1.10", // 必须设备网络可达
    "port": 1883,
    "username": "device",
    "password": "device-pass",
    "client_id": "gspm1b-28372fcbbbb8",
    "publish_topic": "gemeopen/gspm1b/28372fcbbbb8/report",
    "subcribe_topic": "gemeopen/gspm1b/28372fcbbbb8/command"
    }
    }

    脚本会:连接当前 Broker → 向 command_topic 发布 setting-mqtt → 等待设备回执。

    成功后会提示:

    ✅ 设备已接受新的 MQTT 配置。
    请给设备【断电重启】,或发送 controller-restart 指令,使配置生效。

    4. 使配置生效

    setting-mqtt 需要重启才生效:

    • 断电重启:拔掉设备再上电(最简单);
    • 软重启:向设备发 {"messageId":"…","system":"restart","type":"setting"}(controller-restart)。

    5. 验证设备已切换

    在你的 Broker 上用任意 MQTT 客户端订阅:

    mosquitto_sub -h 192.168.1.10 -p 1883 -u device -P device-pass \\
    -t 'gemeopen/gspm1b/28372fcbbbb8/report' -v

    若设备按上报周期持续吐出 JSON(含 voltage/current/power/energy/key),说明切换成功 🎉。

    6. 没有厂家凭据怎么办?

    • 方案 A(推荐):联系 GemeOpen 获取测试服务器凭据,用脚本切换;
    • 方案 B:设备支持内网 HTTP 控制(固件 2.0.0+),可在设备所在局域网内直接配置(具体接口以设备文档为准);
    • 方案 C:先用厂家默认服务器调试,跑通 scripts/ 与后端逻辑后,再切换。

    7. 主题与设备 MAC 的对应关系

    建议按设备 MAC 规划主题,便于多设备管理:

    gemeopen/gspm1b/<mac>/report # 设备上报(你订阅)
    gemeopen/gspm1b/<mac>/command # 设备指令(你发布)

    后端的 MQTT_REPORT_TOPIC 默认用通配符 gemeopen/gspm1b/+/report,可同时接收多台设备。


    03-homeassistant.md

    03 · Home Assistant 接入

    面向初学者,从零把 GSPM1B 接入 Home Assistant,实现通断电控制 + 实时电流/电压/功率采集 + 累计用电量。

    1. 整体思路(先看这张图)

    GSPM1B ──MQTT──► Mosquitto Broker ◄──MQTT── Home Assistant
    (设备) (你的服务器) (MQTT 集成)

    Home Assistant 通过 MQTT 集成连接你的 Mosquitto,再用一份 YAML 把设备消息映射成实体:

    • switch(开关)→ 控制通断电
    • sensor(传感器)→ 电压 / 电流 / 功率 / 累计用电量 / 信号

    2. 前置条件

    项要求
    Home Assistant 任意安装方式(HAOS / Docker / Supervised / Core)
    MQTT Broker Mosquitto(本工程 mosquitto/ + docker-compose.yml 已提供)
    设备 GSPM1B 已按 [02 · 设备端配置] 02-device-setup.md 指向你的 Broker
    设备 MAC 后面配置中所有 <MAC> 都要替换成它

    3. 步骤一:准备 Mosquitto Broker

    3.1 用本工程一键启动(推荐)

    cd gemeopen-ha-demo
    docker compose up -d mosquitto

    3.2 或使用 Home Assistant OS 的官方 Add-on

    设置 → 加载项 → 搜索 Mosquitto broker → 安装 → 启动。

    用哪种都行,只要设备、HA 都连同一个 Broker。

    4. 步骤二:在 HA 中添加 MQTT 集成

  • 设置 → 设备与服务 → 添加集成 → 搜索 MQTT;
  • Broker 填 mosquitto 的地址(Docker 场景填宿主机 IP,如 192.168.1.10)、端口 1883;
  • 填入 Mosquitto 的用户名/密码(见 mosquitto/mosquitto.conf 与 docker-compose.yml);
  • 提交,集成显示“已连接”。
  • 5. 步骤三:添加实体配置

  • 把本工程的 homeassistant/mqtt-gspm1b.yaml 复制到 HA 配置目录(与 configuration.yaml 同级);
  • 编辑 mqtt-gspm1b.yaml,把 所有 <MAC> 替换为你的设备 MAC(小写,例如 28372fcbbbb8);
  • 在 configuration.yaml 中加入一行:
  • mqtt: !include mqtt–gspm1b.yaml

  • 开发者工具 → YAML → 检查配置 → 重启 HA。
  • 如果你更熟悉 UI:也可在设置 → 设备与服务 → MQTT → 通过“添加实体”逐个添加,参数与 YAML 一致。

    6. 步骤四:验证实体

    重启后,设置 → 设备与服务 → 实体,应能看到:

    实体 ID类型说明
    switch.gspm1b_switch switch 通断电开关
    sensor.gspm1b_voltage sensor 电压 (V)
    sensor.gspm1b_current sensor 电流 (A)
    sensor.gspm1b_power sensor 功率 (W)
    sensor.gspm1b_energy sensor 累计用电量 (kWh)
    sensor.gspm1b_signal sensor 信号强度 (dBm)

    测试:

    • 点 switch.gspm1b_switch 开/关,观察实物插座继电器是否动作;
    • 若传感器数值为“未知”,说明设备还没上报——检查:
    • 设备是否已切换到该 Broker(见 02 文档);
    • 是否已开启定时上报(见下节)。

    7. 步骤五:开启设备定时上报(让传感器持续更新)

    设备默认可能不主动汇报。给它下发一次“设置上报频率”指令即可(示例间隔 15 秒):

    mosquitto_pub -h 192.168.1.10 -p 1883 -u device -P device-pass \\
    -t 'gemeopen/gspm1b/28372fcbbbb8/command' \\
    -m '{"messageId":"1","timerEnable":1,"timerInterval":15,"type":"setting"}'

    之后 report 主题会每 15 秒收到一条 device-timer-task,HA 传感器随之更新。

    8. 步骤六:添加仪表盘

  • 设置 → 仪表盘 → 新建仪表盘(标题如“智能插座”);
  • 打开它 → 右上角编辑 → 添加卡片,按 homeassistant/dashboard.yaml 的内容添加:
    • 开关:Entities 卡片 → switch.gspm1b_switch
    • 电压/电流:Gauge 卡片
    • 功率/电量:Sensor 卡片(带迷你曲线)
    • 历史:History graph 卡片
  • 也可直接把 dashboard.yaml 的内容粘贴到“原始配置编辑器”。

    9. 步骤七(加分项):能源面板与自动化

    能源面板:累计用电量已设 device_class: energy + state_class: total_increasing,会自动出现在 设置 → 仪表盘 → 能源 → 添加用电设备。

    自动化示例:功率超过 2000W 时通知(configuration.yaml 或 UI 自动化):

    automation:
    – alias: "GSPM1B 功率过高提醒"
    trigger:
    – platform: numeric_state
    entity_id: sensor.gspm1b_power
    above: 2000
    for: "00:01:00"
    action:
    – service: persistent_notification.create
    data:
    title: "插座功率过高"
    message: "当前功率 {{ states('sensor.gspm1b_power') }} W"

    定时断电示例:

    – alias: "每天 23:30 自动断电"
    trigger:
    – platform: time
    at: "23:30:00"
    action:
    – service: switch.turn_off
    target:
    entity_id: switch.gspm1b_switch

    10. 常见问题速查

    现象排查
    switch 显示不可用 command_topic/state_topic 里的 <MAC> 是否替换正确;MQTT 集成是否连接
    开关能点但实物无反应 设备是否已切到该 Broker;command_topic 是否为设备的 subcribe
    传感器一直“未知” 未开启定时上报;或设备未上报;用 mosquitto_sub 抓包确认
    数值不变 上报间隔过大;或本地缓存未触发上报
    能源面板不显示 确认 state_class: total_increasing 已生效并已产生数据

    更多排错见 [07 · 排错手册] 07-troubleshooting.md 。


    04-backend.md

    04 · Java 后端(Spring Boot + MQTT)

    路径 B 的后端:订阅设备 MQTT 消息 → 归一化 → 通过 REST / WebSocket 提供给 Angular 前端。

    1. 文件结构

    backend/
    ├── pom.xml # Maven 依赖(Spring Boot 3.2 + Paho MQTT)
    ├── Dockerfile # 多阶段:maven 构建 → jre 运行
    ├── README.md
    └── src/main/
    ├── resources/application.yml # 端口与全部环境变量
    └── java/com/gemeopen/demo/
    ├── GemeOpenApplication.java # 启动类
    ├── model/
    │ ├── DeviceState.java # 设备状态快照(契约 5.2)
    │ ├── Sample.java # 历史采样点(契约 5.5)
    │ └── SwitchRequest.java # 开关请求体(契约 5.3)
    ├── store/DeviceStore.java # 线程安全状态 + 环形历史
    ├── mqtt/MqttClientService.java # MQTT 连接/订阅/解析/下发
    ├── ws/TelemetryWebSocketHandler.java # WebSocket 广播
    ├── config/
    │ ├── WebSocketConfig.java # 注册 /ws/telemetry
    │ └── CorsConfig.java # 跨域配置
    └── web/DeviceController.java # REST 端点

    2. 运行

    本地(需 JDK 17+ 与 Maven)

    cd backend
    mvn spring-boot:run
    # 或构建后运行
    mvn -DskipTests package
    java -jar target/gemeopen-demo.jar

    可用环境变量覆盖配置(见 application.yml),例如:

    MQTT_HOST=192.168.1.10 DEVICE_MAC=28372fcbbbb8 java -jar target/gemeopen-demo.jar

    Docker

    docker build -t gemeopen-backend-java ./backend
    docker run -d –name gemeopen-backend-java -p 8000:8000 \\
    -e MQTT_HOST=192.168.1.10 -e DEVICE_MAC=28372fcbbbb8 \\
    gemeopen-backend-java

    3. API 一览

    方法路径说明
    GET /api/health 服务/Broker/设备在线状态
    GET /api/device 当前状态快照
    POST /api/device/switch 通断电,body {"on": true}
    POST /api/device/refresh 触发一次 info + statistic 查询
    GET /api/device/history?limit=200 采样历史(绘图用)
    GET /api/config 非敏感运行配置
    WS /ws/telemetry 实时状态推送

    字段定义见 [00 · 架构与契约] 00-architecture.md 第 5 节。

    4. 代码导读(重点三处)

    4.1 MqttClientService:连接与回调

    client = new MqttClient(brokerUrl, clientId, new MemoryPersistence());
    client.setCallback(new MqttCallbackExtended() {
    public void connectComplete(boolean reconnect, String serverURI) {
    client.subscribe(reportTopic, 0); // 订阅设备上报
    }
    public void messageArrived(String topic, MqttMessage msg) {
    DeviceState state = normalize(msg.getPayload()); // 归一化字段
    store.update(state); // 更新状态与历史
    wsHandler.broadcast(state); // 推送给前端
    }
    ...
    });

    4.2 字段归一化

    设备原始字段归一化字段类型
    key (0/1) relayOn Boolean
    voltage voltageV Double
    current currentA Double
    power activePowerW Double
    energy energyKwh Double
    signal signalDbm Integer

    4.3 TelemetryWebSocketHandler:广播

    维护 CopyOnWriteArraySet<WebSocketSession>,状态更新时遍历发送;由于 WebSocket 不能并发写, 发送时用 synchronized 加锁串行化:

    public void broadcast(Object payload) {
    String json = mapper.writeValueAsString(payload);
    TextMessage msg = new TextMessage(json);
    synchronized (sendLock) {
    for (WebSocketSession s : sessions) {
    if (s.isOpen()) s.sendMessage(msg);
    }
    }
    }

    5. 二次开发建议

  • 持久化:把 DeviceStore 的内存历史换成 JPA + PostgreSQL / InfluxDB;
  • 多设备:MQTT_REPORT_TOPIC 已用 + 通配,可按 MAC 建立 Map<String, DeviceState>;
  • 鉴权:引入 Spring Security,为前端接口加 Token;
  • 配置化阈值:新增告警服务,对功率/电量做越限回调。

  • 05-frontend.md

    05 · Angular 前端(Angular 17)

    路径 B 的前端:展示实时电压/电流/功率/累计电量,并提供通断电开关。

    1. 文件结构

    frontend/
    ├── package.json # 依赖与脚本
    ├── angular.json # 构建配置(含 env 替换、dev 代理)
    ├── tsconfig.json / tsconfig.app.json
    ├── proxy.conf.json # 开发代理 /api、/ws → localhost:8000
    ├── Dockerfile # 多阶段:ng build → nginx
    ├── nginx.conf # 托管 dist + 反代 /api、/ws
    ├── README.md
    └── src/
    ├── index.html
    ├── main.ts # bootstrapApplication(AppComponent)
    ├── styles.css # 全局深色主题
    ├── environments/
    │ ├── environment.ts # apiBase: http://localhost:8000(开发)
    │ └── environment.prod.ts # apiBase: ''(生产同源,走 Nginx 反代)
    └── app/
    ├── app.config.ts # provideHttpClient()
    ├── app.component.ts/.html/.css # 根布局
    ├── models/device-state.ts # 类型与空值兜底
    ├── services/
    │ ├── api.service.ts # REST 封装
    │ └── telemetry.service.ts # 状态流:REST + WebSocket + 降级轮询
    └── components/
    ├── switch-control/ # 通断电开关
    ├── realtime-metrics/ # 电压/电流/功率/信号
    ├── energy-total/ # 累计用电量
    └── history-chart/ # 原生 SVG 折线图

    2. 运行

    cd frontend
    npm install
    npm start # http://localhost:4200(自动带 proxy.conf.json 代理到 8000)
    npm run build # 生产构建,产物在 dist/frontend/browser/

    3. 数据流与实时更新

    核心在 telemetry.service.ts:

  • 用 BehaviorSubject<DeviceState> 维护状态流 state$;
  • 首屏 GET /api/device 取初值;
  • 连接 WebSocket /ws/telemetry,每帧更新 state$;
  • 断线指数退避重连(1s→30s 封顶);
  • WebSocket 连续失败则降级为 5 秒轮询,恢复后自动停止轮询。
  • 组件通过 state$ | async 订阅,自动随数据刷新。

    4. 界面构成

    区域组件内容
    顶部 AppComponent 标题、设备在线徽标、连接状态(实时/轮询/断开)、最后更新时间、刷新按钮
    控制 SwitchControl 通电/断电开关(请求中态、离线禁用、错误提示)
    指标 RealtimeMetrics 电压 V / 电流 A / 功率 W / 信号 dBm
    电量 EnergyTotal 累计用电量 kWh
    趋势 HistoryChart 原生 SVG 双线折线(电压 + 功率),含网格与范围统计

    5. 配置

    环境API 地址说明
    开发 http://localhost:8000 也可走 proxy.conf.json 代理
    生产构建 ''(同源) 由 nginx.conf 把 /api、/ws 反代到 backend:8000

    改后端地址:编辑 src/environments/environment.ts。

    6. 构建与部署

    npm run build
    # 产物:dist/frontend/browser/

    # Docker
    docker build -t gemeopen-frontend-angular ./frontend
    docker run -d -p 8080:80 gemeopen-frontend-angular

    7. 二次开发建议

  • 换 UI 组件库:可接入 Angular Material / PrimeNG;
  • 加路由:app.routes.ts 拆出「实时」「历史」「设置」多页;
  • 多设备:顶部加设备切换,按 MAC 传参;
  • 告警:订阅后端告警流,做 Toast/声音提示。

  • 06-deploy-ops.md

    06 · 部署与运维

    覆盖 本地开发 → Docker 部署 → 生产建议,以及日常运维操作。

    1. 部署方式总览

    方式适用场景难度说明
    A. 本地开发 学习/调试 ★ 手动起 Broker + Java 后端 + Angular 前端
    B. Docker Compose 快速上线 ★★ 一条命令起全套(推荐)
    C. 生产部署 长期运行 ★★★ 密码认证 + HTTPS + 自动启动 + 备份

    2. 方式 A:本地开发

    2.1 启动 MQTT Broker

    cd gemeopen-ha-java-demo
    docker compose up -d mosquitto

    2.2 启动 Java 后端(JDK 17+ / Maven)

    cd backend
    mvn spring-boot:run
    # 或
    mvn -DskipTests package && java -jar target/gemeopen-demo.jar

    用环境变量覆盖配置:

    MQTT_HOST=192.168.1.10 DEVICE_MAC=28372fcbbbb8 java -jar target/gemeopen-demo.jar

    健康检查:curl http://localhost:8000/api/health 接口文档(如启用):http://localhost:8000/api/device

    2.3 启动 Angular 前端(Node 18+)

    cd frontend
    npm install
    npm start # http://localhost:4200(已配置代理到 8000)


    3. 方式 B:Docker Compose(推荐)

    3.1 前置

    • 安装 Docker 与 Docker Compose 插件;
    • 修改 docker-compose.yml 中 DEVICE_MAC 为你的设备 MAC。

    3.2 启动

    cd gemeopen-ha-java-demo
    docker compose up -d –build
    docker compose ps

    服务地址
    Mosquitto mqtt://<宿主机IP>:1883
    Java 后端 API http://localhost:8000/api/health
    Angular 前端 http://localhost:8080

    3.3 关键:让设备能访问到 Broker

    设备端 setting-mqtt 里的 Broker 地址必须填 宿主机局域网 IP(如 192.168.1.10), 不能用 localhost / mosquitto(那是容器内部地址)。并确认防火墙放行 1883。


    4. 方式 C:生产环境建议

    4.1 启用 Broker 密码认证

    按 mosquitto/mosquitto.conf 末尾说明生成 passwd 并开启认证,然后同步更新: 设备 setting-mqtt、HA MQTT 集成、后端 MQTT_USERNAME/MQTT_PASSWORD。

    4.2 安全清单

    • 关闭匿名访问;设备/HA/后端使用独立账号
    • MQTT 端口不暴露公网;远程用 VPN 或 TLS(8883)
    • 前端对外 HTTPS(Nginx/Caddy 反代 + 证书)
    • 后端 CORS_ORIGINS 由 * 收紧为你的域名
    • 密钥用环境变量/密钥管理,不入库不入代码

    4.3 开机自启

    • Docker:restart: unless-stopped 已配置;
    • 裸机后端用 systemd:

    # /etc/systemd/system/gemeopen-backend.service
    [Unit]
    Description=GemeOpen Java Backend
    After=network.target mosquitto.service
    [Service]
    WorkingDirectory=/opt/gemeopen-ha-java-demo/backend
    ExecStart=/usr/bin/java -jar /opt/gemeopen-ha-java-demo/backend/target/gemeopen-demo.jar
    Environment=MQTT_HOST=192.168.1.10
    Environment=DEVICE_MAC=28372fcbbbb8
    Restart=always
    [Install]
    WantedBy=multi-user.target

    sudo systemctl daemon-reload && sudo systemctl enable –now gemeopen-backend


    5. 日常运维

    5.1 看日志

    docker compose logs -f backend
    docker compose logs -f mosquitto
    docker compose logs -f frontend

    5.2 健康检查

    curl http://localhost:8000/api/health
    # {"status":"ok","mqttConnected":true,"deviceOnline":true}

    5.3 更新

    docker compose up -d –build # Docker 方式
    # 或裸机:重新 mvn package 后重启服务
    sudo systemctl restart gemeopen-backend

    5.4 备份

    • Broker 数据:mosquitto-data 卷;
    • 历史数据:当前 Demo 存于内存,重启即清空。生产建议改接 PostgreSQL / InfluxDB / TimescaleDB。

    5.5 监控建议

    指标方式
    后端存活 /api/health + Uptime Kuma / 定时 curl
    JVM 指标 Spring Boot Actuator + Prometheus + Grafana
    MQTT 连接数 mosquitto_sub -t '$SYS/broker/clients/connected'
    设备在线 后端 online 字段,可加 HA 自动化告警

    5.6 JVM 调优(可选)

    java -Xms256m -Xmx512m -jar target/gemeopen-demo.jar

    单设备低频上报场景内存占用很小;可结合 Actuator 观察堆使用。


    6. 配置速查(后端环境变量)

    见 [00 · 架构与契约] 00-architecture.md 第 6 节,或 backend/src/main/resources/application.yml。


    07-troubleshooting.md

    07 · 排错手册

    按“症状”查“原因/解决”。随身备好两条抓包命令:

    # 看设备是否在发数据(订阅设备上报主题)
    mosquitto_sub -h 192.168.1.10 -p 1883 -t 'gemeopen/gspm1b/+/report' -v

    # 看是否有人给设备发指令(订阅设备指令主题)
    mosquitto_sub -h 192.168.1.10 -p 1883 -t 'gemeopen/gspm1b/+/command' -v


    一、设备侧

    症状可能原因解决
    设备不上报 未切换到自建 Broker 运行 scripts/configure_device.py 执行 setting-mqtt,再断电重启
    切换后彻底没数据 目标 Broker 设备不可达 地址用局域网 IP/公网域名,放行 1883
    上报间隔很长 电池/缓存策略 把 timerInterval 调小(如 15s)
    通电后数据不刷新 未开定时上报 发 {"timerEnable":1,"timerInterval":15,"type":"setting"}
    改了参数不生效 部分设置需重启 断电重启或发 {"system":"restart","type":"setting"}

    二、MQTT Broker

    症状可能原因解决
    客户端连不上 端口/地址/防火墙 docker compose ps、docker compose logs mosquitto
    not authorised 开了认证但凭据错 核对 passwd,或临时改回 allow_anonymous true 验证
    订阅收不到 主题拼写错 用 + 通配测试 gemeopen/gspm1b/+/report
    容器起不来 配置语法错 查看 mosquitto 日志

    三、Home Assistant

    症状可能原因解决
    MQTT 集成添加失败 Broker 地址/凭据错 Docker 场景用宿主机 IP
    switch 不可用 state_topic 无数据 先确保设备在报数据;检查 <MAC> 是否替换
    点开关没反应 command_topic 填成 report 必须是设备 subcribe 主题(…/command)
    传感器一直“未知” 未开定时上报 开启上报;抓包确认字段名
    能源面板无数据 缺 state_class 确认 energy 传感器 total_increasing
    改 YAML 不生效 未重载 开发者工具 → YAML → 检查配置 → 重启 HA

    四、Java 后端(Spring Boot)

    症状可能原因解决
    启动报 Port 8000 already in use 端口被占用 改 server.port 或停掉占用进程
    /api/health 里 mqttConnected:false 连不上 Broker 检查 MQTT_HOST/PORT/USERNAME/PASSWORD
    /api/device 全为 null 没收到设备上报 用 mosquitto_sub 验证设备在发
    开关接口 success:true 但实物无反应 MQTT_COMMAND_TOPIC 的 {mac} 未替换 检查 DEVICE_MAC 与 topic 模板
    编译报依赖下载失败 网络抖动 重试 mvn -DskipTests package;配置镜像
    想调日志级别 — application.yml 里 logging.level.com.gemeopen=DEBUG

    小技巧:mvn -DskipTests package 打包后 java -jar target/gemeopen-demo.jar 最接近生产运行方式。


    五、Angular 前端

    症状可能原因解决
    页面一直“离线” 后端未起/地址错 打开 http://localhost:8000/api/health;检查 environment.ts
    有数据但不刷新 WebSocket 被代理拦截 开发用 proxy.conf.json;生产用 nginx.conf 的 /ws 段
    跨域报错 后端未允许来源 后端 CORS_ORIGINS 设为前端地址
    图表为空 /api/device/history 无数据 需先积累若干条上报
    npm install 很慢 网络/镜像 换 npm 镜像源,或使用 Docker 构建
    构建后接口 404 生产 apiBase 未走同源 生产构建用 environment.prod.ts(apiBase: '')+ Nginx 反代

    六、网络连通性自查(万能四连)

    # 1) 能否向 Broker 发布测试消息
    mosquitto_pub -h 192.168.1.10 -p 1883 -t test -m hello

    # 2) 后端 → Broker 配置
    docker compose exec backend sh -c 'echo $MQTT_HOST'

    # 3) 浏览器/命令行 → 后端
    curl http://192.168.1.10:8000/api/health

    # 4) HA → Broker(MQTT 集成页面看“已连接”)

    绝大多数问题都能通过「确认数据是否到达 Broker」快速定位是设备侧、Broker 侧还是应用侧。


    赞(0)
    未经允许不得转载:网硕互联帮助中心 » MQTT智能插座如何接入Home Assistant,从零开始完整工程实现(Java+Angular)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!