跳转到内容

Shelly MQTT Topic 结构

Shelly MQTT Topic 结构

本节详细介绍 Shelly 设备的 MQTT Topic 结构和数据格式。学习完成后,您将能够:

  • 理解 Shelly Gen1 和 Gen2 的 Topic 差异
  • 订阅正确的 Topic 获取设备状态和能耗数据
  • 发布命令控制 Shelly 设备
  • 设计统一的 Topic 抽象层
# 设备状态 (定期推送)
shelly1pm-{deviceid}/status
→ {"relays":[{"ison":false}],"meters":[{"power":0.0,"total":123}]}
# 继电器状态变化 (事件触发)
shelly1pm-{deviceid}/relay/0
→ {"ison":true}
# 在线状态
shelly1pm-{deviceid}/online
→ true / false
Terminal window
# 通过 HTTP API 控制 (Gen1 主要方式)
curl http://shelly1pm-ip/relay/0?turn=on
curl http://shelly1pm-ip/relay/0?turn=off
# 通过 MQTT 控制 (需要额外配置)
# 发布到:
shelly1pm-{deviceid}/command
"on" / "off" / "toggle"
{
"relays": [
{"ison": false, "has_timer": false}
],
"meters": [
{
"power": 42.5, // 当前功率 (W)
"overpower": 0.0,
"is_valid": true,
"timestamp": 1694321234,
"counters": [0.0, 0.0],
"total": 1452000.0 // 总电量 (Wh)
}
]
}
# 开关状态
shellyplus1pm-{deviceid}/status/switch:0
→ {"id":0,"output":true,"apower":42.5,"voltage":223.1,"current":0.216}
# 功率数据
shellyplus1pm-{deviceid}/status/devicepower:0
→ {"id":0,"battery":{"V":3.2},"external":{"V":223.1}}
# 在线状态
shellyplus1pm-{deviceid}/status/cloud
→ {"connected":true}
{
"id": 0,
"source": "switch",
"output": true,
"apower": 42.5, // 当前功率 (W)
"voltage": 223.1, // 电压 (V)
"current": 0.216, // 电流 (A)
"pf": 0.92, // 功率因数
"aenergy": {
"total": 1452000, // 总电量 (mWh)
"by_minute": [12.3, 15.1], // 每分钟电量
"minute_ts": 1694321234
},
"temperature": {
"tC": 42.5 // 内部温度
}
}

Gen2 的核心能力是通过 MQTT RPC 通道进行双向通信:

Topic: shellyplus1pm-{deviceid}/rpc
// 获取状态
{
"id": 1,
"src": "nodered",
"method": "Switch.GetStatus",
"params": {"id": 0}
}
// 控制开关
{
"id": 2,
"src": "nodered",
"method": "Switch.Set",
"params": {
"id": 0,
"on": true
}
}
// 设置自动关闭
{
"id": 3,
"src": "nodered",
"method": "Switch.Set",
"params": {
"id": 0,
"on": true,
"toggle_after": 300 // 5 分钟后自动关闭
}
}
// 获取设备信息
{
"id": 4,
"src": "nodered",
"method": "Shelly.GetDeviceInfo"
}
Topic: nodered/rpc (根据请求中的 src 字段)
{
"id": 1,
"src": "shellyplus1pm-{deviceid}",
"result": {
"id": 0,
"output": false,
"apower": 0,
"voltage": 223.1,
"current": 0.0
}
}
Shelly Plus 1PM (Gen2) Topic Structure:
─────────────────────────────────────────
📂 shellyplus1pm-{deviceid}/
├── 📂 status/ ← 自动状态推送
│ ├── 📄 switch:0 ← 开关状态 + 能耗数据
│ ├── 📄 devicepower:0 ← 电源状态
│ ├── 📄 cloud ← 云连接状态
│ ├── 📄 wifi ← Wi-Fi 状态
│ └── 📄 sys ← 系统信息
├── 📄 rpc ← RPC 命令通道
└── 📂 events/ ← 事件通知 (RPC events)
└── 📄 rpc

建议在 Node-RED 中创建统一的能耗数据处理 Flow:

// Function: 统一 Shelly 数据解析器
// 支持 Gen1 和 Gen2 两种格式
var topic = msg.topic;
var payload = msg.payload;
// 检测设备类型
var deviceType = "unknown";
if (topic.includes("shellyplus")) {
deviceType = "shelly-gen2";
} else if (topic.includes("shelly")) {
deviceType = "shelly-gen1";
}
// 标准化输出
var normalized = {
deviceId: topic.split('/')[0],
deviceType: deviceType,
timestamp: Date.now()
};
if (deviceType === "shelly-gen2") {
// Gen2: 直接从 status/switch 获取
normalized.power = payload.apower || 0;
normalized.voltage = payload.voltage || 0;
normalized.current = payload.current || 0;
normalized.powerFactor = payload.pf || 0;
normalized.output = payload.output || false;
normalized.totalEnergy = (payload.aenergy?.total || 0) / 1000;
normalized.temperature = payload.temperature?.tC || 0;
} else if (deviceType === "shelly-gen1") {
// Gen1: 从 status 中 extract
var meter = payload.meters?.[0];
var relay = payload.relays?.[0];
normalized.power = meter?.power || 0;
normalized.totalEnergy = (meter?.total || 0) / 1000;
normalized.output = relay?.ison || false;
}
msg.payload = normalized;
return msg;

Q1: Gen1 和 Gen2 的 Topic 结构完全不兼容,如何统一管理?

Section titled “Q1: Gen1 和 Gen2 的 Topic 结构完全不兼容,如何统一管理?”

建议在 Node-RED 中创建数据抽象层(如上面的 Function 代码),将 Gen1 和 Gen2 数据标准化为统一格式,下游的 InfluxDB 和 Grafana 无需关心设备类型。

RPC 提供请求-响应模式,可以获取即时数据(不需要等 TelePeriod 推送),支持双向通信,且可以通过同一个 MQTT 连接管理所有 RPC 方法。

Q3: 如何批量管理多个 Shelly 设备?

Section titled “Q3: 如何批量管理多个 Shelly 设备?”

在 Node-RED 中使用通配符订阅:

  • 订阅 shelly+/+/status/# 接收所有设备状态
  • 按设备 ID 分流处理
  • 使用 Flow/Global Context 管理设备注册表

推荐做法:

  • Gen2 优先使用 RPC over MQTT 获取数据
  • 在 Node-RED 中创建统一的数据抽象层
  • 使用通配符订阅多设备时注意 Topic 过滤
  • 为每个 RPC 请求生成唯一 ID 用于匹配响应

避免做法:

  • Gen1 和 Gen2 的控制接口混用
  • RPC 请求 ID 不唯一导致响应匹配混乱
  • 订阅过于宽泛的 Topic(如 #
  • 不处理 RPC 响应超时的情况
  1. Gen1 Shelly 使用 shelly{id}/statusshelly{id}/relay/{n} Topic
  2. Gen2 Shelly 使用 shellyplus{id}/status/switch:{n} 结构化 Topic
  3. RPC over MQTT 提供双向请求-响应通信
  4. RPC 命令通过 {deviceid}/rpc 发送,响应路由到 src 指定的 Topic
  5. Node-RED 抽象层可统一 Gen1/Gen2 的数据格式