Aliases: add module aliases for 9 nested module references Apply: replace apply/3 with direct module attribute calls Line length: break 1 long spec line Refactoring: extract helpers to reduce complexity and nesting in show.ex, radio.ex, weather workers, terrain, duct detection, backfill dashboard, contact map, and mix tasks
91 lines
2.3 KiB
Elixir
91 lines
2.3 KiB
Elixir
defmodule Microwaveprop.Commercial.PollWorker do
|
|
@moduledoc false
|
|
use Oban.Worker, queue: :commercial, max_attempts: 1
|
|
|
|
alias Microwaveprop.Commercial
|
|
alias Microwaveprop.Commercial.SnmpClient
|
|
alias Microwaveprop.Weather
|
|
alias Microwaveprop.Weather.IemClient
|
|
|
|
require Logger
|
|
|
|
@impl Oban.Worker
|
|
def perform(%Oban.Job{}) do
|
|
links = Commercial.enabled_links()
|
|
|
|
poll_and_record(links, &SnmpClient.poll/3)
|
|
fetch_weather(links)
|
|
|
|
:ok
|
|
end
|
|
|
|
def poll_and_record(links, poll_fn) do
|
|
now = DateTime.utc_now()
|
|
Enum.each(links, &poll_link(&1, poll_fn, now))
|
|
end
|
|
|
|
defp poll_link(link, poll_fn, now) do
|
|
case poll_fn.(link.host, link.community, link.radio_type) do
|
|
{:ok, data} ->
|
|
save_sample(link, data, now)
|
|
|
|
{:error, reason} ->
|
|
Logger.warning("SNMP poll failed for #{link.label} (#{link.host}): #{inspect(reason)}")
|
|
end
|
|
end
|
|
|
|
defp save_sample(link, data, now) do
|
|
attrs =
|
|
data
|
|
|> Map.put(:link_id, link.id)
|
|
|> Map.put(:sampled_at, now)
|
|
|
|
case Commercial.create_sample(attrs) do
|
|
{:ok, _sample} ->
|
|
Logger.info("Recorded sample for #{link.label}")
|
|
|
|
{:error, changeset} ->
|
|
Logger.warning("Failed to save sample for #{link.label}: #{inspect(changeset.errors)}")
|
|
end
|
|
end
|
|
|
|
defp fetch_weather(links) do
|
|
stations =
|
|
links
|
|
|> Enum.map(& &1.weather_station)
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.uniq()
|
|
|
|
now = DateTime.utc_now()
|
|
start_dt = DateTime.add(now, -3600, :second)
|
|
|
|
Enum.each(stations, &fetch_station_weather(&1, start_dt, now))
|
|
end
|
|
|
|
defp fetch_station_weather(station_code, start_dt, now) do
|
|
{:ok, station} =
|
|
Weather.find_or_create_station(%{
|
|
station_code: station_code,
|
|
station_type: "asos",
|
|
name: station_code,
|
|
lat: 0.0,
|
|
lon: 0.0
|
|
})
|
|
|
|
case IemClient.fetch_asos(station_code, start_dt, now) do
|
|
{:ok, rows} ->
|
|
ingest_asos(station, station_code, rows)
|
|
|
|
{:error, reason} ->
|
|
Logger.warning("ASOS fetch failed for #{station_code}: #{inspect(reason)}")
|
|
end
|
|
end
|
|
|
|
defp ingest_asos(station, station_code, rows) do
|
|
rows
|
|
|> Enum.filter(& &1.observed_at)
|
|
|> Enum.each(&Weather.upsert_surface_observation(station, &1))
|
|
|
|
Logger.info("Fetched #{length(rows)} ASOS observations for #{station_code}")
|
|
end
|
|
end
|