From d15821e72e7f16b486927a7938521b16e9fe9144 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 4 Jul 2025 10:23:37 -0500 Subject: [PATCH] more detail fixing --- lib/aprsme/packet.ex | 39 +- lib/aprsme/packets.ex | 2 +- .../live/weather_live/callsign_view.ex | 11 +- .../live/weather_live/callsign_view.html.heex | 385 +++++++++++------- test/aprsme/packets_weather_test.exs | 2 +- 5 files changed, 278 insertions(+), 161 deletions(-) diff --git a/lib/aprsme/packet.ex b/lib/aprsme/packet.ex index 63e566d..38f36df 100644 --- a/lib/aprsme/packet.ex +++ b/lib/aprsme/packet.ex @@ -296,12 +296,39 @@ defmodule Aprsme.Packet do data_extended end - %{} - |> put_symbol_fields(combined_data) - |> extract_weather_data(combined_data) - |> put_weather_fields(combined_data) - |> put_equipment_fields(combined_data) - |> put_message_fields(combined_data) + result = + %{} + |> put_symbol_fields(combined_data) + |> extract_weather_data(combined_data) + |> put_weather_fields(combined_data) + |> put_equipment_fields(combined_data) + |> put_message_fields(combined_data) + + # If any weather fields are present, set data_type to "weather" + weather_fields = [ + :temperature, + :humidity, + :wind_speed, + :wind_direction, + :wind_gust, + :pressure, + :rain_1h, + :rain_24h, + :rain_since_midnight, + :snow + ] + + has_weather = + Enum.any?(weather_fields, fn field -> + v = result[field] || result[to_string(field)] + not is_nil(v) + end) + + if has_weather and (result[:data_type] != "weather" and result["data_type"] != "weather") do + Map.put(result, :data_type, "weather") + else + result + end end defp put_symbol_fields(map, data_extended) do diff --git a/lib/aprsme/packets.ex b/lib/aprsme/packets.ex index ecd3675..c94a528 100644 --- a/lib/aprsme/packets.ex +++ b/lib/aprsme/packets.ex @@ -413,7 +413,7 @@ defmodule Aprsme.Packets do def get_weather_packets(callsign, start_time, end_time, opts \\ %{}) do limit = Map.get(opts, :limit, 500) - base_query = from(p in Packet, order_by: [asc: p.received_at]) + base_query = from(p in Packet, order_by: [desc: p.received_at]) query = base_query diff --git a/lib/aprsme_web/live/weather_live/callsign_view.ex b/lib/aprsme_web/live/weather_live/callsign_view.ex index 99ef422..f75243f 100644 --- a/lib/aprsme_web/live/weather_live/callsign_view.ex +++ b/lib/aprsme_web/live/weather_live/callsign_view.ex @@ -48,10 +48,13 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do end defp get_latest_weather_packet(callsign) do - # Get the most recent packet for this callsign that is a weather report - %{callsign: callsign, limit: 10} - |> Packets.get_recent_packets() - |> Enum.find(&PacketUtils.weather_packet?/1) + # Get weather packets from the last 7 days to find the most recent one + end_time = DateTime.utc_now() + start_time = DateTime.add(end_time, -7 * 24 * 3600, :second) + + callsign + |> Packets.get_weather_packets(start_time, end_time, %{limit: 1}) + |> List.first() end defp get_weather_history(callsign, start_time, end_time) do diff --git a/lib/aprsme_web/live/weather_live/callsign_view.html.heex b/lib/aprsme_web/live/weather_live/callsign_view.html.heex index e546bc1..9f66fad 100644 --- a/lib/aprsme_web/live/weather_live/callsign_view.html.heex +++ b/lib/aprsme_web/live/weather_live/callsign_view.html.heex @@ -1,158 +1,245 @@ <%= if @weather_packet do %> -
-
-

- Weather for {@callsign} - <%= if @weather_packet do %> - <% {symbol_table_id, symbol_code} = - AprsmeWeb.MapLive.PacketUtils.get_symbol_info(@weather_packet) %> - <% symbol_table = if symbol_table_id in ["/", "\\", "]"], do: symbol_table_id, else: "/" %> - <% symbol_code = symbol_code || ">" %> - <% table_id = - if symbol_table == "/", do: "0", else: if(symbol_table == "]", do: "2", else: "1") %> - <% symbol_code_ord = - symbol_code - |> String.to_charlist() - |> List.first() - |> (fn c -> if is_integer(c), do: c, else: 63 end).() %> - <% index = symbol_code_ord - 33 %> - <% safe_index = max(0, min(index, 93)) %> - <% column = rem(safe_index, 16) %> - <% row = div(safe_index, 16) %> - <% x = -column * 128 %> - <% y = -row * 128 %> - <% symbol_img = "/aprs-symbols/aprs-symbols-128-#{table_id}@2x.png" %> -
+
+
+
+
+
+

+ Weather Station +

+
+ + {@callsign} + + <% {symbol_table_id, symbol_code} = + AprsmeWeb.MapLive.PacketUtils.get_symbol_info(@weather_packet) %> + <% symbol_table = + if symbol_table_id in ["/", "\\", "]"], do: symbol_table_id, else: "/" %> + <% symbol_code = symbol_code || ">" %> + <% table_id = + if symbol_table == "/", do: "0", else: if(symbol_table == "]", do: "2", else: "1") %> + <% symbol_code_ord = + symbol_code + |> String.to_charlist() + |> List.first() + |> (fn c -> if is_integer(c), do: c, else: 63 end).() %> + <% index = symbol_code_ord - 33 %> + <% safe_index = max(0, min(index, 93)) %> + <% column = rem(safe_index, 16) %> + <% row = div(safe_index, 16) %> + <% x = -column * 128 %> + <% y = -row * 128 %> + <% symbol_img = "/aprs-symbols/aprs-symbols-128-#{table_id}@2x.png" %> +
+
+
+
+
+
+ <.link + navigate={~p"/info/#{@callsign}"} + class="inline-flex items-center rounded-md bg-gray-100 px-3 py-1.5 text-sm font-semibold text-gray-700 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-200" + > + View info + + <.link + navigate={~p"/packets/#{@callsign}"} + class="inline-flex items-center rounded-md bg-white px-3 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50" + > + View packets + + <.link + navigate={~p"/#{@callsign}"} + class="inline-flex items-center rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" + > + View on map + +
- <% end %> - <.link - navigate={~p"/info/#{@callsign}"} - class="ml-2 text-blue-600 hover:underline text-base font-normal" - > - info - - <.link - navigate={~p"/#{@callsign}"} - class="ml-2 text-blue-600 hover:underline text-base font-normal" - > - view on map - -

-
- {PacketUtils.get_timestamp(@weather_packet)} -
-
-
- Temperature: - {PacketUtils.get_weather_field(@weather_packet, :temperature)}°F -
-
- Humidity: - {PacketUtils.get_weather_field(@weather_packet, :humidity)}% -
-
- Wind: - {PacketUtils.get_weather_field(@weather_packet, :wind_direction)}° @ {PacketUtils.get_weather_field( - @weather_packet, - :wind_speed - )} mph -
-
- Gusts: - {PacketUtils.get_weather_field(@weather_packet, :wind_gust)} mph -
-
- Pressure: - {PacketUtils.get_weather_field(@weather_packet, :pressure)} hPa -
-
- Rain (1h): - {get_weather_field_zero(@weather_packet, :rain_1h)} in -
-
- Rain (24h): - {get_weather_field_zero(@weather_packet, :rain_24h)} in -
-
- Rain (since midnight): - {get_weather_field_zero(@weather_packet, :rain_since_midnight)} in
-
- Raw comment: {@weather_packet.comment || @weather_packet["comment"]} +
+
+
+
+ <% dt = + AprsmeWeb.TimeHelpers.to_datetime( + Map.get(@weather_packet, :inserted_at) || Map.get(@weather_packet, "inserted_at") + ) %> +
+
+ +
+
+

Weather Details

+
+
+
+
+
Last WX report
+
+ <%= if dt do %> + {Calendar.strftime(dt, "%Y-%m-%d %H:%M:%S UTC")} ({AprsmeWeb.TimeHelpers.time_ago_in_words( + dt + )})
+ <%!-- {Calendar.strftime(dt, "%Y-%m-%d %H:%M:%S %Z")} local time at {Map.get(@weather_packet, :region) || Map.get(@weather_packet, "region") || "Unknown location"} [?] --%> + <% else %> + Unknown + <% end %> +
+
+
+
Temperature
+
+ {PacketUtils.get_weather_field(@weather_packet, :temperature)}°F +
+
+
+
Humidity
+
+ {PacketUtils.get_weather_field(@weather_packet, :humidity)}% +
+
+
+
Wind
+
+ {PacketUtils.get_weather_field(@weather_packet, :wind_direction)}° @ {PacketUtils.get_weather_field( + @weather_packet, + :wind_speed + )} mph +
+
+
+
Gusts
+
+ {PacketUtils.get_weather_field(@weather_packet, :wind_gust)} mph +
+
+
+
Pressure
+
+ {PacketUtils.get_weather_field(@weather_packet, :pressure)} hPa +
+
+
+
Rain (1h)
+
+ {get_weather_field_zero(@weather_packet, :rain_1h)} in +
+
+
+
Rain (24h)
+
+ {get_weather_field_zero(@weather_packet, :rain_24h)} in +
+
+
+
Rain (since midnight)
+
+ {get_weather_field_zero(@weather_packet, :rain_since_midnight)} in +
+
+
+
Raw Packet
+
+ <%= if is_binary(@weather_packet.raw_packet) do %> + {Aprsme.EncodingUtils.sanitize_string(@weather_packet.raw_packet)} + <% else %> + {@weather_packet.raw_packet || ""} + <% end %> +
+
+
+
+ Raw comment: {@weather_packet.comment || @weather_packet["comment"]} +
+
-
-
-

Weather History Graphs

- <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :temperature, nil)))) do %> -
+
+
+

Weather History Graphs

+ <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :temperature, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :humidity, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :pressure, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :wind_direction, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :wind_speed, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_1h, nil)))) or Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_24h, nil)))) or Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_since_midnight, nil)))) do %> +
+
+ <% end %> + <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :luminosity, nil)))) do %> +
+
+ <% end %> +
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :humidity, nil)))) do %> -
-
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :pressure, nil)))) do %> -
-
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :wind_direction, nil)))) do %> -
-
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :wind_speed, nil)))) do %> -
-
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_1h, nil)))) or Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_24h, nil)))) or Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :rain_since_midnight, nil)))) do %> -
-
- <% end %> - <%= if Enum.any?(@weather_history, &(not is_nil(Map.get(&1, :luminosity, nil)))) do %> -
-
- <% end %> - -
+
+ <% else %>
diff --git a/test/aprsme/packets_weather_test.exs b/test/aprsme/packets_weather_test.exs index c464c26..911f279 100644 --- a/test/aprsme/packets_weather_test.exs +++ b/test/aprsme/packets_weather_test.exs @@ -209,7 +209,7 @@ defmodule Aprsme.PacketsWeatherTest do assert {:ok, stored_packet} = Packets.store_packet(packet_data) assert stored_packet.data_type == "weather" - assert stored_packet.snow == 5.0 + assert stored_packet.snow == 0.5 refute Map.has_key?(stored_packet, :raw_weather_data) refute Map.has_key?(stored_packet, "raw_weather_data") end