跳转至

63 sms-短信

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

声明:本介绍为技术支持页面,禁止用于非法用途,请遵守国家法律法规要求。

短信转发为中性物联网技术,仅限本人实名登记 SIM 卡,用于企业合法内部运维。严禁用于代他人接收短信、接码、批量注册账号等违法行为,使用者承担全部法律责任。

一、概述

sms 库提供了短信相关功能,包括异步发送短信、同步发送短信、设置新短信回调函数、设置长短信自动合并模式以及清除长短信缓存的功能

1、对于电信卡来说,SMS 短信功能跟核心库 CC(VoLTE 通话)是伴生关系,只有支持 CC 核心库的固件才支持电信卡的 SMS 短信功能;

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

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

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

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

短信编码说明(GSM7 与 UCS2)

6、短信内容在发送时,底层会根据内容自动选择编码方式:

  • 若短信内容全部为 ASCII 可见字符(纯英文/数字/符号),则使用 GSM7 编码(7bit GSM Default);

  • 若短信内容包含非 ASCII 字符(如中文、emoji 等),则自动切换为 UCS2 编码(16bit Unicode);

7、接收短信时,底层同样支持 GSM7 和 UCS2 两种编码的自动解析,无需用户手动处理编码格式;

8、发送和接收短信的 GSM7/UCS2 自适应编码功能,从780EXX/8000 v2034 固件版本开始支持;

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/sms

-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "smsdemo"
VERSION = "001.000.001"

log.info("main", PROJECT, VERSION)


if wdt then
    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
    wdt.init(9000)--初始化watchdog设置为9s
    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
log.info("main", "sms demo")

-- 辅助发送http请求, 因为http库需要在task里运行
function http_post(url, headers, body)
    local function http()
        local code, headers, body = http.request("POST", url, headers, body).wait()
        log.info("resp", code)
    end
    sys.taskInit(http)
end

function sms_handler(num, txt)
    -- num 手机号码
    -- txt 文本内容
    log.info("sms", num, txt, txt:toHex())

    -- http演示1, 发json
    local body = json.encode({phone=num, txt=txt})
    local headers = {}
    headers["Content-Type"] = "application/json"
    log.info("json", body)
    http_post("http://www.luatos.com/api/sms/blackhole", headers, body)
    -- http演示2, 发表单的
    headers = {}
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    local body = string.format("phone=%s&txt=%s", num:urlEncode(), txt:urlEncode())
    log.info("params", body)
    http_post("http://www.luatos.com/api/sms/blackhole", headers, body)
    -- http演示3, 不需要headers,直接发
    http_post("http://www.luatos.com/api/sms/blackhole", nil, num .. "," .. txt)
    -- 如需发送到钉钉, 参考 demo/dingding
    -- 如需发送到飞书, 参考 demo/feishu
end

--------------------------------------------------------------------
-- 接收短信, 支持多种方式, 选一种就可以了
-- 1. 设置回调函数
--sms.setNewSmsCb(sms_handler)
-- 2. 订阅系统消息
--sys.subscribe("SMS_INC", sms_handler)
-- 3. 在task里等着
local function sms_sub()
    while true do
        local ret, num, txt = sys.waitUntil("SMS_INC", 300000)
        if num then
            -- 方案1, 交给自定义函数处理
            sms_handler(num, txt)
            -- 方案2, 因为这里是task内, 可以直接调用http.request
            -- local body = json.encode({phone=num, txt=txt})
            -- local headers = {}
            -- headers["Content-Type"] = "application/json"
            -- log.info("json", body)
            -- local code, headers, body = http.request("POST", "http://www.luatos.com/api/sms/blackhole", headers, body).wait()
            -- log.info("resp", code)
        end
    end
end
sys.taskInit(sms_sub)

-------------------------------------------------------------------
-- 发送短信, 直接调用sms.send就行, 是不是task无所谓
local function sms_send()
     sys.wait(10000)
    -- 中移动卡查短信
     sms.send("+8610086", "301")
    -- 联通卡查话费
    -- sms.send("10010", "101")
end
sys.taskInit(sms_send)



-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;

如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;

"SMS_INC"

消息类型:string
消息含义:表示收到短信内容
注意事项:普通短信(非长短信):
         每收到一条短信,立即执行回调函数。
         长短信(多条短信组成的完整消息):
         必须所有短信片段接收完成后才会执行一次回调,不会每收到一条片段就触发回调。
参数示例:
-- 接收短信, 支持多种方式, 选一种就可以了
-- 1. 设置回调函数
local function handleNewSms(phone, sms)  
    log.info("sms", phone, sms)  
end   
sms.setNewSmsCb(handleNewSms)

-- 2. 订阅系统消息
local function handleSmsInc(phone, sms)  
    log.info("sms", phone, sms)  
end  
sys.subscribe("SMS_INC", handleSmsInc)

"SMS_READY"

消息类型:string
消息含义:表示短信功能初始化完成,此时可以正常收发短信。
注意事项:建议在发送或接收短信前先等待该消息,确保短信模块已就绪。
          SM 卡注册网络后底层才会发出此消息,未插卡或未注册网络时不会触发。
参数示例:-- 等待短信就绪后发送短信
sys.subscribe("SMS_READY", function(id)
    log.info("sms", "ready, sim id:", id)
    sms.send("10010", "101")
end)

"SMS_SENT"

消息类型:string
消息含义:表示短信发送操作的最终结果通知,包含发送成功或失败的状态信息。
注意事项:普通短信(非长短信):
         每发送一条短信,当网络返回发送结果后立即触发一次该消息。
         由于 sms.send() 是异步操作,其返回值仅表示发送请求是否成功提交,而非实际发送结果。
         长短信(多条短信组成的完整消息):
         仅在所有短信片段全部发送完成后才会触发一次该消息。
         不会对每个短信片段单独触发消息,确保应用层只收到一次完整的发送结果。
         对于长短信,建议使用 sms.sendLong().wait() 方式获取发送结果。
回调参数:
result 
参数含义:短信向SMSC提交的整体结果 
数据类型:boolean 
取值范围:truefalse 
是否必选:回调固定输出; 
注意事项:true代表短信中心已接收短信true仅代表提交成功,不等于收件人收到短信;
         false代表提交失败
参数示例:true

rp_cause 
参数含义:3GPP RPCause协议错误码 
数据类型:number 
取值范围:0255 
是否必选:回调固定输出; 
注意事项:RP层协议错误,仅 error_code=0 并且 result=false 场景下有效;
         用于识别空号、停机等运营商侧返回业务错误; 
         130表示空号;
         1050表示停机;
         27表示用户不在线;
参数示例:0

rp_cause_str 
参数含义:RPCause错误码对应的文本描述 
数据类型:string 
取值范围:暂无; 
是否必选:回调固定输出; 
注意事项:对rp_cause的可读文字说明,方便日志排查; 
参数示例:SUCCESS

msg_ref 
参数含义:短信消息参考编号; 
数据类型:number 
取值范围:0255 
是否必选:回调固定输出; 
注意事项:短信唯一标识,用于和SMS_REPORT回执事件做消息匹配;多条并发短信依靠此字段一一对应回执; 
参数示例:123

error_code 
参数含义:SDK层短信错误码 
数据类型:number 
取值范围:0300330331332500 
         0表示提交成功,短信中心接受;
         300表示设备故障;
         330表示短信中心地址未知;
         331表示无网络服务 / SIM 未开通短信业务;
         332表示网络超时;
         500表示未知错误;
是否必选:回调固定输出; 
注意事项:业务判断优先使用此字段;0代表提交成功,非0代表 网络/SIM/设备类故障; 
参数示例:0

参数示例:-- 短信提交事件完整回调示例 
local function sms_sent_cb(result, rp_cause, rp_cause_str, msg_ref, error_code)     
    log.info("SMS_SENT", "result=", result, "rp_cause=", rp_cause, "str=", rp_cause_str, "msg_ref=", msg_ref, "error_code=", error_code)
end 
 sys.subscribe("SMS_SENT", sms_sent_cb)

"SMS_REPORT"

消息类型:string
消息含义:表示短信状态回执事件,返回接收方手机真实投递结果(送达/失败)。
注意事项:该消息V2048及以后版本支持
         必须在调用 sms.send() 将回执参数设置为 true,才会收到该事件;否则不会触发。           
         msg_ref 用于和 SMS_SENT  msg_ref 做消息匹配,多条并发短信依赖该编号区分对应回执。           
         status=0x46 代表消息超过VP有效期被短信中心丢弃,与 setVp / send接口vp参数配置强相关
回调参数:
msg_ref 
参数含义:短信消息参考编号; 
数据类型:number 取值范围:0255 
是否必选:回调固定输出; 
注意事项:与SMS_SENT回调输出的msg_ref一一对应,用于匹配对应短信的投递回执; 
参数示例:12

status 
参数含义:短信投递ST状态码 
数据类型:number 
取值范围:0x000x200x220x230x430x46 
         0x00表示成功送达;
         0x20表示网络拥塞临时失败;
         0x22表示用户关机/不在线无响应;
         0x23表示服务拒绝,大概率停机;
         0x43表示不可达,空号/停机;
         0x46表示超过VP有效期,消息丢弃;
是否必选:回调固定输出; 
注意事项:0x00为成功送达,其余为各类投递失败状态; 
参数示例:0x00

status_str 
参数含义:ST状态码对应的文本描述 
数据类型:string 
取值范围:暂无; 
是否必选:回调固定输出; 
注意事项:status的可读文字说明,用于日志排查; 
参数示例:"SUCCESS"

phone 
参数含义:短信接收方手机号码; 
数据类型:string 
取值范围:暂无; 
是否必选:回调固定输出; 
注意事项:目标接收号码; 
参数示例:"13800138000"

discharge_time 
参数含义:送达或投递失败发生的时间; 
数据类型:string 
取值范围:暂无; 
是否必选:回调固定输出; 
注意事项:短信中心上报事件的时间; 
参数示例:"2026‑08‑19 15:20:30"

参数示例:-- 短信提交事件完整回调示例 
local function sms_report_cb(msg_ref, status, status_str, phone, discharge_time)     
    log.info("SMS_REPORT", "msg_ref=", msg_ref, "status=", status, "str=", status_str, "phone=", phone, "time=", discharge_time) 
end
sys.subscribe("SMS_REPORT", sms_report_cb)

四、函数详解

sms.send(phone, msg, auto_phone_fix, need_report ,vp)

功能

异步发送短信,通过返回值确认任务启动状态,底层"SMS_SENT"消息获取最终发送结果。

参数

phone

参数含义:表示电话号码;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"13188888888"

msg

参数含义:短信内容,编码格式为UTF-8的字符串;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:单条短信最大为140字节,一个英文算一个字节,一个中文算2个字节;
         sendLong的主要差异为异步发送模式
参数示例:"101"

auto_phone_fix

参数含义用于控制是否自动修正电话号码格式
         当auto_phone_fix=true时默认值
         系统会对电话号码进行智能处理具体规则如下
         1.如果电话号码以'+'开头例如"+8613416121234"),会自动移除'+'保留后面的部分
         2.如果电话号码不以'86'开头中国国家代码),会自动在号码前面添加'86'
         3.如果电话号码已经以'86'开头则保持不变
         当auto_phone_fix=false时
         系统会直接使用用户传入的电话号码不做任何自动处理和格式调整
         -- 自动处理模式
         -- 输入sms.send("+8613416121234", "Hello"true)
         -- auto_phone_fix=true(默认)
         -- 实际发送的号码"8613416121234"自动去掉'+'

         -- 禁用自动处理
         -- 输入sms.send("+8613416121234", "Hello", false)
         -- 实际发送的号码"+8613416121234"保持原样
         默认true
数据类型boolean
取值范围true/false
是否必选可选传入此参数
注意事项暂无
参数示例true

need_report

参数含义:表示是否请求短信回执(状态报告),默认false不请求,
         设置为true后,无论短信最终是成功送达还是投递失败、超时丢弃,均会触发SMS_REPORT事件上报投递状态
数据类型:boolean
取值范围:true/false
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

vp

参数含义:短信中心最大重试有效期,短信下发后,接收方关机 / 无信号时,短信中心会在该时间内持续尝试投递;
         超时未送达则短信直接丢弃;
数据类型:number
取值范围:0255
是否必选:可选传入此参数;
注意事项: 该参数在V2050及以后版本支持
         该值是协议标准编码值,不是直接填小时 / 天数,需要按照下表公式换算得到实际时长
         最终生效时间受短信中心最大上限约束,即使 VP 算出来 7 天,
         若运营商 SMSC 上限只有 72 小时,则实际按 72 小时生效;
         与回执参数无关:回执 boolean 只控制是否上报送达报告,VP 控制消息在网关侧保存多久 
         参数示例:169,计算:169166 =3 =72小时;
参数示例:169

VP 完整换算表

vp 值 计算公式 实际有效期范围
0‑143 (vp+1) ×5 分钟 5 分钟~12 小时
144‑167 12h + (vp‑143) ×30 分钟 12 ~ 24 小时
168‑196 (vp‑166) 天 2 ~ 30 天
197‑255 (vp‑192) 周 5 周~63 周

返回值

local result = sms.send(phone, msg, auto_phone_fix, need_report ,vp)

result

含义说明:短信发送结果,
         sms.send 的同步结果仅表示任务启动成功,
         最终发送状态需通过异步事件 "SMS_SENT" 获取;
数据类型:boolean
取值范围:true或者false
注意事项:暂无;
返回示例:true

示例

sms.send("10010", "101", true, true, 169)

sms.sendLong(phone, msg, auto_phone_fix).wait()

功能

同步发送短信,只可以在 task 中运行,支持长级联短信;

参数

phone

参数含义:表示电话号码;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"13188888888"

msg

参数含义:短信内容,编码格式为UTF-8的字符串;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:支持长短信(长级联短信),底层会根据内容自动选择编码方式:
         1. ASCII字符(英文/数字/符号)→ GSM7编码
         2. 包含非ASCII字符(如中文)→ UCS2编码
         长短信单分片大小最大134字节,最大分片数量128片;
          sms.send 相比,核心差异在于同步发送模式,支持长级联短信自动拆分;
         如果超过最长限制,会出现下列情况:
         1. 直接返回失败,表示发送任务未启动。
         2. 自动截断并发送部分内容
         3. 触发模块内部错误调用后无返回(卡死)
            或抛出异常(如内存不足、缓冲区溢出)
参数示例:"祝你天天开心!"

auto_phone_fix

参数含义:用于控制是否自动修正电话号码格式,
         auto_phone_fix=true时(默认值)
         系统会对电话号码进行智能处理,具体规则如下:
         1.如果电话号码以'+'开头(例如"+8613416121234"),会自动移除'+'号,保留后面的部分
         2.如果电话号码不以'86'开头(中国国家代码),会自动在号码前面添加'86'
         3.如果电话号码已经以'86'开头,则保持不变
         auto_phone_fix=false时
         系统会直接使用用户传入的电话号码,不做任何自动处理和格式调整
         -- 自动处理模式
         -- 输入:sms.send("+8613416121234", "Hello",true) 
         -- auto_phone_fix=true(默认)
         -- 实际发送的号码:"8613416121234"(自动去掉'+'号)

         -- 禁用自动处理
         -- 输入:sms.send("+8613416121234", "Hello", false)
         -- 实际发送的号码:"+8613416121234"(保持原样)
         默认true
数据类型:boolean
取值范围:true/false
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

返回值

local result = sms.sendLong(phone, msg, auto_phone_fix).wait()

result

含义说明:短信发送结果;
数据类型:boolean
取值范围:true或者false
注意事项:暂无;
返回示例:true

示例

sms.sendLong("10010", "101").wait()

sms.setNewSmsCb(func)

功能

设置接收到新短信的回调函数,

  1. 普通短信(非长短信):每收到一条短信,立即执行回调函数。
  2. 长短信(多条短信组成的完整消息):必须所有短信片段接收完成后才会执行一次回调,不会每收到一条片段就触发回调。

参数

func

参数含义:接收到新短信时触发的回调函数,支持处理普通短信与长短信两种模式
         普通短信:每收到一条立即执行,参数为(num, txt, metas)  
         长短信:所有分段接收完成后执行一次,metas包含完整分段元数据
         回调函数格式为:
         function callbacknum, txt, metas
         -- num: string类型,表示电话号码
         -- txt:string类型,表示发送的文本信息
         -- metas(短信):year(年)、mon(月)、 day(日)、hour(时)、min(分)、sec(秒)、tz(时区)
         -- metas(短信):refNum:长短信的参考编号
- seqNum :当前短信分片的序号
- maxNum :长短信的总分片数
数据类型:function
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:local function smscb(num, txt, metas)
             log.info("sms", num, txt, metas and json.encode(metas) or "")
         end
         sms.setNewSmsCb(smscb)
         -- 普通短信示例:
         -- local function smscb1("+8613800138000","+8613800138000",
         -- {year=2025,mon=10,day=11,hour=15,min=30,sec=45,tz=480})
         -- sms.setNewSmsCb(smscb1) 
         -- 长短信示例: 
         -- local function smscb2("+8613900139000", txt="这是一条长短信合并后的完整内容",
         -- metas={refNum=123,seqNum=3,maxNum=3,year=2025,mon=10,day=11,hour=15,min=32,sec=00,tz=480})
         -- sms.setNewSmsCb(smscb2)

返回值

nil

示例

local function smscb(num, txt, metas)
    -- num 手机号码
    -- txt 文本内容
    -- metas 短信的元数据
    -- 普通短信的metas结构:
    -- {
    --  refNum = nil,    -- 无长短信编号
    --  seqNum = 1,      -- 固定为1
    --  maxNum = 1,      -- 固定为1
    -- }
    -- 长短信合并后的metas结构:
    -- {
    -- refNum = 123,    -- 长短信唯一ID
    -- seqNum = 1,      -- 当前为第1段
    -- maxNum = 3,      -- 共3段
    -- year = 2025, mon = 10, day = 11, 
    -- hour = 15, min = 30, sec = 45, 
    -- tz = 480         -- +8:00时区
     -- }
    -- 时间戳字段同上
    -- 注意, 如果开启了长短信自动合并功能,
    -- 长短信会自动合并成一条txt
    log.info("sms", num, txt, metas and json.encode(metas) or "")
end)
sms.setNewSmsCb(smscb)

sms.autoLong(mode)

功能

设置长短信的自动合并功能

参数

mode

参数含义:是否自动合并,true为自动合并,为默认值;
数据类型:boolean
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true

返回值

local result = sms.autoLong(true)

含义说明:设置长短信的自动合并功能结果;
数据类型:boolean
取值范围:true或者false
注意事项:暂无;
返回示例:true

示例

sms.autoLong(false)

sms.clearLong()

功能

清除长短信缓存

使用场景如下:

  1. 长短信分片未完全接收导致缓存残留
  2. 缓存池溢出风险
  3. 内存资源紧张
  4. 异常状态重置

参数

nil

返回值

local num = sms.clearLong()

num

含义说明:清理掉的片段数量;
数据类型:number
取值范围:暂无;
注意事项:暂无;
返回示例:1

示例

sms.clearLong()

sms.debug(enable)

功能

设置短信模块的调试模式

参数

enable

含义说明:enable 是否启用调试模式,true为启用,false为禁用
数据类型:boolean
取值范围:ture或false
注意事项:暂无;
参数示例:true

返回值

nil

示例

-- 启用短信调试模式,会输出更多日志信息
sms.debug(true)
-- 禁用短信调试模式
sms.debug(false)

sms.setVp(vp)

功能

设置全局短信有效期,即短信中心最大重试保存时长。

该函数在V2050及以后版本支持

参数

vp

参数含义:短信中心最大重试有效期,短信下发后,接收方关机 / 无信号时,短信中心会在该时间内持续尝试投递;
         超时未送达则短信直接丢弃;
数据类型:number
取值范围:0255
是否必选:可选传入此参数;
注意事项:该值是协议标准编码值,不是直接填小时 / 天数,需要按照下表公式换算得到实际时长
         最终生效时间受短信中心最大上限约束,即使 VP 算出来 7 天,
         若运营商 SMSC 上限只有 72 小时,则实际按 72 小时生效;
         与回执参数无关:回执 boolean 只控制是否上报送达报告,VP 控制消息在网关侧保存多久 
         参数示例:169,计算:169166 =3 =72小时;
参数示例:169

VP 完整换算表

vp 值 计算公式 实际有效期范围
0‑143 (vp+1) ×5 分钟 5 分钟~12 小时
144‑167 12h + (vp‑143) ×30 分钟 12 ~ 24 小时
168‑196 (vp‑166) 天 2 ~ 30 天
197‑255 (vp‑192) 周 5 周~63 周

返回值

local value = sms.setVp(vp)

value

含义说明:返回设置完成后生效的全局短信vp编码值
数据类型:number
取值范围:0255
注意事项:暂无;
返回示例:169

示例

sms.setVp(169) 

五、产品支持说明

不同产品的LuatOS固件,对sms核心库的支持情况如下:

1、Air780EX2/Air700ECP/Air780EPM/Air780EGP 1号、2号、103-106号固件支持(均支持移动/联通,部分支持电信);

2、Air700ECH/Air780EHM/EHV/EGH/EGG/EHU/EHN/Air8000系列 均支持移动/联通,部分支持电信;

3、Air8101系列 不支持;

4、Air1601 / Air1602 都不支持;

各产品固件支持核心库列表详细说明参考下面链接:

Air780EX2/Air700ECP/Air780EPM/Air780EGP固件支持列表

Air700ECH/Air780EHM/EHV/EGH/EGG/EHU/EHN固件支持列表

Air8000系列所有型号固件支持列表

Air8101系列所有型号固件支持列表

Air1601/Air1602固件支持列表

搜索