Browse Source

add: 为air302添加一个demo,演示上传温度数据到tlink平台,默认间隔2分钟,使用ds18b20

Wendal Chen 5 years ago
parent
commit
8825f559d7
1 changed files with 198 additions and 0 deletions
  1. 198 0
      bsp/air302/demo/tlink_udp_ds18b20/main.lua

+ 198 - 0
bsp/air302/demo/tlink_udp_ds18b20/main.lua

@@ -0,0 +1,198 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "tlink"
+VERSION = "1.0.0"
+
+--[[
+本示例用于演示定时把文档数据传输到tlink平台, 由tlink平台进行处理, 并在网页端和手机端进行展示
+
+本示例需要使用中国移动或者中国联通NB专有卡, 普通2G/3G/4G卡无法保证正常
+
+-- 设备端接线
+
+1. Air302开发板一块
+2. DS18B20传感器一个
+    - 需要带上拉电阻4.7k
+    - 数据端接入模块/开发板的GPIO17
+    - VCC接入VDDIO或其他3.3V供电脚
+    - GND接入模块的GND
+
+--- tlink网页端的配置
+
+1. 首先, 请到 http://tlink.io 注册账号, 普通账号即可, 无需企业版
+2. 然后, 登录后台, 在左侧菜单, 选择 "设备管理", 然后点击 "添加设备"
+3. 新增设备时
+    - 3.1 设备名称自选(例如模块的IMEI值)
+    - 3.2 链接协议 选"UDP"
+    - 3.3 掉线延时 选"300秒"
+    - 3.4 传感器, 点"追加",会新增一行
+        - 3.4.1 传感器名称, 填"温度传感器"
+        - 3.4.2 类型, 选 "数值型"
+        - 3.4.3 小数位, 选 "1(小数位)"
+        - 3.4.4 单位, 填"摄氏度"
+        - 3.4.5 地图, 随便选一个地址就行
+    - 3.5 滚动屏幕到底部, 点击"创建设备", 完成基本创建
+4. 返回设备列表后, 点击新设备的"设置连接"
+    - 4.1 重点, 设备信息展示栏的 "序列号", 点击最后一个图标(修改)
+        - 4.1.1 填入值 0 和 模块的IMEI值, 共16位
+        - 4.1.2 例如模块的IMEI为 867814046436255, 则填入 0867814046436255
+    - 4.2 点击 "数据头标签" "[H:数据]", 填入 一个字符  "#" 即井号
+    - 4.3 点击 "数据标签" "D?"
+    - 4.4 点击 "结束符标签" "[回车换行]"
+    - 4.5 点击 "保存协议", 则 "当前协议" 会显示为 "[H:]  [D?]  [TE:0D0A]"
+5. 返回设备列表, 至此, 网页端的配置就完成了
+
+参考文档: 
+    - 创建设备 https://www.tlink.io/help.htm?menu=2
+    - UDP 协议 https://www.tlink.io/help.htm?menu=2&page=46
+    - 安卓APP  https://www.tlink.io/help.htm?menu=2&page=116
+
+注意事项:
+    - 本demo是适合单传上传数据的场景,不适合有数据下发的场景
+    - 由UDP的特性决定, 不能100%保证数据能上报成功
+]]
+
+local sys = require "sys"
+
+-----------------------------------------------------------------------------------
+--PM异常唤醒检测  休眠时间最低120S
+--- pm_wakeup_time_check() 读取上次设置hib时间,并且与本次时间作比较,异常唤醒将直接睡眠
+-- @return 无
+function pm_wakeup_time_check ()
+    log.info("pm", pm.lastReson())
+    if pm.lastReson() == 1 then
+        local tdata = lpmem.read(512, 6) -- 0x5A 0xA5, 然后一个32bit的taskInit
+        local _, mark, tsleep = pack.unpack(tdata, ">HI")
+        if mark == 0x5AA5 then
+            local tnow = os.time()
+            log.info("pm", "sleep time", tsleep, tnow)
+			--下面的120S根据休眠时间设置,最大可以设置休眠时间-12S。
+            if tnow - tsleep < (120 - 12) then
+                pm.request(pm.HIB) -- 建议休眠
+                return -- 是提前唤醒, 继续睡吧
+            end
+        end
+    end
+    return true
+end
+
+--- PM进入休眠
+-- @param sec 进入hib深睡眠时间,单位:秒
+-- @返回值: 无
+-- @ pm_enter_hib_mode(sec)
+function pm_enter_hib_mode(sec)
+    --设置休眠唤醒时间,并开启休眠
+    lpmem.write(512, pack.pack(">HI", 0x5AA5, os.time())) -- 把当前时间写入lpmem
+    pm.dtimerStart(0, sec*1000)
+    pm.request(pm.HIB) -- 建议休眠
+    --log.info("pm check",pm.check())
+    --sys.wait(300*1000)
+end
+
+-----------------------------------------------------------------------------------------
+
+-- 读取ds18b20的数据
+function get_data()
+    local data = nil
+    for i=1,10 do -- 读取时存在失败的可能性,所以需要尝试多次
+        local temp, result = sensor.ds18b20(17)
+        if result and temp ~= 250 then
+            -- 数据格式对应 [H:]  [D?]  [TE:0D0A]
+            data = string.format( "0%s#%d\r\n", nbiot.imei(), math.floor(temp))
+            log.info("data", data)
+            log.info("data.hex", data:toHex())
+            break
+        end
+        sys.wait(2000)
+    end
+    return data
+end
+
+-- 主任务
+function main_task()
+    -- 等待联网
+    while not socket.isReady() do sys.wait(1000) end
+    -- 建立netclient对象
+    local netc = socket.udp()
+    netc:host("47.106.61.135") -- 这里对应的 udp.tlink.io 的IP地址
+    netc:port(9896)            -- UDP协议的端口号
+    -- 配置好回调
+    netc:on("connect", function(id, re)
+        log.info("netc", "connect", id, re)
+        sys.taskInit(function()
+            local data = get_data()
+            if data then
+                log.info("netc", "send reg package", data)
+                netc:send(data, 2)
+            end
+            sys.publish("NETC_OK")
+        end)
+    end)
+    netc:on("recv", function(id, data)
+        -- 注意, 唤醒操作, 调用netc:rebind后, 如果基站有缓存的数据, 这里就会被触发
+        log.info("netc", "recv", id, data)
+        --netc:send(data)
+    end)
+    -- 检查开机原因
+    local flag = false
+    log.info("pm", "lastReson", pm.lastReson())
+    -- 非普通上电/复位上电,那就是唤醒上电咯
+    if pm.lastReson() ~= 0 then
+        -- 读取低功耗内存的 0x5A 0xA5 ? ? ? ?
+        local data = lpmem.read(0, 6)
+        -- 打印内容,方便调试
+        log.info("lpmem", data:toHex())
+        -- 使用pack库解析之
+        local _, t1,t2,sockid = pack.unpack(data, ">bbI")
+        -- 头两个字符是我们自定义的0x5A 0xA5,不是的话,就肯定是脏数据了
+        if t1 == 0x5A and t2 == 0xA5 then
+            netc:rebind(sockid) -- 重建tcp上下文
+            local data = get_data()
+            if data then
+                netc:send(data, 2) -- 发送心跳
+            end
+            flag = true
+        else
+            -- 脏数据就不管了
+            log.info("lpmem", "bad custom lpmem data, skip")
+        end
+    end
+    -- 如果不唤醒流程, 或者数据是脏的,就新建连接
+    if not flag then
+        -- 启动tcp连接线程
+        if netc:start() == 0 then
+            sys.waitUntil("NETC_OK", 15000)
+            if netc:closed() == 0 then
+                -- 启动成功, 那就把sockid放入低功耗内存,在唤醒时重建上下文.
+                lpmem.write(0, pack.pack(">bbI", 0x5A, 0xA5, netc:sockid()))
+            else
+                -- 启动,那就重启吧 or 重试2次?
+                log.warn("Start netc FAIL!!!")
+                sys.wait(15000)
+                rtos.reboot()
+            end
+        else
+            -- socket线程都启动失败?什么情况啊
+            log.warn("Start netc FAIL!!!")
+            sys.wait(5000)
+            rtos.reboot()
+        end
+    end
+    -- 要求进入休眠状态,省电. 
+    -- 如修改休眠时长, 务必做到 "同比例"修改pm_wakeup_time_check里面的检测时长
+    pm_enter_hib_mode(120)
+end
+
+-- 先判断休眠是否够了, 然后再执行主任务
+sys.taskInit(function()
+    if pm_wakeup_time_check() then
+        main_task()
+    else
+        log.info("pm", "too early, back to hib")
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!