local util_notify = {} -- 消息队列 local msg_queue = {} local function urlencodeTab(params) local msg = {} for k, v in pairs(params) do table.insert(msg, string.urlEncode(k) .. "=" .. string.urlEncode(v)) table.insert(msg, "&") end table.remove(msg) return table.concat(msg) end local notify = { -- 发送到 串口 ["uart"] = function(msg) if config.UART_ID == nil or config.UART_ID == "" then log.error("util_notify", "未配置 `config.UART_ID`") return end --初始化 -- 最常用115200 8N1 uart.setup(config.UART_ID, 115200, 8, 1, uart.NONE) log.info("util_notify", "发送到串口", config.UART_ID, msg) -- 写入可见字符串 local res_body = uart.write(config.UART_ID, msg) return 200, '', res_body end, -- 发送到 dingtalk -- ["dingtalk"] = function(msg) -- if config.DINGTALK_WEBHOOK == nil or config.DINGTALK_WEBHOOK == "" then -- log.error("util_notify", "未配置 `config.DINGTALK_WEBHOOK`") -- return -- end -- local header = { -- ["Content-Type"] = "application/json; charset=utf-8" -- } -- local body = { -- msgtype = "text", -- text = { -- content = msg -- } -- } -- local json_data = json.encode(body) -- -- LuatOS Bug, json.encode 会将 \n 转换为 \b -- json_data = string.gsub(json_data, "\\b", "\\n") -- log.info("util_notify", "POST", config.DINGTALK_WEBHOOK) -- return util_http.fetch(nil, "POST", config.DINGTALK_WEBHOOK, header, json_data) -- end, -- -- 发送到 wecom -- ["wecom"] = function(msg) -- if config.WECOM_WEBHOOK == nil or config.WECOM_WEBHOOK == "" then -- log.error("util_notify", "未配置 `config.WECOM_WEBHOOK`") -- return -- end -- local header = { -- ["Content-Type"] = "application/json; charset=utf-8" -- } -- local body = { -- msgtype = "text", -- text = { -- content = msg -- } -- } -- local json_data = json.encode(body) -- -- LuatOS Bug, json.encode 会将 \n 转换为 \b -- json_data = string.gsub(json_data, "\\b", "\\n") -- log.info("util_notify", "POST", config.WECOM_WEBHOOK) -- return util_http.fetch(nil, "POST", config.WECOM_WEBHOOK, header, json_data) -- end, } local function append(msg) if type(msg) ~= "table" then log.error("util_notify.append", "添加扩展信息错误", "参数类型错误", type(msg)) return msg end -- 本机号码 local number = mobile.number(mobile.simid()) if number then msg.to = string.gsub(number,"+86","",1) end -- 开机时长 local ms = mcu.ticks() local seconds = math.floor(ms / 1000) local minutes = math.floor(seconds / 60) local hours = math.floor(minutes / 60) seconds = seconds % 60 minutes = minutes % 60 local boot_time = string.format("%02d:%02d:%02d", hours, minutes, seconds) if ms >= 0 then msg.start_time = boot_time end -- 运营商 local oper = util_mobile.getOper(true) if oper ~= "" then msg.oper = oper end -- 信号 local rsrp = mobile.rsrp() if rsrp ~= 0 then msg.rsrp = rsrp end return msg end --- 发送通知 -- @param msg 消息内容 -- @param channel 通知渠道 -- @return true: 无需重发, false: 需要重发 function util_notify.send(msg, channel) log.info("util_notify.send", "发送通知", channel) -- 判断消息内容 msg if type(msg) ~= "table" then log.error("util_notify.send", "发送通知失败", "参数类型错误", type(msg)) return true end if msg.sms == "" then log.error("util_notify.send", "发送通知失败", "消息内容为空") return true end -- 判断通知渠道 channel if channel and notify[channel] == nil then log.error("util_notify.send", "发送通知失败", "未知通知渠道", channel) return true end -- 通知内容追加更多信息 if config.NOTIFY_APPEND_MORE_INFO then msg = append(msg) end -- 发送通知 local code, headers, body = notify[channel](json.encode(msg)) if code == nil then log.info("util_notify.send", "发送通知失败, 无需重发", "code:", code, "body:", body) return true end if code == -6 then -- 发生在 url 过长时, 重发也不会成功 log.info("util_notify.send", "发送通知失败, 无需重发", "code:", code, "body:", body) return true end if code >= 200 and code < 500 then log.info("util_notify.send", "发送通知成功", "code:", code, "body:", body) return true end log.error("util_notify.send", "发送通知失败, 等待重发", "code:", code, "body:", body) return false end --- 添加到消息队列 -- @param msg 消息内容 -- @param channels 通知渠道 function util_notify.add(msg, channels) if type(msg) ~= "table" then log.info("util_notify.add", "添加消息失败", "参数错误") end channels = channels or config.NOTIFY_TYPE if type(channels) ~= "table" then channels = {channels} end for _, channel in ipairs(channels) do table.insert(msg_queue, {channel = channel, msg = msg, retry = 0}) end sys.publish("NEW_MSG") log.debug("util_notify.add", "添加到消息队列, 当前队列长度:", #msg_queue) end -- 轮询消息队列 -- 发送成功则从消息队列中删除 -- 发送失败则等待下次轮询 local function poll() local item, result while true do -- 消息队列非空, 且网络已注册 if next(msg_queue) ~= nil then -- log.debug("util_notify.poll等待信号",gpio.get(config.STATUS_GPIO),gpio.HIGH) if gpio.get(config.STATUS_GPIO) == gpio.HIGH then log.debug("util_notify.poll", "轮询消息队列中, 当前队列长度:", #msg_queue) item = msg_queue[1] table.remove(msg_queue, 1) if item.retry > (config.NOTIFY_RETRY_MAX or 100) then log.error("util_notify.poll", "超过最大重发次数", "消息内容:", json.encode(item.msg)) else result = util_notify.send(item.msg, item.channel) item.retry = item.retry + 1 if not result then -- 发送失败, 移到队尾 table.insert(msg_queue, item) sys.wait(50) end sys.wait(1000) end sys.wait(50) else -- log.debug("util_notify.poll", "等待主机状态下发, 当前队列长度:", #msg_queue) sys.wait(50) end else sys.waitUntil("NEW_MSG", 1000 * 10) end end end sys.taskInit(poll) return util_notify