The linker error from the previous attempt was actual symbol
references, not a flag-combination oddity:
undefined reference to `g2c_enc_jpeg2000'
undefined reference to `g2c_dec_jpeg2000'
Those live in g2c's "new" file-based API, built only when
BUILD_G2C=ON. In v1.9.0 the option defaulted OFF and was marked
"experimental until 2.0.0 release", so I had explicitly disabled
it. In v2.1.0 (released 2025-01-13, before wgrib2 v3.6.0 on
2025-02-19) it defaults ON and the API is stable. Bump
G2C_VERSION to 2.1.0 and drop the BUILD_G2C override.
With the new-API symbols now exported, wgrib2 can be compiled
with every decoder we care about in one shot:
-DUSE_PNG=ON -DUSE_OPENJPEG=ON -DUSE_AEC=ON
`wgrib2 -config` in the final runtime image now reports:
Supported decoding: simple, complex, rle, ieee, png, jpeg2000,
CCSDS AEC
Verified end-to-end by building the full image with podman and
running wgrib2 -config inside it. MrmsFetchWorker's packing
type 41 (PNG) messages will decode once the rolling deploy lands.
Last attempt (-DUSE_PNG=ON -DUSE_AEC=ON on wgrib2) reached 100 %
linking libwgrib2.so and then died with "make: Error 2" on the
parallel wgrib2_exe link. wgrib2's own CI workflow
(.github/workflows/Linux_options.yml) never tests USE_PNG alone —
its matrix uses -DUSE_OPENJPEG=ON, and its NCEPLIBS-g2c is built
with -DUSE_OpenJPEG=ON -DUSE_Jasper=OFF. Copying that known-good
combination:
* g2c now builds with USE_PNG + USE_AEC + USE_OpenJPEG (Jasper
still disabled — libjasper is out of Debian anyway).
* wgrib2 flips to -DUSE_OPENJPEG=ON -DUSE_AEC=ON.
* libopenjp2-7-dev added to the builder apt list, libopenjp2-7
added to the runtime apt list so libg2c.so + wgrib2 can
resolve OpenJPEG symbols at exec time.
wgrib2 delegates actual GRIB2 decompression to g2c, which is
built with PNG support, so DRT 5.41 (MRMS PrecipRate) still
decodes through this link — wgrib2's own USE_PNG knob isn't
required for decoding, only for encoding we don't do.
The previous attempt to flip `-DUSE_PNG=ON -DUSE_AEC=ON` on wgrib2
broke the image build because wgrib2 v3.6.0's CMakeLists.txt
line 94 forces `find_package(g2c 1.9.0 REQUIRED)` whenever PNG or
JPEG2000 is enabled, and NCEPLIBS-g2c wasn't installed in the
wgrib2-builder stage.
Install NCEPLIBS-g2c v1.9.0 (the version wgrib2 asks for) in the
wgrib2-builder stage ahead of wgrib2 itself, with:
- USE_PNG=ON (needs libpng-dev, already present)
- USE_AEC=ON (needs libaec-dev, already present)
- USE_Jasper=OFF (default ON — would need libjasper-dev
and another runtime dep we don't need)
- USE_OpenJPEG=OFF (same rationale)
- BUILD_G2C=OFF (new experimental API, not needed here)
Then flip wgrib2's PNG/AEC flags back on. wgrib2's binary links
dynamically against libg2c.so so the final stage copies
/usr/local/lib/libg2c.so* from the builder and refreshes the
loader cache with ldconfig.
With the decoder restored, re-add MrmsFetchWorker to the prod
cron in runtime.exs. That worker pulls NOAA MRMS PrecipRate grids
every 2 minutes, which use GRIB2 DRT 5.41 (PNG-compressed) — the
whole reason we needed the PNG decoder in the first place. ASOS
nudges will now have a live radar overlay again.
The previous commit that added -DUSE_PNG=ON -DUSE_AEC=ON to the
wgrib2 cmake invocation broke the image build: wgrib2 3.6.0 turns
find_package(g2c 1.9.0 REQUIRED) on when those flags are enabled,
and NCEPLIBS-g2c isn't installed in the wgrib2-builder stage.
Revert to the stock wgrib2 cmake config so CI is green again and
pull MrmsFetchWorker out of the prod cron instead. Without the
PNG decoder the worker can't read MRMS PrecipRate (GRIB2 DRT
5.41) and was logging "packing type 41 not supported" every two
minutes. AsosAdjustmentWorker's MRMS path already handles an
empty cache gracefully — the ASOS nudge still runs, it just
drops the live radar overlay.
Re-add MrmsFetchWorker once the Dockerfile installs NCEPLIBS-g2c
and rebuilds wgrib2 with PNG/AEC support.
Prod wgrib2 3.6.0 was built without PNG support (cmake had no
-DUSE_PNG flag) so MrmsFetchWorker crashed on every tick with
'packing type 41 not supported' — MRMS PrecipRate tiles are
PNG-compressed (GRIB2 DRT 5.41). libpng-dev was already in the
builder stage; the cmake invocation just never asked wgrib2 to
use it.
Also turn on -DUSE_AEC=ON since libaec-dev is already installed
and some HRRR native-grid variables ship with AEC/CCSDS 121
compression.
Vendor oban_web 2.12.1 and oban_met 1.1.0 (taken from the
towerops-web2 vendor tree), bump oban to ~> 2.21, and mount the Oban
dashboard at /admin/oban behind the existing require_admin on_mount
hook. Adds an admin-only "Oban" nav link and extends the Dockerfile
to copy vendor/ before deps.get so production builds pick up the
path dependencies.
Move COPY priv after mix compile so ML model retraining doesn't bust
the compile cache. Create empty priv dirs before compile for
:code.priv_dir. Move algo.md after compile. Add docs/plans and
analysis outputs to .dockerignore.
Add a separate wgrib2-builder stage that compiles wgrib2 from source.
Docker layer caching means this only builds once — subsequent deploys
reuse the cached layer. The binary is copied into the final runtime
image. Also fixed wgrib2 path lookup to be runtime instead of
compile-time so it works in the Docker build pipeline.
Poll UBNT AirFiber radios (AF11X + AF60-LR) every 5 minutes via
net-snmp CLI, storing signal metrics in commercial_samples. Fetches
ASOS weather alongside each cycle for propagation correlation.
Includes 7 seeded link definitions, Oban cron worker, and net-snmp
in the Docker image.
Fetch elevation data along the path between two stations via the
Open-Meteo Elevation API (with Open-Topo-Data fallback), compute
Fresnel zone clearance, earth bulge, and knife-edge diffraction loss,
and store the results per QSO.
- terrain_profiles table with migration and TerrainProfile schema
- ElevationClient with batched API calls and fallback
- TerrainAnalysis with Fresnel/diffraction physics (ITU-R P.526-15)
- TerrainProfileWorker on Oban :terrain queue
- QsoWeatherEnqueueWorker enqueues terrain jobs automatically
- QSO show page displays verdict badge and collapsible elevation table
- Reorder show page: terrain, soundings, solar, HRRR, surface obs
- Fix Dockerfile wgrib2 build (add cmake dependency)
HRRR provides hourly 3km-resolution atmospheric profiles, filling the
temporal gaps (12-hourly soundings) and spatial gaps (only 9 sounding
stations) in our current weather data.
- Add hrrr_profiles table and hrrr_queued flag on QSOs
- HrrrClient fetches GRIB2 data via HTTP Range requests + wgrib2
- HrrrFetchWorker derives refractivity/ducting params via SoundingParams
- QsoWeatherEnqueueWorker now also enqueues HRRR jobs
- QSO show page displays HRRR section with collapsible profile
- Dockerfile builds wgrib2 from source for production