diff --git a/lib/signs/realtime.ex b/lib/signs/realtime.ex index 00065d89a..d8eca9832 100644 --- a/lib/signs/realtime.ex +++ b/lib/signs/realtime.ex @@ -35,6 +35,7 @@ defmodule Signs.Realtime do :current_time_fn, announced_arrivals: [], announced_approachings: [], + announced_approachings_with_crowding: [], announced_passthroughs: [], uses_shuttles: true ] @@ -63,6 +64,7 @@ defmodule Signs.Realtime do read_period_seconds: non_neg_integer(), announced_arrivals: [Predictions.Prediction.trip_id()], announced_approachings: [Predictions.Prediction.trip_id()], + announced_approachings_with_crowding: [Predictions.Prediction.trip_id()], announced_passthroughs: [Predictions.Prediction.trip_id()], uses_shuttles: boolean() } diff --git a/lib/signs/utilities/audio.ex b/lib/signs/utilities/audio.ex index 3a8f0b0a9..6437652c5 100644 --- a/lib/signs/utilities/audio.ex +++ b/lib/signs/utilities/audio.ex @@ -146,16 +146,24 @@ defmodule Signs.Utilities.Audio do {[], sign.announced_approachings, sign.announced_arrivals}, fn audio, {new_audios, new_approaching_trips, new_arriving_trips} -> case audio do - # TODO: Add a check for whether high-confidence crowding info is present and whether it has already been announced with an approaching message - %Audio.TrainIsArriving{trip_id: trip_id} when not is_nil(trip_id) -> - if audio.trip_id in sign.announced_arrivals do - {new_audios, new_approaching_trips, new_arriving_trips} - else - {new_audios ++ [audio], new_approaching_trips, - [audio.trip_id | new_arriving_trips]} + %Audio.TrainIsArriving{trip_id: trip_id, crowding_description: crowding_description} + when not is_nil(trip_id) -> + cond do + # If we've already announced the arrival, don't announce it + audio.trip_id in sign.announced_arrivals -> + {new_audios, new_approaching_trips, new_arriving_trips} + + # If the arrival has high-confidence crowding info but we've already announced crowding with the approaching message, announce it without crowding + crowding_description && audio.trip_id in sign.announced_approachings_with_crowding -> + {new_audios ++ [%{audio | crowding_description: nil}], new_approaching_trips, + [audio.trip_id | new_arriving_trips]} + + # else, announce normally + true -> + {new_audios ++ [audio], new_approaching_trips, + [audio.trip_id | new_arriving_trips]} end - # TODO: Start tracking trip_ids where we announce high-confidence crowding info with Approaching %Audio.Approaching{trip_id: trip_id} when not is_nil(trip_id) -> if audio.trip_id in sign.announced_approachings do {new_audios, new_approaching_trips, new_arriving_trips} @@ -170,9 +178,21 @@ defmodule Signs.Utilities.Audio do end ) + new_announced_approaching_with_crowding = + for %Audio.Approaching{trip_id: trip_id, crowding_description: crowding_description} <- + new_audios, + not is_nil(trip_id) and not is_nil(crowding_description) do + trip_id + end + sign = %{ sign | announced_approachings: Enum.take(new_approaching_trips, @announced_history_length), + announced_approachings_with_crowding: + Enum.take( + new_announced_approaching_with_crowding ++ sign.announced_approachings_with_crowding, + @announced_history_length + ), announced_arrivals: Enum.take(new_arriving_trips, @announced_history_length) } @@ -182,10 +202,35 @@ defmodule Signs.Utilities.Audio do else new_audios end + |> tap(&log_crowding(&1, sign.id)) {new_audios, sign} end + defp log_crowding(new_audios, sign_id) do + Enum.each(new_audios, fn + %{ + trip_id: trip_id, + crowding_description: crowding_description, + route_id: "Orange", + __struct__: audio_type + } + when audio_type in [Audio.Approaching, Audio.TrainIsArriving] -> + announcement_type = + case audio_type do + Audio.Approaching -> "approaching" + Audio.TrainIsArriving -> "arrival" + end + + Logger.info( + "crowding_log: announcement_type=#{announcement_type} trip_id=#{trip_id} sign_id=#{sign_id} crowding_description=#{inspect(crowding_description)}" + ) + + _ -> + nil + end) + end + @spec sort_audio([Content.Audio.t()]) :: [Content.Audio.t()] defp sort_audio(audios) do Enum.sort_by(audios, fn audio -> diff --git a/test/signs/utilities/audio_test.exs b/test/signs/utilities/audio_test.exs index 8dbe335e5..d8056d79f 100644 --- a/test/signs/utilities/audio_test.exs +++ b/test/signs/utilities/audio_test.exs @@ -823,5 +823,178 @@ defmodule Signs.Utilities.AudioTest do assert log =~ "message_to_audio_warning Utilities.Audio generic_paging_mismatch" end + + test "Announce approaching with crowding when condfidence high" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :approaching, + route_id: "Orange", + crowding_data_confidence: :high, + crowding_description: {:front, :some_crowding} + }, + current_content_bottom: %Content.Message.Empty{} + } + + {audios, _} = from_sign(sign) + + assert [ + %Content.Audio.Approaching{ + destination: :oak_grove, + crowding_description: {:front, :some_crowding} + } + ] = audios + end + + test "Announce approaching without crowding when condfidence low" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :approaching, + route_id: "Orange", + crowding_data_confidence: :low, + crowding_description: {:front, :some_crowding} + }, + current_content_bottom: %Content.Message.Empty{} + } + + {audios, _} = from_sign(sign) + + assert [ + %Content.Audio.Approaching{ + destination: :oak_grove, + crowding_description: nil + } + ] = audios + end + + test "Track announced approachings with crowding" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :approaching, + route_id: "Orange", + crowding_data_confidence: :high, + crowding_description: {:front, :some_crowding}, + trip_id: "trip1" + }, + current_content_bottom: %Content.Message.Empty{} + } + + {audios, sign} = from_sign(sign) + + assert [ + %Content.Audio.Approaching{ + destination: :oak_grove, + crowding_description: {:front, :some_crowding} + } + ] = audios + + assert(["trip1"] = sign.announced_approachings_with_crowding) + end + + test "Don't track announced approachings without crowding" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :approaching, + route_id: "Orange", + crowding_data_confidence: :low, + crowding_description: {:front, :some_crowding}, + trip_id: "trip1" + }, + current_content_bottom: %Content.Message.Empty{} + } + + {audios, sign} = from_sign(sign) + + assert [ + %Content.Audio.Approaching{ + destination: :oak_grove, + crowding_description: nil + } + ] = audios + + assert([] = sign.announced_approachings_with_crowding) + end + + test "Announce arrival with crowding if not already announced" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :arriving, + route_id: "Orange", + crowding_data_confidence: :high, + crowding_description: {:front, :some_crowding}, + trip_id: "trip2" + }, + current_content_bottom: %Content.Message.Empty{}, + announced_approachings_with_crowding: ["trip1"] + } + + {audios, _} = from_sign(sign) + + assert [ + %Content.Audio.TrainIsArriving{ + destination: :oak_grove, + crowding_description: {:front, :some_crowding} + } + ] = audios + end + + test "Don't announce arrival with crowding if confidence low" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :arriving, + route_id: "Orange", + crowding_data_confidence: :low, + crowding_description: {:front, :some_crowding}, + trip_id: "trip2" + }, + current_content_bottom: %Content.Message.Empty{}, + announced_approachings_with_crowding: ["trip1"] + } + + {audios, _} = from_sign(sign) + + assert [ + %Content.Audio.TrainIsArriving{ + destination: :oak_grove, + crowding_description: nil + } + ] = audios + end + + test "Don't announce arrival with crowding if already announced with approaching" do + sign = %{ + @sign + | current_content_top: %Message.Predictions{ + destination: :oak_grove, + minutes: :arriving, + route_id: "Orange", + crowding_data_confidence: :high, + crowding_description: {:front, :some_crowding}, + trip_id: "trip1" + }, + current_content_bottom: %Content.Message.Empty{}, + announced_approachings_with_crowding: ["trip1"] + } + + {audios, _} = from_sign(sign) + + assert [ + %Content.Audio.TrainIsArriving{ + destination: :oak_grove, + crowding_description: nil + } + ] = audios + end end end