feat: use block reader for accurate ETA and delay data
This commit is contained in:
+99
-44
@@ -108,7 +108,7 @@ function Peripherals.init()
|
|||||||
Peripherals.station = station
|
Peripherals.station = station
|
||||||
State.hasStationPeripheral = station ~= nil
|
State.hasStationPeripheral = station ~= nil
|
||||||
State.stationPeripheralSide = stationSide
|
State.stationPeripheralSide = stationSide
|
||||||
-- Monitors
|
-- monitors
|
||||||
local monitors = { peripheral.find("monitor") }
|
local monitors = { peripheral.find("monitor") }
|
||||||
if #monitors > 0 then
|
if #monitors > 0 then
|
||||||
Peripherals.primaryMonitor = monitors[1]
|
Peripherals.primaryMonitor = monitors[1]
|
||||||
@@ -125,6 +125,8 @@ function Peripherals.init()
|
|||||||
if Peripherals.createTarget then
|
if Peripherals.createTarget then
|
||||||
pcall(Peripherals.createTarget.resize, 80, 10)
|
pcall(Peripherals.createTarget.resize, 80, 10)
|
||||||
end
|
end
|
||||||
|
-- Block Reader (Advanced Peripherals)
|
||||||
|
Peripherals.blockReader = peripheral.find("blockReader")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@@ -2239,74 +2241,127 @@ State.pendingApproaching = {}
|
|||||||
|
|
||||||
function Main.loop()
|
function Main.loop()
|
||||||
while true do
|
while true do
|
||||||
if Peripherals.createTarget then
|
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
|
||||||
|
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"
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
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 = platform,
|
||||||
|
trainId = trainName,
|
||||||
|
destination = destination,
|
||||||
|
eta = tostring(etaSeconds) .. "s",
|
||||||
|
etaSeconds = etaSeconds,
|
||||||
|
delay = delayMinutes
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Fallback to Display Link text parsing if Block Reader is not available
|
||||||
|
elseif Peripherals.createTarget then
|
||||||
local lines = Peripherals.createTarget.dump()
|
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
|
for _, lineText in pairs(lines) do
|
||||||
if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then
|
if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then
|
||||||
local etaVal, etaUnit, tName, dest
|
local delayMatch = string.match(lineText, "%+%s*(%d+)")
|
||||||
etaVal, etaUnit, tName, dest = string.match(lineText, "^(%d+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$")
|
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
|
if not tName then
|
||||||
etaVal, etaUnit, tName, dest = string.match(lineText, "^([^%s]+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$")
|
platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+(%[.-%][^%s]*)%s+(.*)$")
|
||||||
end
|
end
|
||||||
if not tName then
|
if not tName then
|
||||||
etaVal, etaUnit, tName, dest = string.match(lineText, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$")
|
platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$")
|
||||||
end
|
end
|
||||||
|
|
||||||
if tName and etaVal then
|
if tName and etaStr then
|
||||||
local announceKey = tName .. "_" .. dest
|
local announceKey = tName .. "_" .. dest
|
||||||
local now = os.epoch("utc")
|
|
||||||
|
|
||||||
-- 45秒预告逻辑:当读取到1分钟时,延迟15秒再播报
|
-- 将 ETA 转换为秒数进行精准判断
|
||||||
if etaVal == "1" then
|
local etaSeconds = -1
|
||||||
if not State.announcedApproaching[announceKey] or (now - State.announcedApproaching[announceKey] > 120000) then
|
local isNow = string.find(etaStr, "现在") or string.find(etaStr, "0")
|
||||||
if not State.pendingApproaching[announceKey] then
|
|
||||||
State.pendingApproaching[announceKey] = {
|
if isNow then
|
||||||
triggerTime = now + 15000, -- 延迟15秒
|
etaSeconds = 0
|
||||||
tName = tName,
|
else
|
||||||
dest = dest,
|
local num, unit = string.match(etaStr, "(%d+)%s*(.*)")
|
||||||
etaVal = etaVal
|
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
|
end
|
||||||
elseif etaVal == "现在" or etaVal == "0" then
|
end
|
||||||
-- 如果列车已经进站(0或现在),并且没有被播报过,立即播报
|
|
||||||
if not State.announcedApproaching[announceKey] or (now - State.announcedApproaching[announceKey] > 120000) then
|
-- 触发逻辑:当 ETA 已经明确 <= 45秒(包括30秒、15秒、现在等),且之前没有播报过
|
||||||
|
if etaSeconds >= 0 and etaSeconds <= 45 then
|
||||||
|
if not State.announcedApproaching[announceKey] then
|
||||||
State.announcedApproaching[announceKey] = now
|
State.announcedApproaching[announceKey] = now
|
||||||
State.pendingApproaching[announceKey] = nil
|
Utils.log("INFO", string.format("Train Approaching: %s (ETA: %ds, Delay: %dm)", tName, etaSeconds, delay))
|
||||||
Utils.log("INFO", "Train Approaching (Now): " .. tName)
|
|
||||||
Network.send({
|
Network.send({
|
||||||
type = "train_approaching",
|
type = "train_approaching",
|
||||||
stationName = State.stationName,
|
stationName = State.stationName,
|
||||||
stationCode = State.stationCode,
|
stationCode = State.stationCode,
|
||||||
stationPlatform = State.stationPlatform or "1",
|
stationPlatform = platform or State.stationPlatform or "1",
|
||||||
trainId = tName,
|
trainId = tName,
|
||||||
destination = dest,
|
destination = dest,
|
||||||
eta = etaVal
|
eta = etaStr,
|
||||||
|
etaSeconds = etaSeconds,
|
||||||
|
delay = delay
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
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
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Peripherals.station then
|
if not Peripherals.station then
|
||||||
|
|||||||
Reference in New Issue
Block a user