sms_app.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. --[[
  2. @module sms_forward
  3. @summary 短信信息转发驱动模块
  4. @version 1.0
  5. @date 2025.10.15
  6. @author 王城钧
  7. @usage
  8. 本文件为来电信息转发驱动模块,核心业务逻辑为:
  9. 1、配置飞书,钉钉,企业微信机器人的webhook和secret(加签)。
  10. 2、send_sms(),发送短信的功能函数,等待IP_READY消息后,手机卡可以进行收发短信。
  11. 3、receive_sms(),接收短信处理的功能函数,收到短信后获取来信号码和短信内容,通过回调函数sms_handler(num, txt)转发到指定的机器人。
  12. 本文件没有对外接口,直接在main.lua中require "sms_forward"就可以加载运行;
  13. ]]
  14. -- webhook_feishu和secret_feishu要换成你自己机器人的值
  15. -- webhook_feishu是钉钉分配给机器人的URL
  16. -- secret_feishu是选取 "加签", 自动生成的密钥
  17. -- 下面的给一个测试群发消息, 随时可能关掉, 请换成你自己的值
  18. local webhook_feishu = "https://open.feishu.cn/open-apis/bot/v2/hook/673d1e1d-0c7e-4d34-b7f0-48bdb4c4d03a"
  19. local secret_feishu = "qlf8UXrJc7RYtJLx77jRVh"
  20. local webhook_dingding =
  21. "https://oapi.dingtalk.com/robot/send?access_token=bf9fe5c74194b9556cff401b87ac5de46a92bbf15cc226b73d14c28773b86f3b"
  22. local secret_dingding = "SEC1bec4c6416b14c945806fa658840c7fbc64c3257aacd0c72f6cad5d22e3d29a4"
  23. --local webhook_weixin = "https://work.weixin.qq.com/wework_admin/common/openBotProfile/24caa08b3a985454055047454d883fc98f"
  24. local webhook_weixin = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=a9dec355-3e0f-45bf-a0b1-0f8813fe6b7d"
  25. -- 飞书关于机器人的文档 https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN
  26. --1.功能函数:短信转发到飞书
  27. local function feishu_post_sms(num, rctxt)
  28. local rheaders = {}
  29. rheaders["Content-Type"] = "application/json"
  30. -- LuatOS的时间戳只到秒,飞书也只需要秒
  31. local timestamp = tostring(os.time())
  32. local sign = crypto.hmac_sha256("", timestamp .. "\n" .. secret_feishu):fromHex():toBase64()
  33. log.info("timestamp", timestamp)
  34. log.info("sign", sign)
  35. -- 注意, 这里的参数跟钉钉不同, 钉钉有个access_token参数, 飞书没有
  36. local url = webhook_feishu
  37. log.info("url", url)
  38. -- json格式也需要按飞书的来
  39. local data = { msg_type = "text" }
  40. data["timestamp"] = timestamp
  41. data["sign"] = sign
  42. -- text就是要发送的文本内容, 其他格式按飞书的要求拼接table就好了
  43. local text = "我的id是" ..
  44. tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ", " .. num .. "发来短信,内容是:" .. rctxt
  45. data["content"] = { text = text }
  46. local rbody = (json.encode(data))
  47. log.info("feishu", rbody)
  48. local code, headers, body = http.request("POST", url, rheaders, rbody, { timeout = 5000 }).wait()
  49. -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
  50. -- 其他错误, 一般是密钥错了, 仔细检查吧
  51. log.info("飞书机器人",
  52. code==200 and "success" or "error",
  53. code,
  54. json.encode(headers or {}),
  55. body and (body:len()>512 and body:len() or body) or "nil")
  56. end
  57. --2.功能函数:短信转发到钉钉
  58. local function dingding_post(num, rctxt)
  59. local rheaders = {}
  60. rheaders["Content-Type"] = "application/json"
  61. -- LuatOS的时间戳只到秒,但钉钉需要毫秒,补3个零
  62. local timestamp = tostring(os.time()) .. "000"
  63. local sign = crypto.hmac_sha256(timestamp .. "\n" .. secret_dingding, secret_dingding):fromHex():toBase64()
  64. :urlEncode()
  65. log.info("timestamp", timestamp)
  66. log.info("sign", sign)
  67. local url = webhook_dingding .. "&timestamp=" .. timestamp .. "&sign=" .. sign
  68. log.info("url", url)
  69. local data = { msgtype = "text" }
  70. -- content就是要发送的文本内容, 其他格式按钉钉的要求拼接table就好了
  71. local content = "我的id是" ..
  72. tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ", " .. num .. "发来短信,内容是:" .. rctxt
  73. data["text"] = { content = content }
  74. local rbody = (json.encode(data))
  75. log.info("dingding", rbody)
  76. local code, headers, body = http.request("POST", url, rheaders, (json.encode(data))).wait()
  77. -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
  78. -- 其他错误, 一般是密钥错了, 仔细检查吧
  79. log.info("钉钉机器人",
  80. code==200 and "success" or "error",
  81. code,
  82. json.encode(headers or {}),
  83. body and (body:len()>512 and body:len() or body) or "nil")
  84. end
  85. --3.功能函数:短信转发到企业微信
  86. local function weixin_post(num, rctxt)
  87. local rheaders = {}
  88. rheaders["Content-Type"] = "application/json"
  89. local timestamp = tostring(os.time()) .. "000"
  90. log.info("timestamp", timestamp)
  91. local url = webhook_weixin .. "&timestamp=" .. timestamp
  92. log.info("url", url)
  93. local data = { msgtype = "text" }
  94. -- content就是要发送的文本内容, 其他格式按钉钉的要求拼接table就好了
  95. local content = "我的id是" ..
  96. tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp() .. ", " .. num .. "发来短信,内容是:" .. rctxt
  97. data["text"] = { content = content }
  98. local rbody = (json.encode(data))
  99. log.info("weixin", rbody)
  100. local code, headers, body = http.request("POST", url, rheaders, (json.encode(data))).wait()
  101. -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
  102. -- 其他错误, 一般是密钥错了, 仔细检查吧
  103. log.info("企业微信机器人",
  104. code==200 and "success" or "error",
  105. code,
  106. json.encode(headers or {}),
  107. body and (body:len()>512 and body:len() or body) or "nil")
  108. end
  109. --4.功能函数:接收短信的回调函数
  110. local function sms_handler(num, txt)
  111. -- num 给我发短信的手机号码
  112. -- txt 收到的短信文本内容
  113. log.info("转发到飞书")
  114. feishu_post_sms(num, txt)
  115. --等待1秒, 非必须
  116. sys.wait(1000)
  117. log.info("转发到钉钉")
  118. dingding_post(num, txt)
  119. --等待1秒, 非必须
  120. sys.wait(1000)
  121. log.info("转发到微信")
  122. weixin_post(num, txt)
  123. end
  124. --------------------------------------------------------------------
  125. --5. 功能函数:接收短信
  126. local function receive_sms()
  127. while 1 do
  128. local ret, num, txt = sys.waitUntil("SMS_INC", 30000)
  129. log.info("收到来自短信:", num)
  130. if num then
  131. log.info("num是", num)
  132. log.info("收到来自" .. num .. "的短信:" .. txt)
  133. --local isReady1, index1 = socket.adapter()
  134. log.info("当前网络", socket.adapter())
  135. sms_handler(num, txt)
  136. end
  137. end
  138. end
  139. -------------------------------------------------------------------
  140. -- 6.功能函数:发送短信, 直接调用sms.send就行, 是不是task无所谓
  141. local function send_sms()
  142. --按照规范的做法,这里应该等待"SMS_READY"消息,
  143. --目前内核固件正在开发支持"SMS_READY"消息功能,
  144. --等开发好了之后,再使用"SMS_READY"消息,
  145. --当前阶段,先使用"IP_READY"替代
  146. sys.waitUntil("IP_READY")
  147. sys.wait(5000)
  148. -- 当前阶段等待5s,使得sms准备就绪,待"SMS_READY"消息开发完成后,删除如上两行代码使用sys.waitUntil("SMS_READY")替代
  149. log.info("发送短信准备就绪")
  150. local cont = 1
  151. log.info("开始发短信")
  152. while 1 do
  153. log.info("现在可以收发短信")
  154. --获取本机号码,如果卡商没写入会返回nil
  155. log.info("mobile.number(id) = ", mobile.number())
  156. --获取本机iccid,如果卡商没写入会返回nil
  157. log.info("mobile.iccid(id) = ", mobile.iccid())
  158. --获取本机simid,如果卡商没写入会返回nil
  159. log.info("mobile.simid(id) = ", mobile.simid())
  160. --获取本机imsi,如果卡商没写入会返回nil
  161. log.info("mobile.imsi(index) = ", mobile.imsi())
  162. -- 注意:以下查话费的三行代码只需根据自己卡的运营商打开其一即可,其余两行关闭,不要全部打开
  163. -- 电信卡查话费
  164. local result = sms.send("10001", "102")
  165. -- 中移动卡查短信
  166. -- local result = sms.send("10086", "301")
  167. -- 联通卡查话费
  168. -- local result = sms.send("10010", "101")
  169. -- 注意:V2018及更高版本固件才有"SMS_SENT"系统消息
  170. if result then
  171. local wait_msg, success = sys.waitUntil("SMS_SENT", 10000)
  172. log.info("发送查询短信", "这是第" .. cont .. "次发送", " 发送结果:", wait_msg and (success and "成功" or "失败") or "超时")
  173. else
  174. log.info("发送查询短信", "这是第" .. cont .. "次发送", " 发送结果:同步发送失败")
  175. end
  176. log.info("等待10分钟")
  177. cont = cont + 1
  178. sys.wait(10 * 60 * 1000)
  179. end
  180. end
  181. --发送短信
  182. sys.taskInit(send_sms)
  183. --接收短信
  184. sys.taskInit(receive_sms)