Skip to content

5.4 发布订阅示例 ​

下面的示例都遵循 5.5 消息格式规范:主题名即数据点名,payload 用裸值。

5.4.1 命令行(mosquitto) ​

bash
# 上报单个值
mosquitto_pub -h 服务器IP -p 1883 -u 账号 -P 密码 -i dev01 \
              -t "车间1/1号机/温度" -m "25.6" -q 1

# 一条消息上报多个值(得到 车间1/1号机/温度、车间1/1号机/湿度)
mosquitto_pub -h 服务器IP -p 1883 -u 账号 -P 密码 -i dev01 \
              -t "车间1/1号机" -m '{"温度":25.6,"湿度":60}' -q 1

# 订阅云端下发
mosquitto_sub -h 服务器IP -p 1883 -u 账号 -P 密码 -i dev01 \
              -t "车间1/1号机/启停" -q 1

5.4.2 Python(paho-mqtt) ​

python
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print("connected", rc)
    client.subscribe("车间1/1号机/启停", qos=1)

def on_message(client, userdata, msg):
    # 服务器下发默认格式为 {"value":新值}
    print(msg.topic, msg.payload.decode())

c = mqtt.Client(client_id="dev01", protocol=mqtt.MQTTv311)
c.username_pw_set("账号", "密码")
c.on_connect = on_connect
c.on_message = on_message
c.connect("服务器IP", 1883, keepalive=60)
c.loop_start()

# 上报裸值
c.publish("车间1/1号机/温度", "25.6", qos=1)

# 批量上报(服务器会拆成 车间1/1号机/温度、车间1/1号机/湿度)
import json
c.publish("车间1/1号机", json.dumps({"温度": 25.6, "湿度": 60}, ensure_ascii=False), qos=1)

5.4.3 Node.js(mqtt.js) ​

javascript
const mqtt = require('mqtt')

const client = mqtt.connect('mqtt://服务器IP:1883', {
  clientId: 'dev01',
  username: '账号',
  password: '密码',
  protocolVersion: 4,          // 4 = MQTT 3.1.1
  keepalive: 60,
})

client.on('connect', () => {
  client.subscribe('车间1/1号机/启停', { qos: 1 })
  client.publish('车间1/1号机/温度', '25.6', { qos: 1 })
})

client.on('message', (topic, payload) => {
  console.log(topic, payload.toString())   // 下发默认为 {"value":新值}
})

5.4.4 LP 设备 Lua 脚本 ​

LP 设备接自家服务器一般用云交互绑定(3.2)就够了,这里给的是用标准 MQTT 接入的写法,适合要自定义主题和 payload 的场合。

lua
-- 客户端对象必须用全局变量长期持有,否则会被 GC 回收
mqttc = mqtt.creat("服务器IP", 1883, "dev01", "账号", "密码")
mqtt.set_version(mqttc, 4)          -- 4 = MQTT 3.1.1
mqtt.set_keepalive(mqttc, 60)

-- 连接成功后再订阅最稳
mqtt.reg(mqttc, mqtt.CONNECTED, function()
    mqtt.subscribe(mqttc, "车间1/1号机/启停", 1)      -- topic, qos
end)

-- 接收回调签名固定为 (topic, payload)
mqtt.reg(mqttc, mqtt.RECVDATA, function(topic, payload)
    if topic == "车间1/1号机/启停" then
        -- 服务器下发 {"value":1},外部数据一律 pcall 保护
        local ok, obj = pcall(json.decode, payload)
        if ok and type(obj) == "table" and obj.value ~= nil then
            plc.y(0, tonumber(obj.value) == 1)          -- 写 Y0
        end
    end
end)

mqtt.start(mqttc)                    -- 内部线程自动重连

-- 定时上报:payload 使用裸值
t = timer.start(5000, function()
    if mqtt.is_linked(mqttc) == 1 then                  -- 返回整数,必须 == 1
        mqtt.publish(mqttc, "车间1/1号机/温度", tostring(plc.d(0) / 10), 1, 0)
    end
end)

三点需要注意:

  • mqtt.函数(客户端, ...) 与 客户端:函数(...) 两种写法等价,creat 只能用库表形式
  • mqtt.is_linked() 返回整数 0/1,Lua 里 0 为真,判断必须写 == 1
  • mqtt.publish() 未连接时返回 nil(不是 false)

5.4.5 双向联动的完整例子 ​

目标:温度上报到云端画面显示;画面上的按钮能远程启停设备。

设备侧

publish   车间1/1号机/温度   →  25.6        (上行)
subscribe 车间1/1号机/启停   ←  {"value":1} (下行)

云端

  1. 两个数据点在实时数据库里自动出现(车间1/1号机/启停 首次需要云端写一次才会创建,可在实时数据库页手动新建或用 HTTP API set_real 写一次)
  2. 云组态里用项目变量(无前缀)绑定:显示控件绑 车间1/1号机/温度,按钮的点击事件用「设定数据」写 车间1/1号机/启停
  3. 要历史曲线,在实时数据库里把温度点的存盘方式设为「瞬时型每分钟存盘」
  4. 要超温报警,在事件触发里做「数据变化 → 数值比较 → 限频 → 发送邮件」

5.4.6 通配符订阅 ​

订阅支持 MQTT 标准通配符,适合做网关或调试监听:

通配符含义例子
+匹配单层车间1/+/温度 匹配 车间1/1号机/温度、车间1/2号机/温度
#匹配多层(只能放末尾)车间1/# 匹配 车间1 下所有层级

$ 开头的主题是 MQTT 系统保留主题,不会被通配符匹配到,所以 # 订阅不到它们。


LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研