Skip to content

Commit

Permalink
prevent count-up by prediction (#711)
Browse files Browse the repository at this point in the history
  • Loading branch information
panentheos authored Oct 19, 2023
1 parent acfa18b commit df6ebc7
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 145 deletions.
50 changes: 43 additions & 7 deletions lib/signs/realtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ defmodule Signs.Realtime do
announced_custom_text: nil,
announced_alert: false,
prev_prediction_keys: nil,
prev_predictions: [],
uses_shuttles: true
]

Expand Down Expand Up @@ -78,6 +79,7 @@ defmodule Signs.Realtime do
announced_custom_text: String.t() | nil,
prev_prediction_keys: [{String.t(), 0 | 1}] | nil,
announced_alert: boolean(),
prev_predictions: [Predictions.Prediction.t()],
uses_shuttles: boolean()
}

Expand Down Expand Up @@ -147,10 +149,21 @@ defmodule Signs.Realtime do
source.headway_destination}
end

predictions =
prev_predictions_lookup =
for prediction <- sign.prev_predictions, into: %{} do
{prediction_key(prediction), prediction}
end

{predictions, all_predictions} =
case sign.source_config do
{top, bottom} -> {fetch_predictions(top, sign), fetch_predictions(bottom, sign)}
config -> fetch_predictions(config, sign)
{top, bottom} ->
top_predictions = fetch_predictions(top, prev_predictions_lookup, sign)
bottom_predictions = fetch_predictions(bottom, prev_predictions_lookup, sign)
{{top_predictions, bottom_predictions}, top_predictions ++ bottom_predictions}

config ->
predictions = fetch_predictions(config, prev_predictions_lookup, sign)
{predictions, predictions}
end

{new_top, new_bottom} =
Expand All @@ -170,6 +183,7 @@ defmodule Signs.Realtime do
|> Utilities.Reader.do_announcements()
|> Utilities.Reader.read_sign()
|> decrement_ticks()
|> Map.put(:prev_predictions, all_predictions)

schedule_run_loop(self())
{:noreply, sign}
Expand All @@ -184,10 +198,32 @@ defmodule Signs.Realtime do
Process.send_after(pid, :run_loop, 1_000)
end

defp fetch_predictions(%{sources: sources}, state) do
Enum.flat_map(sources, fn source ->
state.prediction_engine.for_stop(source.stop_id, source.direction_id)
end)
defp prediction_key(prediction) do
Map.take(prediction, [:stop_id, :route_id, :vehicle_id, :direction_id, :trip_id])
end

defp fetch_predictions(%{sources: sources}, prev_predictions_lookup, state) do
for source <- sources,
prediction <- state.prediction_engine.for_stop(source.stop_id, source.direction_id) do
prev = prev_predictions_lookup[prediction_key(prediction)]

prediction
|> prevent_countup(prev, :seconds_until_arrival)
|> prevent_countup(prev, :seconds_until_departure)
end
end

defp prevent_countup(prediction, nil, _), do: prediction

defp prevent_countup(prediction, prev, key) do
seconds = Map.get(prediction, key)
prev_seconds = Map.get(prev, key)

if seconds && prev_seconds && round(seconds / 60) == round(prev_seconds / 60) + 1 do
Map.put(prediction, key, Map.get(prev, key))
else
prediction
end
end

@spec announce_passthrough_trains(Signs.Realtime.t(), predictions()) :: Signs.Realtime.t()
Expand Down
62 changes: 0 additions & 62 deletions lib/signs/utilities/messages.ex
Original file line number Diff line number Diff line change
Expand Up @@ -235,66 +235,4 @@ defmodule Signs.Utilities.Messages do
nil
end
end

@spec same_content?(Content.Message.t(), Content.Message.t()) :: boolean()
def same_content?(sign_msg, new_msg) do
sign_msg == new_msg or countup?(sign_msg, new_msg)
end

# Specific to JFK/UMass Mezzanine:
# Sign is remaining in full-page paging state
defp countup?(
%Content.Message.GenericPaging{messages: [%Content.Message.Predictions{} = p1 | _]},
%Content.Message.GenericPaging{messages: [%Content.Message.Predictions{} = p2 | _]}
) do
countup?(p1, p2)
end

# Specific to JFK/UMass Mezzanine:
# Sign is transitioning from normal state to a full-page paging state
defp countup?(
%Content.Message.Predictions{} = p1,
%Content.Message.GenericPaging{
messages: [%Content.Message.PlatformPredictionBottom{} = p2 | _]
}
) do
countup?(p1, %Content.Message.Predictions{destination: p2.destination, minutes: p2.minutes})
end

# Specific to JFK/UMass Mezzanine:
# Sign is transitioning from full-page paging state to normal state
defp countup?(
%Content.Message.GenericPaging{
messages: [%Content.Message.PlatformPredictionBottom{} = p1 | _]
},
%Content.Message.Predictions{} = p2
) do
countup?(%Content.Message.Predictions{destination: p1.destination, minutes: p1.minutes}, p2)
end

defp countup?(
%Content.Message.Predictions{destination: same, minutes: :arriving},
%Content.Message.Predictions{destination: same, minutes: :approaching}
) do
true
end

defp countup?(
%Content.Message.Predictions{destination: same, minutes: :approaching},
%Content.Message.Predictions{destination: same, minutes: 1}
) do
true
end

defp countup?(
%Content.Message.Predictions{destination: same, minutes: a},
%Content.Message.Predictions{destination: same, minutes: b}
)
when a + 1 == b do
true
end

defp countup?(_sign, _new) do
false
end
end
16 changes: 5 additions & 11 deletions lib/signs/utilities/updater.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ defmodule Signs.Utilities.Updater do
and the sign is configured to announce that fact, will send that audio request, too.
"""

alias Signs.Utilities.Messages
require Logger

@spec update_sign(
Expand All @@ -16,21 +15,16 @@ defmodule Signs.Utilities.Updater do
DateTime.t()
) :: Signs.Realtime.t()
def update_sign(sign, top_msg, bottom_msg, current_time) do
top_changed? = not Messages.same_content?(sign.current_content_top, top_msg)
new_top = if top_changed?, do: top_msg, else: sign.current_content_top
bottom_changed? = not Messages.same_content?(sign.current_content_bottom, bottom_msg)
new_bottom = if bottom_changed?, do: bottom_msg, else: sign.current_content_bottom

if !sign.last_update ||
Timex.after?(current_time, Timex.shift(sign.last_update, seconds: 130)) ||
top_changed? ||
bottom_changed? do
sign.sign_updater.update_sign(sign.text_id, new_top, new_bottom, 145, :now, sign.id)
sign.current_content_top != top_msg ||
sign.current_content_bottom != bottom_msg do
sign.sign_updater.update_sign(sign.text_id, top_msg, bottom_msg, 145, :now, sign.id)

%{
sign
| current_content_top: new_top,
current_content_bottom: new_bottom,
| current_content_top: top_msg,
current_content_bottom: bottom_msg,
last_update: current_time
}
else
Expand Down
15 changes: 14 additions & 1 deletion test/signs/realtime_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,19 @@ defmodule Signs.RealtimeTest do
tick_read: 0
})
end

test "prevents showing predictions that count up by 1" do
expect(Engine.Predictions.Mock, :for_stop, fn _, _ ->
[prediction(arrival: 180, destination: :ashmont)]
end)

expect_messages({"Ashmont 2 min", ""})

Signs.Realtime.handle_info(:run_loop, %{
@sign
| prev_predictions: [prediction(arrival: 120, destination: :ashmont)]
})
end
end

describe "decrement_ticks/1" do
Expand Down Expand Up @@ -1074,7 +1087,7 @@ defmodule Signs.RealtimeTest do
boarding_status: Keyword.get(opts, :boarding_status),
new_cars?: false,
revenue_trip?: true,
vehicle_id: nil
vehicle_id: "v1"
}
end

Expand Down
64 changes: 0 additions & 64 deletions test/signs/utilities/updater_test.exs

This file was deleted.

0 comments on commit df6ebc7

Please sign in to comment.