Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加保活功能,定时发送短信到指定号码 #27

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ USB连接Air780e,选择 `Luatools/resource/618_lua_lod/版本号` 目录下的

目前固件包含`gpio`、`uart`、`pwm`、`wdt`、`crypto`、`rtc`、`network`、`sntp`、`tls`、`wlan`、`pm`、`cjson`、`ntp`、`shell`、`dbg`。

# 保活 API 说明

API 提供 GET 和 POST 请求支持。

- GET 请求返回 POST 请求存储的时间戳
- POST 请求接收 `{ "expiry": "1732622763" }`,并存储

# 致谢

本项目参考[低成本短信转发器](https://github.com/chenxuuu/sms_forwarding)而来,尤其是PDU相关代码,没有`chenxuuu`的这份项目和[50元内自制短信转发器(Air780E+ESP32C3)](https://www.chenxublog.com/2022/10/28/19-9-sms-forwarding-air780e-esp32c3.html)这篇文章,我不会这么快就完成开发。
Expand Down
52 changes: 51 additions & 1 deletion air780_helper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ end)
-- 发送AT指令
function air780_helper.send_at_command(command)
uart.write(uart_id, command)
-- 如果是PDU模式下的短信内容,直接返回
if command:sub(1, 6) == "001110" then
return
end
uart.write(uart_id, "\r\n")
log.debug("air780_helper", "发送AT指令\""..command.."\"")
end
Expand Down Expand Up @@ -80,6 +84,20 @@ sys.subscribe(constants.uart_ready_message, function()
return
end

-- 响应发送短信指令
if current_line:find(">", 1, true) then
-- log.debug("air780_helper", "捕获到短信发送提示符")
sys.publish(constants.air780_helper_sms_send_ready)
return
end

-- 响应发送短信成功
if current_line:find("+CMGS:", 1, true) then
-- log.debug("air780_helper", "捕获到短信发送成功")
sys.publish(constants.air780_send_sms_success)
return
end

local urc = current_line:match("^%+(%w+)")

if urc then -- URC上报
Expand Down Expand Up @@ -129,7 +147,7 @@ sys.subscribe(constants.uart_ready_message, function()
end
until #data == 0
end
end
end
end
end
end)
Expand All @@ -145,4 +163,36 @@ function air780_helper.send_at_command_and_wait(command, topic_listen_to, timeou
end
end

function air780_helper.topic_wait(topic, timeout)
local is_successful, r1, r2, r3 = sys.waitUntil(topic, timeout or 1000)
return is_successful
end

function air780_helper.sent_sms(to, text)
local logging_tag = "air780_helper.sent_sms"
local data, len = pdu_helper.encode_pdu(to, text)
if not data or not len then
log.error(logging_tag, "短信编码失败")
return false
end
air780_helper.send_at_command("AT+CMGS=" .. len)

-- 增加调试信息
log.debug(logging_tag, "等待短信发送提示符")
local result = air780_helper.topic_wait(constants.air780_helper_sms_send_ready, 3000)
if not result then
log.error(logging_tag, "短信发送失败,AT+CMGS=" .. len .. " 超时")
return false
end

air780_helper.send_at_command(data .. "\x1A")
local result = air780_helper.topic_wait(constants.air780_send_sms_success, 5000)
if result then
log.info(logging_tag, "短信发送成功")
return true
else
log.error(logging_tag, "短信发送失败")
return false
end
end
return air780_helper
17 changes: 12 additions & 5 deletions config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,22 @@ config.disable_rndis = true
-- 而1156版本AT固件第一次检测有概率检测不到SIM卡,需要重试
config.retry_sim_detection = true

-- 续期 API
config.renew_api = "https://api.example.com/sim/expiry"
-- 续期间隔
config.renew_day = 180
-- 续期检查间隔,单位小时。为 0 时禁用
config.renew_check_interval = 0
-- 续期接收号码
config.renew_number = "+8613881388138"
-- 续期短信内容
config.renew_content = "注意余额"

config.wifi = {
{
ssid = "Wi-Fi名",
password = "Wi-Fi密码",
},
-- {
-- ssid = "",
-- password = "",
-- }
}

-- 手动配置DNS服务器
Expand Down Expand Up @@ -73,7 +80,7 @@ config.notification_channel = {
-- telegram 机器人
telegram = {
enabled = false,
-- Webhook地址
-- Webhook地址, https://api.telegram.org/bot<token>/sendMessage
webhook_url = "",
-- chat_id, 通过 https://api.telegram.org/bot<token>/getUpdates 获取
chat_id = ""
Expand Down
2 changes: 2 additions & 0 deletions constants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ constants.air780_message_topic_new_message_notification_configured = "NEW_MESSAG
constants.air780_message_topic_network_connected = "NETWORK_CONNECTED"
constants.air780_message_topic_new_sms_received = "NEW_SMS_RECEIVED"
constants.air780_message_topic_new_notification_request = "NEW_NOTIFICATION_REQUEST"
constants.air780_helper_sms_send_ready = "SMS_SEND_READY"
constants.air780_send_sms_success = "SMS_SENT_SUCCESSFULLY"

return constants
12 changes: 11 additions & 1 deletion main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ sys.taskInit(function ()
log.info(logging_tag, "GPRS已附着")
break
else
log.info(logging_tag, "GPRS未附着将在5秒后重新检查")
log.info(logging_tag, "GPRS未附着, 将在5秒后重新检查")
sys.wait(5000)
end
end
Expand All @@ -131,6 +131,16 @@ sys.taskInit(function ()
led_helper.light_status_led()
end)

sys.taskInit(function()
renew = require("renew")
sys.waitUntil(constants.air780_message_topic_new_message_notification_configured)
sys.waitUntil("NTP_UPDATE")
if config.renew_check_interval > 0 then
log.info("renew", "自动续期启动")
renew.renew()
end
end)

--[[
long_sms_buffer = {
[phone_number] = {
Expand Down
14 changes: 14 additions & 0 deletions pdu_helper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -363,4 +363,18 @@ function pdu_helper.decode_pdu(pdu, len)
return sender_number, sms_content_in_utf8, sms_receive_time, long_sms, total_message_count, current_idx, sms_id
end

-- 生成PDU短信编码
-- 仅支持单条短信,传入数据为utf8编码
-- 返回值为pdu编码与长度
function pdu_helper.encode_pdu(num,data)
data = utf8_to_ucs2(data):toHex()
local numlen, datalen, pducnt, pdu, pdulen, udhi = string.format("%02X", #num), #data / 2, 1, "", "", ""
if datalen > 140 then--短信内容太长啦
data = data:sub(1, 140 * 2)
end
datalen = string.format("%02X", datalen)
pdu = "001110" .. numlen .. number_to_bcd_number(num) .. "000800" .. datalen .. data
return pdu, #pdu // 2 - 1
end

return pdu_helper
88 changes: 88 additions & 0 deletions renew.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
local renew = {}

local sys = require("sys")
local sysplus = require("sysplus")
local air780 = require("air780_helper")
local config = require("config")

-- 获取到期时间
-- GET https://api.example.com/sim/expiry 1732622763
function renew.get_expire_date()
local code, headers, body = http.request("GET", config.renew_api, {["User-Agent"] = "LuatOS/1.0.0 (Lua; ESP32; Air780)"}, nil, {ipv6=true}).wait()

-- 如果 code 为负数,说明请求失败
if code < 0 or code ~= 200 then
log.error("renew", "获取到期时间", "code=" .. code)
return nil
end

-- 尝试将 body 转换为数字
local date = tonumber(body)
if not date then
log.error("renew", "获取到期时间", "未知时间格式:" .. tostring(body))
return nil
end

return date
end

-- 更新到期时间
-- POST https://api.example.com/sim/expiry { "expiry": "1732622763" }
function renew.update_expire_date(date)
local body = { expiry = date }
local code, headers, body = http.request("POST", config.renew_api, {["Content-Type"] = "application/json", ["User-Agent"] = "LuatOS/1.0.0 (Lua; ESP32; Air780)"}, json.encode(body), {ipv6=true}).wait()
if code ~= 200 then
log.error("renew", "更新到期时间", "code=" .. code)
return false
end
return true
end

-- 发送短信
-- 发送短信后,更新到期时间,到期时间为当前时间戳 + config.renew_day
function renew.send_sms()
if air780.sent_sms(config.renew_number, config.renew_content) then
log.debug("renew", "sent_sms success")
if renew.update_expire_date(os.time() + config.renew_day * 24 * 60 * 60) then
log.debug("renew", "更新到期时间成功")
return true
else
log.error("renew", "更新到期时间失败")
return false
end
else
log.error("renew", "发送短信失败")
return false
end
return true
end

-- 保活
-- 如果 date 为空,则发送短信
-- 如果当前时间戳大于等于 date,则发送短信
-- 检查间隔为 config.renew_check_interval 单位小时
function renew.renew()
while true do
local date = renew.get_expire_date()
if date == nil then
log.error("renew", "get_expire_date", "get_expire_date failed")
goto continue
end
if date == "" or os.time() >= date then
log.debug("renew", "已到期,开始保活")
if renew.send_sms() then
log.debug("renew", "保活成功")
else
log.error("renew", "保活失败")
end

goto continue
end
log.debug("renew", "时间未到,无需保活")

::continue::
sys.wait(config.renew_check_interval * 60 * 60 * 1000)
end
end

return renew