Эх сурвалжийг харах

1.添加MQTT部分。将传感器数据上传至公司服务器
2. 注释掉了一部分注释

ZhaoSai 2 сар өмнө
parent
commit
c7273d3338

+ 62 - 80
drv_periph/LoRa_Process.lua

@@ -92,115 +92,91 @@ local function bytes_to_float(b1,b2,b3,b4)
     return (sign==1 and -1 or 1) * (1 + mant/0x800000) * 2^(expo-127)
 end
 
-local function print_sensor(s)
-    if s.data_type == 0x01 then
-        local t = bit.lshift(s.data[1],8) + s.data[2]
-        log.info("Sensor","温度", string.format("%.2f°C", t/100.0))
-    elseif s.data_type == 0x02 then
-        local h = bit.lshift(s.data[1],8) + s.data[2]
-        log.info("Sensor","湿度", string.format("%.2f%%", h/100.0))
-    elseif s.data_type == 0x03 then
-        log.info("Sensor","光照强度", s.data[1])
-    elseif s.data_type == 0x04 then
-        log.info("Sensor","烟雾浓度", s.data[1])
-    elseif s.data_type == 0x10 then
-        if #s.data == 4 then
-            local val = bytes_to_float(s.data[1],s.data[2],s.data[3],s.data[4])
-            log.info("Sensor","扩展类型0x10 (float)", string.format("%.4f L", val))
-        else
-            log.warn("Sensor","0x10 长度异常", #s.data)
+-- 解码传感器数据,返回 (value, unit, type)
+local function decode_sensor(sensor)
+    if sensor.data_type == 0x01 then
+        local t = bit.lshift(sensor.data[1],8) + sensor.data[2]
+        return t / 100.0, "°C", "temperature"
+    elseif sensor.data_type == 0x02 then
+        local h = bit.lshift(sensor.data[1],8) + sensor.data[2]
+        return h / 100.0, "%", "humidity"
+    elseif sensor.data_type == 0x03 then
+        return sensor.data[1], "lux", "light"
+    elseif sensor.data_type == 0x04 then
+        return sensor.data[1], "ppm", "smoke"
+    elseif sensor.data_type == 0x10 then
+        if #sensor.data == 4 then
+            local val = bytes_to_float(sensor.data[1],sensor.data[2],sensor.data[3],sensor.data[4])
+            return val, "L", "liquid"
         end
-    else
-        log.info("Sensor","未知类型", s.data_type, "原始数据", table.concat(s.data,","))
     end
+    return sensor.data, "raw", "unknown"
 end
 
 
-
-
+-- 解析接收到的帧,返回符合 JSON 格式的表
 local function parse_received_frame(hex_str)
-    log.info("Frame","收到数据", hex_str)
-
-    -- 转换 hex_str → buf
     local buf = {}
     for i = 1, #hex_str, 2 do
         local hex_byte = hex_str:sub(i, i+1)
-        local dec_byte = tonumber(hex_byte, 16)
-        if not dec_byte then
-            log.error("Frame","十六进制转换失败", "非法字符:"..hex_byte)
-            return false
-        end
-        table.insert(buf, dec_byte)
-    end
-    local buf_len = #buf
-    if buf_len < 9 then
-        log.error("Frame","长度不足", buf_len)
-        return false
+        table.insert(buf, tonumber(hex_byte, 16))
     end
+    if #buf < 9 then return nil end
+    if buf[1] ~= FRAME_HEADER1 or buf[2] ~= FRAME_HEADER2 then return nil end
 
-    -- 帧头
-    if buf[1] ~= FRAME_HEADER1 or buf[2] ~= FRAME_HEADER2 then
-        log.error("Frame","帧头错误", string.format("实际=0x%02X%02X", buf[1], buf[2]))
-        return false
-    end
-
-    -- 地址与帧类型
-    local src_addr = buf[3]
-    local dst_addr = buf[4]
+    local src_addr   = buf[3]
+    local dst_addr   = buf[4]
     local frame_type = buf[5]
-    if dst_addr ~= MASTER_ADDR or frame_type ~= FRAME_TYPE_DATA then
-        log.error("Frame","地址/类型错误", 
-            string.format("src=0x%02X dst=0x%02X type=0x%02X", src_addr,dst_addr,frame_type))
-        return false
-    end
+    if dst_addr ~= MASTER_ADDR or frame_type ~= FRAME_TYPE_DATA then return nil end
 
-    -- 传感器数量+数据总长
     local sensor_count   = buf[6]
     local data_total_len = buf[7]
 
-    -- CRC校验
-    local crc_low, crc_high = buf[buf_len-1], buf[buf_len]
+    -- CRC 校验
+    local crc_low, crc_high = buf[#buf-1], buf[#buf]
     local crc_recv = crc_low + bit.lshift(crc_high,8)
-    local crc_calc = Modbus_CRC16(buf, buf_len-2)
-    if crc_recv ~= crc_calc then
-        log.error("Frame","CRC错误", string.format("recv=0x%04X calc=0x%04X", crc_recv,crc_calc))
-        return false
-    end
-
-    log.info("Frame","地址=0x"..string.format("%02X",src_addr),
-                      "传感器数="..sensor_count,
-                      "数据长度="..data_total_len.."字节")
+    local crc_calc = Modbus_CRC16(buf, #buf-2)
+    if crc_recv ~= crc_calc then return nil end
+
+    -- ✅ 返回简洁 JSON
+    local result = {
+        ts      = os.time(),
+        addr    = src_addr,
+        sensors = {}
+    }
 
-    -- 逐个解析传感器
     local offset = 8
     local data_end = 8 + data_total_len - 1
     for i = 1, sensor_count do
-        if offset + 2 > data_end then
-            log.warn("Frame","传感器头部越界", "offset="..offset)
-            break
-        end
+        if offset + 2 > data_end then break end
         local sensor = {
-            sensor_id = buf[offset],
+            id        = buf[offset],
             data_type = buf[offset+1],
             data_len  = buf[offset+2],
-            data = {}
+            data      = {}
         }
-        if offset + 3 + sensor.data_len - 1 > data_end then
-            log.warn("Frame","传感器数据越界 ID=0x"..string.format("%02X",sensor.sensor_id))
-            break
-        end
         for j = 1, sensor.data_len do
             table.insert(sensor.data, buf[offset+2+j])
         end
-        print_sensor(sensor)
+
+        local value, unit, type = decode_sensor(sensor)
+        table.insert(result.sensors, {
+            id    = sensor.id,
+            type  = type,
+            value = value,
+            unit  = unit
+        })
+
         offset = offset + 3 + sensor.data_len
     end
 
-    return true
+    return result
 end
 
 
 
+
+
 -- --------------------- 主机轮询 ---------------------
 function master_query_loop()
     
@@ -224,6 +200,10 @@ function master_query_loop()
                     log.info("slave_addr_hex",slave_addr_hex)
                     -- log.info("rx_buf:sub(7,8)",rx_buf:sub(7,8))
                     -- log.info("rx_buf:sub(5,6)",rx_buf:sub(5,6))
+                    if rx_buf:sub(1,2) ~= "5A" then
+                        log.info("帧头错误")
+                        break
+                    end
                     if rx_buf:sub(5,6) ~= slave_addr_hex then  
                         log.info("从机地址不匹配")
                         break
@@ -232,15 +212,17 @@ function master_query_loop()
                         log.info("主机地址不匹配")
                         break
                     end
-                    if parse_received_frame(rx_buf) then
-                        response = true
-                        break
-                    end
+                        local result = parse_received_frame(rx_buf)
+                        if result then
+                            -- 发布事件,外部来处理
+                            sys.publish("SENSOR_UPDATE",result)
+                            break
+                        end
                 end
                 sys.wait(50)
             end
             if not response then
-                log.warn("Host",string.format("从机0x%02X无响应",addr))
+                -- log.warn("Host",string.format("从机0x%02X无响应",addr))
             end
             sys.wait(5000)
         end
@@ -250,7 +232,7 @@ end
 sys.taskInit(function()
 
 
-    sys.wait(5000)
+    sys.wait(10000)
 
     radio.RadioInit()
     radio.RadioStandby()

+ 55 - 55
drv_periph/sx126x_driver.lua

@@ -76,7 +76,7 @@ pio.pin.setdebounce(0xffffffff)
 
 
 function gpio4IntFnc(msg)
-    log.info("testGpioSingle.gpio4IntFnc",msg,getGpio4Fnc())
+    -- log.info("testGpioSingle.gpio4IntFnc",msg,getGpio4Fnc())
     --上升沿中断
     if msg==cpu.INT_GPIO_POSEDGE then
         sys.publish("LORA_CALL_BACK")
@@ -103,7 +103,7 @@ end
 
 function gsonLoginfo(data)
     local jsondata = json.encode(data)
-    log.info("SX126xSetModulationParams.encode",jsondata)
+    -- log.info("SX126xSetModulationParams.encode",jsondata)
 end
 
 -- 初始化SPI
@@ -123,7 +123,7 @@ end
 function SX126xWakeup()
     local command = sx126x_reg.RadioCommands.RADIO_GET_STATUS .. "00"
     local ret = Drv_spi.drv_spi_read_write_byte(command,1)
-    log.info("SX126xWakeup",ret)
+    -- log.info("SX126xWakeup",ret)
 end
 
 --命令写入 完成
@@ -149,7 +149,7 @@ function SX126xReadCommand(command,size)
 
     local ret = Drv_spi.drv_spi_read_write_byte(command,size)
     -- Drv_spi.drv_spi_read_write_byte(command,0)
-    log.info("SX126xReadCommand",ret)
+    -- log.info("SX126xReadCommand",ret)
     return ret
 end
 -- -----------------------------------------------SPI基础读写---------------------------------------------------
@@ -187,7 +187,7 @@ function SX126xWriteRegisters(address,buffer)
     end
 
     local test = address .. bufferTotal
-    log.info("SX126xWriteRegisters",bufferTotal)
+    -- log.info("SX126xWriteRegisters",bufferTotal)
     Drv_spi.drv_spi_read_write_byte(test,0);
 end
 
@@ -220,7 +220,7 @@ end
 function SX126xSetPaConfig(paDutyCycle,hpMax,deviceSel,paLut)
     local buf = {paDutyCycle,hpMax,deviceSel,paLut}
     SX126xWriteCommand(sx126x_reg.RadioCommands.RADIO_SET_PACONFIG,buf)
-    log.info("SX126xSetPaConfig",sx126x_reg.RadioCommands.RADIO_SET_PACONFIG)
+    -- log.info("SX126xSetPaConfig",sx126x_reg.RadioCommands.RADIO_SET_PACONFIG)
 end
 
 function SX126xSetTxParams(power, rampTime)
@@ -282,7 +282,7 @@ function SX126xSetDioIrqParams(irqMask, dio1Mask, dio2Mask, dio3Mask)
     end
     
     -- 6. 打印日志(验证格式是否正确)
-    log.info("SX126xSetDioIrqParams", table.concat(buf_hex, " "))
+    -- log.info("SX126xSetDioIrqParams", table.concat(buf_hex, " "))
     
     -- 7. 发送命令(写入8字节配置)
     SX126xWriteCommand(sx126x_reg.RadioCommands.RADIO_CFG_DIOIRQ, buf_hex)
@@ -304,7 +304,7 @@ end
 function SX126xSetPacketType(packetType)
     PacketType = packetType;
     SX126xWriteCommand( sx126x_reg.RadioCommands.RADIO_SET_PACKETTYPE,{PacketType})
-    log.info("PacketType:",PacketType,sx126x_reg.RadioCommands.RADIO_SET_PACKETTYPE)
+    -- log.info("PacketType:",PacketType,sx126x_reg.RadioCommands.RADIO_SET_PACKETTYPE)
 end
 
 -- 原驱动好像并没有启用,不晓得这个是什么功能
@@ -343,7 +343,7 @@ function SX126xSetModulationParams(modulationParams)
     modulationParams.Params.LoRa.LowDatarateOptimize
     }
     local jsondata = json.encode(buf)
-    log.info("SX126xSetModulationParams.encode",jsondata)
+    -- log.info("SX126xSetModulationParams.encode",jsondata)
     SX126xWriteCommand( sx126x_reg.RadioCommands.RADIO_SET_MODULATIONPARAMS,buf);
 end
 
@@ -446,8 +446,8 @@ function SX126xSetRfFrequency(frequency)
 
     freq = frequency / FREQ_STEP
     
-    log.info("freq", freq)
-    log.info("freq", string.format("%02X", freq))
+    -- log.info("freq", freq)
+    -- log.info("freq", string.format("%02X", freq))
     SX126xWriteCommand( sx126x_reg.RadioCommands.RADIO_SET_RFFREQUENCY, {string.format("%02X", freq)});
 end
 
@@ -482,7 +482,7 @@ end
 function RadioSend(buffer,size,time_out) 
     -- setTransmitMode() 
     -- SX126xSetDioIrqParams( sx126x_reg.RadioIrqMasks_t.IRQ_TX_DONE + sx126x_reg.RadioIrqMasks_t.IRQ_RX_TX_TIMEOUT, sx126x_reg.RadioIrqMasks_t.IRQ_TX_DONE + sx126x_reg.RadioIrqMasks_t.IRQ_RX_TX_TIMEOUT, sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_NONE, sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_NONE )--SX126xSetDioIrqParams( sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_ALL, sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_ALL, sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_NONE, sx126x_reg.RadioIrqMasks_t.IRQ_RADIO_NONE )
-    log.info("RadioSend",buffer,size,time_out)
+    -- log.info("RadioSend",buffer,size,time_out)
         local tx_irq_mask = bit.bor(
         sx126x_reg.RadioIrqMasks_t.IRQ_TX_DONE,
         sx126x_reg.RadioIrqMasks_t.IRQ_RX_TX_TIMEOUT
@@ -527,9 +527,9 @@ function sentString(strData)
     RadioSend(hexStr,string.format("%02X", #hexStr/2),"00") 
         --     local original = "Hello, Lua!\n"
         -- local hexStr = stringToHex(original)
-        log.info("test:",hexStr)  -- 输出: 48656c6c6f2c204c756121
-        log.info("testlen:",#hexStr)
-        log.info("testlen2:",string.format("%02X", #hexStr/2))
+        -- log.info("test:",hexStr)  -- 输出: 48656c6c6f2c204c756121
+        -- log.info("testlen:",#hexStr)
+        -- log.info("testlen2:",string.format("%02X", #hexStr/2))
         -- RadioSend(hexStr,string.format("%02X", #hexStr/2),"00") 
 end
 
@@ -669,8 +669,8 @@ local function SX126xGetIrqStatus()
     -- 正确的字节序:高字节在前,低字节在后
     local irq = bit.lshift(msb, 8) + lsb
 
-    log.info("IRQ原始数据", ret, "LSB:", string.format("0x%02X", lsb), "MSB:", string.format("0x%02X", msb))
-    log.info("IRQ解析结果", string.format("0x%04X", irq))
+    -- log.info("IRQ原始数据", ret, "LSB:", string.format("0x%02X", lsb), "MSB:", string.format("0x%02X", msb))
+    -- log.info("IRQ解析结果", string.format("0x%04X", irq))
 
     return irq
 end
@@ -678,7 +678,7 @@ end
 
 
 sys.subscribe("LORA_CALL_BACK", function()
-    log.info("LORA_CALL_BACK")
+    -- log.info("LORA_CALL_BACK")
     --     -- 先读 IRQ 状态
     local irq = SX126xGetIrqStatus()
     if irq == 0 then
@@ -690,55 +690,55 @@ sys.subscribe("LORA_CALL_BACK", function()
     RadioRx()
 
 
-    local tx_gpio_level = pio.pin.getval(pio.P0_27)
-    local rx_gpio_level = pio.pin.getval(pio.P0_28)
-    log.info("TXENGPIO 电平", tx_gpio_level)
-    log.info("RXENGPIO 电平", rx_gpio_level)
+    -- local tx_gpio_level = pio.pin.getval(pio.P0_27)
+    -- log.info("TXENGPIO 电平", tx_gpio_level)
+    -- local rx_gpio_level = pio.pin.getval(pio.P0_28)
+    -- log.info("RXENGPIO 电平", rx_gpio_level)
     -- if tx_gpio_level == 0 and rx_gpio_level == 1 then
     --     return
     -- end
 
-    log.info("IRQ原始HEX", ret)  -- 记得在 GetIrqStatus 里打印
-    log.info("IRQ解析结果", string.format("0x%04X", irq))
+    -- log.info("IRQ原始HEX", ret)  -- 记得在 GetIrqStatus 里打印
+    -- log.info("IRQ解析结果", string.format("0x%04X", irq))
     if irq == 0xAC then
         return
     end
     --日志显示还是有点区别的。如果是oxAC就是把自己读出来了    如果是0xA4就是正常的接收
 
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_TX_DONE) ~= 0 then
-        log.info("发送完成")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_RX_DONE) ~= 0 then
-        log.info("接收完成")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_RX_TX_TIMEOUT) ~= 0 then
-        log.info("接收超时")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CRC_ERROR) ~= 0 then
-        log.info("接收CRC错误")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CAD_DONE) ~= 0 then
-        log.info("CAD完成")
-    end
-    if bit.band(irq,sx126x_reg.RadioIrqMasks_t.IRQ_HEADER_VALID) ~= 0 then
-        log.info("头部有效")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_HEADER_ERROR) ~= 0 then
-        log.info("头部错误")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_SYNCWORD_VALID) ~= 0 then
-        log.info("同步字有效")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_PREAMBLE_DETECTED) ~= 0 then
-        log.info("前导码检测到")
-    end
-    if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CAD_ACTIVITY_DETECTED) ~= 0 then
-        log.info("CAD活动检测到")
-    end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_TX_DONE) ~= 0 then
+    --     log.info("发送完成")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_RX_DONE) ~= 0 then
+    --     log.info("接收完成")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_RX_TX_TIMEOUT) ~= 0 then
+    --     log.info("接收超时")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CRC_ERROR) ~= 0 then
+    --     log.info("接收CRC错误")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CAD_DONE) ~= 0 then
+    --     log.info("CAD完成")
+    -- end
+    -- if bit.band(irq,sx126x_reg.RadioIrqMasks_t.IRQ_HEADER_VALID) ~= 0 then
+    --     log.info("头部有效")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_HEADER_ERROR) ~= 0 then
+    --     log.info("头部错误")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_SYNCWORD_VALID) ~= 0 then
+    --     log.info("同步字有效")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_PREAMBLE_DETECTED) ~= 0 then
+    --     log.info("前导码检测到")
+    -- end
+    -- if bit.band(irq, sx126x_reg.RadioIrqMasks_t.IRQ_CAD_ACTIVITY_DETECTED) ~= 0 then
+    --     log.info("CAD活动检测到")
+    -- end
 
 
     local ret = SX126xReadCommand(sx126x_reg.RadioCommands.RADIO_GET_RXBUFFERSTATUS, 3)
-    log.info("LORA_CALL_BACK", ret)
+    -- log.info("LORA_CALL_BACK", ret)
 
     local payloadLength = ret:sub(3, 4)
     local num1 = tonumber(payloadLength, 16)

+ 4 - 4
main.lua

@@ -47,9 +47,9 @@ wdt.setup(pio.P0_30, pio.P0_31)
 --加载网络指示灯功能模块
 --根据自己的项目需求和硬件配置决定:1、是否加载此功能模块;2、配置指示灯引脚
 --合宙官方出售的Air720U开发板上的网络指示灯引脚为pio.P0_1,LTE指示灯引脚为pio.P0_4
-require "netLed"
-pmd.ldoset(2,pmd.LDO_VLCD)
-netLed.setup(true,pio.P0_1,pio.P0_4)
+-- require "netLed"
+-- pmd.ldoset(2,pmd.LDO_VLCD)
+-- netLed.setup(true,pio.P0_1,pio.P0_4)
 --网络指示灯功能模块中,默认配置了各种工作状态下指示灯的闪烁规律,参考netLed.lua中ledBlinkTime配置的默认值
 --如果默认值满足不了需求,此处调用netLed.updateBlinkTime去配置闪烁时长
 
@@ -69,7 +69,7 @@ errDump.request("udp://dev_msg1.openluat.com:12425", nil, true)
 -- require "Air530zGPS"
 
 require "LoRa_Process"
-
+require "mqttTask"
 
 --启动系统框架
 sys.init(0, 0)

+ 30 - 0
mqttConnect/mqttInMsg.lua

@@ -0,0 +1,30 @@
+--- 模块功能:MQTT客户端数据接收处理
+-- @author openLuat
+-- @module mqtt.mqttInMsg
+-- @license MIT
+-- @copyright openLuat
+-- @release 2018.03.28
+
+module(...,package.seeall)
+
+--- MQTT客户端数据接收处理
+-- @param mqttClient,MQTT客户端对象
+-- @return 处理成功返回true,处理出错返回false
+-- @usage mqttInMsg.proc(mqttClient)
+function proc(mqttClient)
+    local result,data
+    while true do
+        result,data = mqttClient:receive(60000,"APP_SOCKET_SEND_DATA")
+        --接收到数据
+        if result then
+            log.info("mqttInMsg.proc",data.topic,string.toHex(data.payload))
+            log.info("mqttInMsg.proc",data.topic,data.payload)
+                
+            --TODO:根据需求自行处理data.payload
+        else
+            break
+        end
+    end
+	
+    return result or data=="timeout" or data=="APP_SOCKET_SEND_DATA"
+end

+ 97 - 0
mqttConnect/mqttOutMsg.lua

@@ -0,0 +1,97 @@
+--- 模块功能:MQTT客户端数据发送处理
+-- @author openLuat
+-- @module mqtt.mqttOutMsg
+-- @license MIT
+-- @copyright openLuat
+-- @release 2018.03.28
+
+
+module(...,package.seeall)
+
+--数据发送的消息队列
+local msgQueue = {}
+
+local function insertMsg(topic,payload,qos,user)
+    table.insert(msgQueue,{t=topic,p=payload,q=qos,user=user})
+    sys.publish("APP_SOCKET_SEND_DATA")
+end
+
+local function pubQos0TestCb(result)
+    log.info("mqttOutMsg.pubQos0TestCb",result)
+    if result then sys.timerStart(pubQos0Test,10000) end
+end
+
+function pubQos0Test()
+    insertMsg("/qos0topic","你好",0,{cb=pubQos0TestCb})
+end
+
+local function pubQos1TestCb(result)
+    log.info("mqttOutMsg.pubQos1TestCb",result)
+    if result then sys.timerStart(pubQos1Test,20000) end
+end
+
+function pubQos1Test()
+    insertMsg("/中文qos1topic","中文qos1data",1,{cb=pubQos1TestCb})
+end
+
+--- 初始化“MQTT客户端数据发送”
+-- @return 无
+-- @usage mqttOutMsg.init()
+function init()
+    -- pubQos0Test()
+    -- pubQos1Test()
+end
+
+--- 去初始化“MQTT客户端数据发送”
+-- @return 无
+-- @usage mqttOutMsg.unInit()
+function unInit()
+    sys.timerStop(pubQos0Test)
+    sys.timerStop(pubQos1Test)
+    while #msgQueue>0 do
+        local outMsg = table.remove(msgQueue,1)
+        if outMsg.user and outMsg.user.cb then outMsg.user.cb(false,outMsg.user.para) end
+    end
+end
+
+
+--- MQTT客户端数据发送处理
+-- @param mqttClient,MQTT客户端对象
+-- @return 处理成功返回true,处理出错返回false
+-- @usage mqttOutMsg.proc(mqttClient)
+function proc(mqttClient)
+    while #msgQueue>0 do
+        local outMsg = table.remove(msgQueue,1)
+        local result = mqttClient:publish(outMsg.t,outMsg.p,outMsg.q)
+        if outMsg.user and outMsg.user.cb then outMsg.user.cb(result,outMsg.user.para) end
+        if not result then return end
+    end
+    return true
+end
+
+
+
+
+---------------------------------
+-- 订阅 LoRa 主机的传感器数据更新事件
+---------------------------------
+sys.subscribe("SENSOR_UPDATE", function(data)
+    -- log.info("收到从机数据", json.encode(data))
+    -- 打包成 JSON
+    -- local payload = {
+    --     addr = addr,
+    --     ts   = ts,
+    --     data = data
+    -- }
+    local json_data = json.encode(data)
+
+    log.info("[MQTT] Upload", json_data)
+
+    -- 放入 MQTT 消息队列
+    insertMsg("/System_Fire_Warning/LoRa/Air724UG/Sensor/Data", json_data, 1, {
+        cb = function(result)
+            log.info("[MQTT] 上报结果", result and "成功" or "失败")
+        end
+    })
+end)
+

+ 71 - 0
mqttConnect/mqttTask.lua

@@ -0,0 +1,71 @@
+--- 模块功能:MQTT客户端处理框架
+-- @author openLuat
+-- @module mqtt.mqttTask
+-- @license MIT
+-- @copyright openLuat
+-- @release 2018.03.28
+
+module(...,package.seeall)
+
+require"misc"
+require"mqtt"
+require"mqttOutMsg"
+require"mqttInMsg"
+
+local ready = false
+
+--- MQTT连接是否处于激活状态
+-- @return 激活状态返回true,非激活状态返回false
+-- @usage mqttTask.isReady()
+function isReady()
+    return ready
+end
+
+--启动MQTT客户端任务
+sys.taskInit(
+    function()
+        local retryConnectCnt = 0
+        while true do
+            if not socket.isReady() then
+                retryConnectCnt = 0
+                --等待网络环境准备就绪,超时时间是5分钟
+                sys.waitUntil("IP_READY_IND",300000)
+            end
+            
+            if socket.isReady() then
+                local imei = misc.getImei()
+                --创建一个MQTT客户端
+                local mqttClient = mqtt.client(imei,600,"user","password")
+                --阻塞执行MQTT CONNECT动作,直至成功
+                --如果使用ssl连接,打开mqttClient:connect("lbsmqtt.airm2m.com",1884,"tcp_ssl",{caCert="ca.crt"}),根据自己的需求配置
+                --mqttClient:connect("lbsmqtt.airm2m.com",1884,"tcp_ssl",{caCert="ca.crt"})
+                if mqttClient:connect("www.kemande.cn",1883,"tcp") then
+                    retryConnectCnt = 0
+                    ready = true
+                    --订阅主题
+                    if mqttClient:subscribe({["/System_Fire_Warning/LoRa/Air724UG/Event/0"]=0, ["/System_Fire_Warning/LoRa/Air724UG/Event/1"]=1}) then
+                        mqttOutMsg.init()
+                        --循环处理接收和发送的数据
+                        while true do
+                            if not mqttInMsg.proc(mqttClient) then log.error("mqttTask.mqttInMsg.proc error") break end
+                            if not mqttOutMsg.proc(mqttClient) then log.error("mqttTask.mqttOutMsg proc error") break end
+                        end
+                        mqttOutMsg.unInit()
+                    end
+                    ready = false
+                else
+                    retryConnectCnt = retryConnectCnt+1
+                end
+                --断开MQTT连接
+                mqttClient:disconnect()
+                if retryConnectCnt>=5 then link.shut() retryConnectCnt=0 end
+                sys.wait(5000)
+            else
+                --进入飞行模式,20秒之后,退出飞行模式
+                net.switchFly(true)
+                sys.wait(20000)
+                net.switchFly(false)
+            end
+        end
+    end
+)