Ask the weather where you are

54a26e2 · Gabriel Morell · 2026-09-03 18:18

38 files +176 -25
Message
{commit_body(@commit)}

Files changed

modified PLANI.md
+9 −8
@@ -76,11 +76,12 @@ the coordinates it comes from and stays out of the importer's way by staying
76 76 out of the Ecto schema.
77 77
78 78 **Sources answered *at* a point rather than *near* one.** Weather, sunrise,
79 −pollen, the tide at the nearest station: there is one answer and it is
80 −computed for wherever you are. These already take a `foci_id` in their query
81 −config (`weather`, `ephem`, `pollen`, `calendar`, `cronos`, `icarus`), so the
82 −change is to accept a point instead — the smallest useful stage, and it needs
83 −no spatial indexing at all.
79 +pollen, what is overhead: there is one answer and it is computed for wherever
80 +you are. Done, via `Configuration.place_for!/1` — every one of them resolved a
81 +foci with the same two lines, so they now take a place when one is handed over
82 +and a foci id otherwise. `weather`, `ephem`, `pollen` and `icarus` relocate;
83 +`cronos` uses its foci for a timezone rather than a position, and `calendar`
84 +for filtering, so neither moves.
84 85
85 86 **Sources with no location.** `github`, `gitlab`, `packages`, `mailbox`,
86 87 `treasury`, `bourse`. A Plani should either refuse these or pass them through
@@ -94,9 +95,9 @@ rather than discovering at runtime.
94 95 home foci. Publishes nothing yet — but the resolution, the expiry and the
95 96 fallback are the part with the design risk in it, and it can be watched on
96 97 a page before anything depends on it.
97 −2. **Relocatable point sources.** Give the query workers that take a `foci_id`
98 − a way to take a `%Geo.Point{}`. Weather and ephem where you are. No schema
99 − changes.
98 +2. ~~**Relocatable point sources.**~~ Done: `place_for!/1` is the one helper
99 + they all use, so a Plani relocates weather, sunrise, pollen and aircraft
100 + without any of them knowing what a Plani is.
100 101 3. **Nearest-N for what is already indexed.** GBFS stations and bikes, AQI
101 102 monitors. The queries exist; they need a limit and a caller.
102 103 4. ~~**GTFS stops.**~~ Done: `gtfs_stops.place` is generated and GiST indexed,
modified apps/room_cronos/lib/room_cronos/cronos_worker.ex
+1 −1
@@ -12,7 +12,7 @@ defmodule RoomCronos.Worker do
12 12 # @decorate cacheable(cache: RoomZeus.Cache, opts: [ttl: @ttl])
13 13 def query_cronos(name, query) do
14 14 q = Configuration.get_query!(name)
15 − foci = Configuration.get_foci!(query.foci_id)
15 + foci = %{place: Configuration.place_for!(query)}
16 16 {lon, lat} = foci.place.coordinates
17 17 tz = WhereTZ.lookup(lat, lon)
18 18 now = DateTime.now!(tz)
modified apps/room_ephem/lib/room_ephem/ephem_worker.ex
+2 −3
@@ -97,8 +97,7 @@ defmodule RoomEphem.Worker do
97 97 @decorate cacheable(cache: RoomZeus.Cache, opts: [ttl: @ttl])
98 98 def query_ephem(_name, query) do
99 99 IO.inspect("QEPH")
100 − foci = Configuration.get_foci!(query.foci_id)
101 − {lon, lat} = foci.place.coordinates
100 + {lon, lat} = Configuration.place_for!(query).coordinates
102 101 lat = normalize_ll(lat)
103 102 lon = normalize_ll(lon)
104 103
@@ -136,7 +135,7 @@ defmodule RoomEphem.Worker do
136 135 |> DateTime.to_time()
137 136 },
138 137 %{period: :phase, result: phase},
139 − %{name: foci.name}
138 + %{name: Configuration.place_name(query)}
140 139 ] ++ moon_entries
141 140 end
142 141 end
modified apps/room_icarus/lib/room_icarus/worker.ex
+7 −1
@@ -317,7 +317,7 @@ defmodule RoomIcarus.Worker do
317 317 defp via_tuple(name), do: {:via, Registry, {@registry, name}}
318 318
319 319 defp target_from_query(query) do
320 − case resolve_foci(field(query, :foci_id)) do
320 + case resolve_foci(RoomSanctum.Configuration.place_for!(query) || field(query, :foci_id)) do
321 321 {lat, lon} -> {lat, lon, clamp_dist(field(query, :dist))}
322 322 nil -> nil
323 323 end
@@ -325,6 +325,12 @@ defmodule RoomIcarus.Worker do
325 325
326 326 defp resolve_foci(nil), do: nil
327 327
328 + # A Plani asks from wherever its client is, which is not a foci and has no
329 + # row to look up.
330 + # Matched by shape rather than as a %Geo.Point{}: this app does not
331 + # depend on geo, and the only thing here with coordinates is a place.
332 + defp resolve_foci(%{coordinates: {lon, lat}}), do: {lat, lon}
333 +
328 334 defp resolve_foci(foci_id) do
329 335 try do
330 336 case Configuration.get_foci!(foci_id) do
modified apps/room_pollen/lib/room_pollen/worker.ex
+11 −2
@@ -131,7 +131,10 @@ defmodule RoomPollen.Worker do
131 131 defp creds(_), do: :no_creds
132 132
133 133 defp target_from_query(query) do
134 − foci_id = Map.get(query, :foci_id) || Map.get(query, "foci_id")
134 + # A place if one was handed over, otherwise the foci named in the query.
135 + anchor =
136 + RoomSanctum.Configuration.place_for!(query) ||
137 + Map.get(query, :foci_id) || Map.get(query, "foci_id")
135 138
136 139 days =
137 140 case Map.get(query, :days) || Map.get(query, "days") do
@@ -140,7 +143,7 @@ defmodule RoomPollen.Worker do
140 143 _ -> 3
141 144 end
142 145
143 − case resolve_foci(foci_id) do
146 + case resolve_foci(anchor) do
144 147 {lat, lng} -> {lat, lng, days}
145 148 nil -> nil
146 149 end
@@ -148,6 +151,12 @@ defmodule RoomPollen.Worker do
148 151
149 152 defp resolve_foci(nil), do: nil
150 153
154 + # A Plani asks from wherever its client is, which is not a foci and has no
155 + # row to look up.
156 + # Matched by shape rather than as a %Geo.Point{}: this app does not
157 + # depend on geo, and the only thing here with coordinates is a place.
158 + defp resolve_foci(%{coordinates: {lng, lat}}), do: {lat, lng}
159 +
151 160 defp resolve_foci(foci_id) do
152 161 try do
153 162 case Configuration.get_foci!(foci_id) do
modified ?
+0 −0

Click to load diff…

modified ?
+0 −0

Click to load diff…

modified apps/room_sanctum/lib/room_sanctum/configuration.ex
+35 −0

Click to load diff…

modified apps/room_sanctum/lib/room_sanctum/workers/plani_worker.ex
+33 −2

Click to load diff…

modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_plani_live/form_component.ex
+22 −6

Click to load diff…

added apps/room_sanctum/test/room_sanctum/place_for_test.exs
+55 −0

Click to load diff…

modified apps/room_weather/lib/room_weather/weather_worker.ex
+1 −2

Click to load diff…

Parents: 7b6b5ac