跳转至

01 短消息(sms)

作者:王城钧 | 最后修改:2026-04-09

一、SMS 简介

SMS(短消息服务,Short Message Service)功能主要用于在蜂窝网络中传输短消息。

移动,联通卡不需开通 VOLTE 可以支持短信功能。使用电信卡 SMS 短信功能时请务必选择同时支持 CC(VoLTE 通话)的固件版本并且需要电信卡开通 VoLTE 功能

在 4G 网络中,短信可以在数据传输的同时进行,不会因数据业务占用网络资源而被延迟或阻塞。

二、演示功能概述

本 demo 演示了向运营商发送话费查询短信后,收到回复的短信,将回复的短信转发给飞书,钉钉,企业微信机器人。

三、准备硬件环境

参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。

四、软件环境

在开始实践本示例之前,先筹备一下软件环境:

1.Luatools 工具

2.本demo开发测试时使用的固件为LuatOS-SoC_V2018_Air780EPM 106号固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件Air780EPM固件Air780EHM固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;

3.luatos 需要的脚本和资源文件

脚本和资源文件点我查看 demo 地址

lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;

准备好软件环境之后,接下来查看如何烧录项目文件到 Air780EPM 开发板,将本篇文章中演示使用的项目文件烧录到 Air780EPM 开发板中。

五、转发机器人设置介绍

5.1 钉钉机器人

打开钉钉主界面,鼠标左键点击消息框,然后再用鼠标左键点击一个内部群

打开群设置

点击机器人设置

选择自定义机器人

设置对应参数

记住 webhook 参数,然后点击完成

5.2 飞书机器人

在飞书界面鼠标左键点击消息框,然后鼠标左键点击选择一个内部群

鼠标左键点击右上角三个点

鼠标左键点击设置

鼠标左键打开群机器人

添加自定义机器人

自行设置机器人

复制 webhook 地址以及 secret(可选)

5.3 企业微信机器人

企业微信,找到需要接收消息的内部群,右键单击管理聊天信息

注意:此操作只有这个群的管理员才可以进行。

鼠标左键点击消息推送

设置机器人信息,并复制 webhook 地址

六、代码示例介绍

只需配置平台信息后,后台自动循环发送话费查询短信,同时监听新短信,收到后自动转发到指定办公平台。

本 demo 的效果是给运营商发短信消息,查询话费信息,并将接收的短信自动转发到飞书、钉钉、企业微信。

6.1 发送短信

设备就绪后,等待系统发布"CC_IND"准备就绪消息,然后每隔 10 分钟自动向电信运营商发送话费查询短信,并持续输出设备相关信息。

**local function send_sms()
**    **--按照规范的做法,这里应该等待"SMS_READY"消息,
    --目前内核固件正在开发支持"SMS_READY"消息功能,
    --等开发好了之后,再使用"SMS_READY"消息,
    --当前阶段,先使用"IP_READY"替代
    sys.waitUntil("IP_READY")
    sys.wait(5000) 
    -- 当前阶段等待5s,使得sms准备就绪,待"SMS_READY"消息开发完成后,删除如上两行代码使用sys.waitUntil("SMS_READY")替代
    log.info("发送短信准备就绪")
    local cont = 1
    log.info("开始发短信")
    while true do
        log.info("现在可以收发短信")

        --获取本机号码,如果卡商没写入会返回nil
        log.info("mobile.number(id) = ", mobile.number())
        --获取本机iccid,如果卡商没写入会返回nil
        log.info("mobile.iccid(id) = ", mobile.iccid())
        --获取本机simid,如果卡商没写入会返回nil
        log.info("mobile.simid(id) = ", mobile.simid())
        --获取本机imsi,如果卡商没写入会返回nil
        log.info("mobile.imsi(index) = ", mobile.imsi())
        -- 注意:以下查话费的三行代码只需根据自己卡的运营商打开其一即可,其余两行关闭,不要全部打开
        -- 电信卡查话费
        local result = sms.send("10001", "102")
        -- 中移动卡查短信
        -- local result = sms.send("10086", "301")
        -- 联通卡查话费
        -- local result = sms.send("10010", "101")
        -- 注意:V2018及更高版本固件才有"SMS_SENT"系统消息
        if result then
            local wait_msg, success  = sys.waitUntil("SMS_SENT", 10000)
            log.info("发送查询短信", "这是第" .. cont .. "次发送", " 发送结果:", wait_msg and (success and "成功" or "失败") or "超时")
        else
            log.info("发送查询短信", "这是第" .. cont .. "次发送", " 发送结果:同步发送失败")
        end
        log.info("等待10分钟")
        cont = cont + 1
        sys.wait(10 * 60 * 1000)
    end
****end**

6.2 接收短信

持续等待并接收新短信,获取短信相关信息后,进回调函数进行后续操作。

local function receive_sms()
    while true do
        local ret, num, txt = sys.waitUntil("SMS_INC", 30000)
        log.info("收到来自短信:", num)
        if num then
            log.info("num是", num)
            log.info("收到来自" .. num .. "的短信:" .. txt)

            --local isReady1, index1 = socket.adapter()
            log.info("当前网络", socket.adapter())

            sms_handler(num, txt)
        end
    end
end

6.3 接收短信回调函数

收到的短信(包含发送号码和内容)依次转发到飞书、钉钉、微信三个平台

local function sms_handler(num, txt)
    -- num 给我发短信的手机号码
    -- txt 收到的短信文本内容

    log.info("转发到飞书")
    feishu_post_sms(num, txt)

    --等待1秒, 非必须
    sys.wait(1000)
    log.info("转发到钉钉")
    dingding_post(num, txt)

    --等待1秒, 非必须
    sys.wait(1000)
    log.info("转发到微信")
    weixin_post(num, txt)
end

6.4 平台信息转发函数

根据各平台的接口规范,将短信信息格式化并通过 HTTP 请求转发。

--1.功能函数:短信转发到飞书
**local** **function** **feishu_post_sms**(num, rctxt)
    **local** rheaders = {}
    rheaders["Content-Type"] = "application/json"

    -- LuatOS的时间戳只到秒,飞书也只需要秒
    **local** timestamp = tostring(os.time())
    **local** sign = crypto.hmac_sha256("", timestamp .. "\n" .. secret_feishu):fromHex():toBase64()
    log.info("timestamp", timestamp)
    log.info("sign", sign)
    -- 注意, 这里的参数跟钉钉不同, 钉钉有个access_token参数, 飞书没有
    **local** url = webhook_feishu
    log.info("url", url)
    -- json格式也需要按飞书的来
    **local** data = { msg_type = "text" }
    data["timestamp"] = timestamp
    data["sign"] = sign
    -- text就是要发送的文本内容, 其他格式按飞书的要求拼接table就好了
    **local** text = "我的id是" ..
        tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ",    " .. num .. "发来短信,内容是:" .. rctxt
    data["content"] = { text = text }
    **local** rbody = (json.encode(data))
    log.info("feishu", rbody)
    **local** code, headers, body = http.request("POST", url, rheaders, rbody, { timeout = 5000 }).wait()
    -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
    -- 其他错误, 一般是密钥错了, 仔细检查吧
    log.info("飞书机器人", 
    code==200 and "success" or "error", 
    code, 
    json.encode(headers or {}), 
    body and (body:len()>512 and body:len() or body) or "nil")
**end**

--2.功能函数:短信转发到钉钉
**local** **function** **dingding_post**(num, rctxt)
    **local** rheaders = {}
    rheaders["Content-Type"] = "application/json"
    -- LuatOS的时间戳只到秒,但钉钉需要毫秒,补3个零
    **local** timestamp = tostring(os.time()) .. "000"
    **local** sign = crypto.hmac_sha256(timestamp .. "\n" .. secret_dingding, secret_dingding):fromHex():toBase64()
        :urlEncode()
    log.info("timestamp", timestamp)
    log.info("sign", sign)
    **local** url = webhook_dingding .. "&timestamp=" .. timestamp .. "&sign=" .. sign
    log.info("url", url)
    **local** data = { msgtype = "text" }
    -- content就是要发送的文本内容, 其他格式按钉钉的要求拼接table就好了
    **local** content = "我的id是" ..
        tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ",    " .. num .. "发来短信,内容是:" .. rctxt
    data["text"] = { content = content }
    **local** rbody = (json.encode(data))
    log.info("dingding", rbody)
    **local** code, headers, body = http.request("POST", url, rheaders, (json.encode(data))).wait()
    -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
    -- 其他错误, 一般是密钥错了, 仔细检查吧
    log.info("钉钉机器人", 
    code==200 and "success" or "error", 
    code, 
    json.encode(headers or {}), 
    body and (body:len()>512 and body:len() or body) or "nil")
**end**

--3.功能函数:短信转发到企业微信
**local** **function** **weixin_post**(num, rctxt)
    **local** rheaders = {}
    rheaders["Content-Type"] = "application/json"

    **local** timestamp = tostring(os.time()) .. "000"
    log.info("timestamp", timestamp)
    **local** url = webhook_weixin .. "&timestamp=" .. timestamp
    log.info("url", url)
    **local** data = { msgtype = "text" }
    -- content就是要发送的文本内容, 其他格式按钉钉的要求拼接table就好了
    **local** content = "我的id是" ..
        tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ",    " .. num .. "发来短信,内容是:" .. rctxt
    data["text"] = { content = content }
    **local** rbody = (json.encode(data))
    log.info("weixin", rbody)
    **local** code, headers, body = http.request("POST", url, rheaders, (json.encode(data))).wait()
    -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
    -- 其他错误, 一般是密钥错了, 仔细检查吧
    log.info("企业微信机器人", 
    code==200 and "success" or "error", 
    code, 
    json.encode(headers or {}), 
    body and (body:len()>512 and body:len() or body) or "nil")
**end**

七、功能验证

烧录代码,插入自己的手机卡,本演示使用的为电信手机卡,日志如下:

钉钉界面群消息转发如下:

飞书界面群消息转发如下:

企业微信界面群消息转发如下:

八、总结

至此,我们演示了 sms 短信转发的全过程。

常见问题

1、物联网卡支持短信功能吗?

一般来说,物联网卡是不支持短信功能的,具体需要咨询物联网卡供应商。

2、支持移动、电信,联通卡的短信功能吗?

1,对于移动/联通卡来说,SMS 短信功能合宙所有全网通 4G 模组都默认支持;

2,对于某些只支持单一运营商的型号,比如只支持移动运营商的 Air700ECH/Air700ECT,则相应的也只支持移动卡的 SMS 短信功能;

3,有些流量卡可能没有开通 SMS 短信功能,请咨询卡商或运营商确认,无法确认时建议用自己的手机卡测试确认;

4,再次提醒!由于合宙二次开发型号模组支持多种固件版本,使用电信卡 SMS 短信功能时请务必选择支持电信卡 SMS 短信功能的固件版本;

3、是否支持彩信功能

不支持

4、短信功能发送英文短信、 中文短信,分别怎么发? 发长短信怎么发?

发送英文短信、中文短信、中英文混合短信可参考下方代码块中的 sms.send 接口使用示例:

local function sms_task()
    sys.wait(10000)
    -- 中移动卡查短信
    -- sms.send("+8610086", "301")
    -- 联通卡查话费
    sms.send("10010", "101")
    local sms1 = sms.send("num", "TEST")
    log.info("英文短信",sms1)
    sys.wait(5000)
    local sms2 = sms.send("num", "你好") 
    log.info("中文短信",sms2)
    sys.wait(5000)
    local sms3 = sms.send("num", "你好test")
    log.info("中英文混合",sms3)

end
sys.taskInit(sms_task)

发送长短信可在文本部分填入,英文算 1 个字节,中文算 2 个字节。

发送长短信可参考下方代码块中的 sms.sendLong 接口使用示例:

local function send_long_sms_task()
    -- 等待短信就绪(根据实际情况,可以等待CC_IND或SMS_READY)
    log.info("sms", "等待短信就绪...")
    sys.waitUntil("CC_IND")
    log.info("sms", "短信功能已就绪,可以开始发送长短信")

    -- 构造一个150字节的短信内容
    -- 中文字符通常占用更多字节,这里使用英文字符确保准确控制长度
    local msg_content = string.rep("1234567890", 15)  -- 每个"1234567890"是10个字节,重复15次正好是150字节

    -- 接收短信的手机号码(请替换为实际需要发送的号码)
    local phone_number = "+8613800138000"  -- 示例号码

    -- 使用sms.sendLong发送长短信,并等待发送结果
    log.info("sms", "开始发送150字节长短信...")
    local result = sms.sendLong(phone_number, msg_content).wait()
    log.info("短信内容",result)
end
sys.taskInit(send_long_sms_task)