Skip to content

4.6 设备端 HTTP 上报 ​

前面几节是「后台程序调服务器接口」。这一节反过来:设备主动用 HTTP 把数据 POST 到服务器,作为 MQTT 之外的另一条上云通道。

4.6.1 什么时候用 HTTP 而不是 MQTT ​

MQTTHTTP
长连接是,需要保持否,一次一断
实时下发支持(订阅)不支持,只能设备主动轮询
上报频率秒级、亚秒级都合适分钟级为宜
流量开销小每次都带完整头部和认证,明显更大
穿透性需要放行 1883只用 80/443,通常无需额外放行
实现复杂度要 MQTT 库一个 HTTP POST 就够

优先选择 MQTT,以下情况使用 HTTP:

  • 网络环境只放行 80/443,1883 被封
  • 设备端没有可用的 MQTT 库,但有 HTTP
  • 上报频率很低(几分钟一次),不值得维持长连接
  • 已有的第三方系统只会发 HTTP

4.6.2 上报就是调用 set_real ​

设备端没有专门的上报接口,直接用 4.3 的 set_real:

POST /web
Content-Type: application/json

{
  "cmd": "set_real",
  "username": "设备子账号",
  "password": "密码",
  "project": "main",
  "data": [
    {"name": "车间1/1号机/温度", "value": "25.6"},
    {"name": "车间1/1号机/湿度", "value": "60"}
  ]
}

数据点不存在会自动创建,效果与 MQTT 上报一致:同样能被云组态绑定、设置存盘、配置事件触发。

响应 {"cmdreq":"ok"} 表示写入成功。

4.6.3 LP 设备 Lua 示例 ​

lua
-- 带自定义头必须用对象模式创建客户端
hc = http.creat("http://192.168.1.100/web")
hc:add_head("Content-Type", "application/json")

-- 每 60 秒上报一次
t = timer.start(60000, function()
    local body = json.encode({
        cmd = "set_real",
        username = "dev01",
        password = "密码",
        project = "main",
        data = {
            { name = "车间1/1号机/温度", value = tostring(plc.d(0) / 10) },
            { name = "车间1/1号机/湿度", value = tostring(plc.d(1) / 10) },
        }
    })
    -- 定时器回调里必须用异步接口,同步接口会阻塞整个事件循环
    hc:post_asy("http://192.168.1.100/web", body, function(errcode, data, len)
        if errcode ~= 0 then
            -- 发送失败,可在这里做本地缓存或计数
            return
        end
        -- data 是响应体字符串,可解析确认 cmdreq
    end)
end)

需使用异步接口

http.post() / client:post() 是同步的,固定 15 秒超时且会阻塞整个 Lua 事件循环。在定时器回调里用同步接口,网络一卡整台设备的脚本、串口采集都会停住。定时上报应使用 post_asy。

4.6.4 设备用 HTTP 拉取云端指令 ​

HTTP 没有下发能力,要接收云端指令只能设备主动轮询 get_real:

lua
hc2 = http.creat("http://192.168.1.100/web")
hc2:add_head("Content-Type", "application/json")

t2 = timer.start(10000, function()
    local body = json.encode({
        cmd = "get_real",
        username = "dev01", password = "密码", project = "main",
        data = { "车间1/1号机/启停" }
    })
    hc2:post_asy("http://192.168.1.100/web", body, function(errcode, resp, len)
        if errcode ~= 0 then return end
        local ok, obj = pcall(json.decode, resp)          -- 外部数据一律 pcall
        if not ok or obj.cmdreq ~= "ok" then return end
        for _, p in ipairs(obj.data or {}) do
            if p.name == "车间1/1号机/启停" then
                plc.y(0, tonumber(p.value) == 1)
            end
        end
    end)
end)

轮询间隔决定了指令的响应延迟。10 秒轮询意味着按钮操作最多 10 秒后才生效。要求实时控制的场景应使用 MQTT 订阅,不要用 HTTP 轮询。

4.6.5 注意事项 ​

  • 账号密码在每个请求体里明文出现,公网上报必须用 HTTPS(https://域名/web,端口 443)
  • 给每台设备开独立子账号,泄露时只影响一台
  • 上报失败要有重试或本地缓存,否则断网期间的数据会丢失
  • 上报频率不宜过高。每分钟一次是合适的量级,秒级上报应改用 MQTT

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