From 95351a2358cf437842897ba9fbb8101a34514d25 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 7 Apr 2026 13:24:58 -0500 Subject: [PATCH] Add /path calculator page LiveView page for analyzing microwave propagation between two points. Features: - Source/destination input: callsign (via gridmap.org API) or Maidenhead grid - Band selector for all 8 microwave bands (10-241 GHz) - Leaflet map showing path line (reuses ContactMap hook) - Terrain elevation cross-section (reuses ElevationProfile hook) - Link summary: distance, bearing, terrain verdict - Loss budget: FSPL + O2 + H2O + rain + diffraction - Propagation score with 10-factor breakdown - Current atmospheric conditions from path-integrated HRRR New CallsignClient for gridmap.org location lookup. Navigation links added to main navbar and map control panel. --- lib/microwaveprop/radio/callsign_client.ex | 37 ++ lib/microwaveprop_web/components/layouts.ex | 1 + lib/microwaveprop_web/live/map_live.ex | 3 + lib/microwaveprop_web/live/path_live.ex | 589 ++++++++++++++++++++ lib/microwaveprop_web/router.ex | 1 + 5 files changed, 631 insertions(+) create mode 100644 lib/microwaveprop/radio/callsign_client.ex create mode 100644 lib/microwaveprop_web/live/path_live.ex diff --git a/lib/microwaveprop/radio/callsign_client.ex b/lib/microwaveprop/radio/callsign_client.ex new file mode 100644 index 00000000..da4a0481 --- /dev/null +++ b/lib/microwaveprop/radio/callsign_client.ex @@ -0,0 +1,37 @@ +defmodule Microwaveprop.Radio.CallsignClient do + @moduledoc "Looks up amateur radio callsign locations via gridmap.org." + + @doc """ + Fetch location for a callsign. Returns {:ok, %{callsign, gridsquare, lat, lon}} or {:error, reason}. + """ + def locate(callsign) do + url = "https://gridmap.org/locate/#{URI.encode(callsign)}" + + case Req.get(url, req_options() ++ [receive_timeout: 10_000]) do + {:ok, %{status: 200, body: %{"latitude" => lat, "longitude" => lon} = body}} when is_number(lat) -> + {:ok, + %{ + callsign: body["callsign"] || callsign, + gridsquare: body["gridsquare"], + lat: lat, + lon: lon + }} + + {:ok, %{status: 200, body: _}} -> + {:error, "callsign not found"} + + {:ok, %{status: 404}} -> + {:error, "callsign not found"} + + {:ok, %{status: status}} -> + {:error, "gridmap.org HTTP #{status}"} + + {:error, reason} -> + {:error, "gridmap.org failed: #{inspect(reason)}"} + end + end + + defp req_options do + Application.get_env(:microwaveprop, :callsign_req_options, []) + end +end diff --git a/lib/microwaveprop_web/components/layouts.ex b/lib/microwaveprop_web/components/layouts.ex index 49948635..0c24a22d 100644 --- a/lib/microwaveprop_web/components/layouts.ex +++ b/lib/microwaveprop_web/components/layouts.ex @@ -41,6 +41,7 @@ defmodule MicrowavepropWeb.Layouts do NTMS Propagation Prediction