Subscribes to mqtt.pskreporter.info:1883 over plain TCP and folds every reception report into hourly aggregates per (band, sender_grid_4, receiver_grid_4). Each spot is the empirical "propagation actually occurred on this path right now" signal we'll correlate against HRRR atmospheric state to recalibrate the scoring weights. Aggregating at the path-hour bucket collapses 50-reporter QSOs to one row instead of 50. Topic filter anchors on USA (DXCC 291) on either sender or receiver side so the broker pre-filters out everything outside our HRRR domain. Bands subscribed: VHF and up (6m, 2m, 70cm, 23cm, + microwave) — HF is dominated by ionospheric propagation, which this project doesn't model. Pskr.Client cluster-elects a singleton via :global.register_name — all replicas start the GenServer but only one connects to MQTT; the rest stay in :standby and watch for the leader's nodedown to re-run election. Off in dev/test, on by default in prod (PSKR_MQTT_ENABLED=false as kill-switch). Pskr.Aggregator buffers in memory keyed by Pskr.path_key/1 and flushes every 60s via Repo.insert_all/3 with an additive ON CONFLICT (count summed, SNR envelope by GREATEST/LEAST, modes unioned via unnest+DISTINCT). Idempotent across overlapping flushes and across leader handover. Dockerfile sets BUILD_WITHOUT_QUIC=1 — emqtt's transitive quicer dep wants CMake + OpenSSL headers we'd otherwise have to add to the builder image just to never use QUIC over plain MQTT. Base image is unchanged; the new dep compiles cleanly into the existing prop-base runtime.
33 lines
1.1 KiB
Elixir
33 lines
1.1 KiB
Elixir
defmodule Microwaveprop.Repo.Migrations.CreatePskrSpotsHourly do
|
|
use Ecto.Migration
|
|
|
|
def change do
|
|
create table(:pskr_spots_hourly, primary_key: false) do
|
|
add :id, :binary_id, primary_key: true
|
|
add :hour_utc, :utc_datetime, null: false
|
|
add :band, :string, null: false
|
|
add :sender_grid, :string, null: false
|
|
add :receiver_grid, :string, null: false
|
|
add :sender_country, :integer
|
|
add :receiver_country, :integer
|
|
add :sender_lat, :float
|
|
add :sender_lon, :float
|
|
add :receiver_lat, :float
|
|
add :receiver_lon, :float
|
|
add :midpoint_lat, :float
|
|
add :midpoint_lon, :float
|
|
add :distance_km, :float
|
|
add :spot_count, :integer, null: false, default: 0
|
|
add :max_snr_db, :integer
|
|
add :min_snr_db, :integer
|
|
add :modes, {:array, :string}, null: false, default: []
|
|
add :first_spot_at, :utc_datetime
|
|
add :last_spot_at, :utc_datetime
|
|
|
|
timestamps(type: :utc_datetime)
|
|
end
|
|
|
|
create unique_index(:pskr_spots_hourly, [:hour_utc, :band, :sender_grid, :receiver_grid])
|
|
create index(:pskr_spots_hourly, [:hour_utc])
|
|
end
|
|
end
|