diff --git a/station_broadcast.lua b/station_broadcast.lua index 4c7187b..069013e 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -2,7 +2,7 @@ -- ============================================================================ -- 1. Configuration & Constants -- ============================================================================ -local APP_VERSION_TEXT = "v1.0.40" +local APP_VERSION_TEXT = "v1.0.41" local CONFIG = { CLOUD_URL = "ws://stabadmin.fse-media.group", @@ -15,6 +15,9 @@ local CONFIG = { STATION_IDENTITY_FILE = "station_identity.cfg", AUDIO_VOLUME = 100, AUDIO_STREAM_PREROLL_CHUNKS = 5, + ALERT_CONFIRM_MS = 60000, + ALERT_COOLDOWN_MS = 300000, + APPROACHING_COOLDOWN_MS = 120000, DEBUG = true } @@ -2309,8 +2312,26 @@ end local Main = {} State.announcedApproaching = {} State.announcedAlerts = {} +State.pendingAlerts = {} State.pendingApproaching = {} +local function cleanupTimestampMap(map, now, maxAgeMs) + for k, v in pairs(map or {}) do + if now - v > maxAgeMs then + map[k] = nil + end + end +end + +local function isPendingAlertReady(key, now) + local firstSeen = State.pendingAlerts[key] + if not firstSeen then + State.pendingAlerts[key] = now + return false + end + return (now - firstSeen) >= (tonumber(CONFIG.ALERT_CONFIRM_MS) or 60000) +end + local function parseEtaText(etaStr) etaStr = tostring(etaStr or "") if etaStr == "" then return -1 end @@ -2472,17 +2493,10 @@ function Main.loop() local elapsedSeconds = (now - (State.lastRefreshedEpoch or now)) / 1000 local currentTick = (data.LastRefreshed or 0) + math.floor(elapsedSeconds * (State.tickRate or 20)) + local seenAlertKeys = {} - for k, v in pairs(State.announcedApproaching) do - if now - v > 300000 then - State.announcedApproaching[k] = nil - end - end - for k, v in pairs(State.announcedAlerts) do - if now - v > 300000 then - State.announcedAlerts[k] = nil - end - end + cleanupTimestampMap(State.announcedApproaching, now, tonumber(CONFIG.APPROACHING_COOLDOWN_MS) or 120000) + cleanupTimestampMap(State.announcedAlerts, now, tonumber(CONFIG.ALERT_COOLDOWN_MS) or 300000) for i, stop in ipairs(data.TrainStops) do local st = stop.Station @@ -2540,7 +2554,8 @@ function Main.loop() local alertType = cancelled and "cancelled" or ((displayDelayMinutes > 0) and "delayed" or nil) local alertKey = alertType and (announceKey .. "::" .. alertType) or nil if alertKey then - if not State.announcedAlerts[alertKey] then + seenAlertKeys[alertKey] = true + if isPendingAlertReady(alertKey, now) and not State.announcedAlerts[alertKey] then State.announcedAlerts[alertKey] = now Utils.log("INFO", string.format("Train Alert: %s (ETA: %ds, Delay: %dm, Cancelled: %s, Reason: %s)", trainName, etaSeconds, displayDelayMinutes, tostring(cancelled), tostring(reason or ""))) Network.send({ @@ -2580,23 +2595,22 @@ function Main.loop() end end end + + for k, _ in pairs(State.pendingAlerts) do + if not seenAlertKeys[k] then + State.pendingAlerts[k] = nil + end + end end end -- Try CC:C Bridge Display Link (Legacy Text Parsing) if Block Reader is not available if not Peripherals.blockReader and Peripherals.createTarget then local lines = Peripherals.createTarget.dump() + local seenAlertKeys = {} - for k, v in pairs(State.announcedApproaching) do - if now - v > 300000 then - State.announcedApproaching[k] = nil - end - end - for k, v in pairs(State.announcedAlerts) do - if now - v > 300000 then - State.announcedAlerts[k] = nil - end - end + cleanupTimestampMap(State.announcedApproaching, now, tonumber(CONFIG.APPROACHING_COOLDOWN_MS) or 120000) + cleanupTimestampMap(State.announcedAlerts, now, tonumber(CONFIG.ALERT_COOLDOWN_MS) or 300000) for _, lineText in pairs(lines) do if lineText and lineText ~= "" and lineText:match("[%w%?%[]") then @@ -2653,7 +2667,8 @@ function Main.loop() local alertKey = announceKey .. "::delayed" if delay > 0 then - if not State.announcedAlerts[alertKey] then + seenAlertKeys[alertKey] = true + if isPendingAlertReady(alertKey, now) and not State.announcedAlerts[alertKey] then State.announcedAlerts[alertKey] = now Utils.log("INFO", string.format("Train Delay Alert: %s (ETA: %ds, Delay: %dm)", tName, etaSeconds, delay)) Network.send({ @@ -2691,6 +2706,12 @@ function Main.loop() end end end + + for k, _ in pairs(State.pendingAlerts) do + if not seenAlertKeys[k] then + State.pendingAlerts[k] = nil + end + end end -- Update Upcoming Trains globally for the monitor