From 13dc054a0169acaf1937910c9cc20addefedcd30 Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Sun, 2 Aug 2026 15:57:14 +0800 Subject: [PATCH] feat: use block reader for accurate ETA and delay data --- station_broadcast.lua | 163 ++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/station_broadcast.lua b/station_broadcast.lua index 351debf..101baa8 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -108,7 +108,7 @@ function Peripherals.init() Peripherals.station = station State.hasStationPeripheral = station ~= nil State.stationPeripheralSide = stationSide - -- Monitors + -- monitors local monitors = { peripheral.find("monitor") } if #monitors > 0 then Peripherals.primaryMonitor = monitors[1] @@ -125,6 +125,8 @@ function Peripherals.init() if Peripherals.createTarget then pcall(Peripherals.createTarget.resize, 80, 10) end + -- Block Reader (Advanced Peripherals) + Peripherals.blockReader = peripheral.find("blockReader") end -- ============================================================================ @@ -2239,72 +2241,125 @@ State.pendingApproaching = {} function Main.loop() while true do - if Peripherals.createTarget then - local lines = Peripherals.createTarget.dump() - for _, lineText in pairs(lines) do - if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then - local etaVal, etaUnit, tName, dest - etaVal, etaUnit, tName, dest = string.match(lineText, "^(%d+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$") - if not tName then - etaVal, etaUnit, tName, dest = string.match(lineText, "^([^%s]+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$") + local now = os.epoch("utc") + + -- Check Block Reader (Advanced Peripherals) first for precise ETA and Delay + if Peripherals.blockReader then + local ok, data = pcall(Peripherals.blockReader.getBlockData) + if ok and data and data.TrainStops then + for k, v in pairs(State.announcedApproaching) do + if now - v > 300000 then + State.announcedApproaching[k] = nil end - if not tName then - etaVal, etaUnit, tName, dest = string.match(lineText, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$") - end - - if tName and etaVal then - local announceKey = tName .. "_" .. dest - local now = os.epoch("utc") + end + + for i, stop in ipairs(data.TrainStops) do + local st = stop.Station + if st then + local trainName = st.TrainName or "Unknown" + local destination = st.Destination or "Unknown" + local platform = stop.StationInfo and stop.StationInfo.Platform or State.stationPlatform or "1" - -- 45秒预告逻辑:当读取到1分钟时,延迟15秒再播报 - if etaVal == "1" then - if not State.announcedApproaching[announceKey] or (now - State.announcedApproaching[announceKey] > 120000) then - if not State.pendingApproaching[announceKey] then - State.pendingApproaching[announceKey] = { - triggerTime = now + 15000, -- 延迟15秒 - tName = tName, - dest = dest, - etaVal = etaVal - } - end - end - elseif etaVal == "现在" or etaVal == "0" then - -- 如果列车已经进站(0或现在),并且没有被播报过,立即播报 - if not State.announcedApproaching[announceKey] or (now - State.announcedApproaching[announceKey] > 120000) then + -- Calculate ETA in seconds + local scheduledArrival = st.ScheduledArrival or 0 + local realArrival = st.RealTimeArrival or 0 + local etaTicks = realArrival - (data.LastRefreshed or 0) + local etaSeconds = math.floor(etaTicks / 20) + + -- Calculate Delay in minutes + local delayTicks = realArrival - scheduledArrival + local delayMinutes = math.floor(delayTicks / (20 * 60)) + if delayMinutes < 0 then delayMinutes = 0 end + + if etaSeconds >= 0 and etaSeconds <= 45 then + local announceKey = trainName .. "_" .. destination + if not State.announcedApproaching[announceKey] then State.announcedApproaching[announceKey] = now - State.pendingApproaching[announceKey] = nil - Utils.log("INFO", "Train Approaching (Now): " .. tName) + Utils.log("INFO", string.format("Train Approaching: %s (ETA: %ds, Delay: %dm)", trainName, etaSeconds, delayMinutes)) Network.send({ type = "train_approaching", stationName = State.stationName, stationCode = State.stationCode, - stationPlatform = State.stationPlatform or "1", - trainId = tName, - destination = dest, - eta = etaVal + stationPlatform = platform, + trainId = trainName, + destination = destination, + eta = tostring(etaSeconds) .. "s", + etaSeconds = etaSeconds, + delay = delayMinutes }) end end end end end - - -- 检查是否有到期的延迟播报(45秒预告) - local now = os.epoch("utc") - for key, info in pairs(State.pendingApproaching) do - if now >= info.triggerTime then - State.announcedApproaching[key] = now - State.pendingApproaching[key] = nil - Utils.log("INFO", "Train Approaching (45s mark): " .. info.tName) - Network.send({ - type = "train_approaching", - stationName = State.stationName, - stationCode = State.stationCode, - stationPlatform = State.stationPlatform or "1", - trainId = info.tName, - destination = info.dest, - eta = info.etaVal - }) + -- Fallback to Display Link text parsing if Block Reader is not available + elseif Peripherals.createTarget then + local lines = Peripherals.createTarget.dump() + + for k, v in pairs(State.announcedApproaching) do + if now - v > 300000 then + State.announcedApproaching[k] = nil + end + end + + for _, lineText in pairs(lines) do + if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then + local delayMatch = string.match(lineText, "%+%s*(%d+)") + local delay = tonumber(delayMatch) or 0 + + -- 从文本中移除延误相关的字眼,防止干扰后续的正则表达式匹配 + local cleanLine = string.gsub(lineText, "%s*%(?%+%s*%d+.-%)?", "") + + local platform, etaStr, tName, dest + platform, etaStr, tName, dest = string.match(cleanLine, "^(%d+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$") + if not tName then + platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$") + end + if not tName then + platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$") + end + + if tName and etaStr then + local announceKey = tName .. "_" .. dest + + -- 将 ETA 转换为秒数进行精准判断 + local etaSeconds = -1 + local isNow = string.find(etaStr, "现在") or string.find(etaStr, "0") + + if isNow then + etaSeconds = 0 + else + local num, unit = string.match(etaStr, "(%d+)%s*(.*)") + if num then + num = tonumber(num) + -- 如果单位包含秒的字眼,或者是乱码但数值>10(如 45 ??, 30 ??),则认为是秒 + if string.find(unit, "秒") or string.find(unit, "s") or string.find(unit, "sec") or (unit == "??" and num > 10) then + etaSeconds = num + else + etaSeconds = num * 60 + end + end + end + + -- 触发逻辑:当 ETA 已经明确 <= 45秒(包括30秒、15秒、现在等),且之前没有播报过 + if etaSeconds >= 0 and etaSeconds <= 45 then + if not State.announcedApproaching[announceKey] then + State.announcedApproaching[announceKey] = now + Utils.log("INFO", string.format("Train Approaching: %s (ETA: %ds, Delay: %dm)", tName, etaSeconds, delay)) + Network.send({ + type = "train_approaching", + stationName = State.stationName, + stationCode = State.stationCode, + stationPlatform = platform or State.stationPlatform or "1", + trainId = tName, + destination = dest, + eta = etaStr, + etaSeconds = etaSeconds, + delay = delay + }) + end + end + end end end end