The Receipts
The live OMEGA Gateway API documentation, showing external provider endpoints for Copernicus, Argo floats, METAR stations and tide gauges
The gateway documents itself. This is the running service at omega.jonathancapone.com/docs, listing its own endpoints against Copernicus, the Argo float network, METAR stations and UK tide gauges.

What This Service Has Actually Done.

This is the densest page on the site, so the evidence comes first: what the gateway's database held at its last census, where that data comes from, and what its own analysis code has caught in the wild. Every frame from OMEGA's own hardware also carries a cryptographic signature the gateway verifies; step 2 of the walkthrough below shows how.

Live Data

Live Database Census & Test Coverage

The gateway SQLite database currently stores ~989,207 measurements and 44,549 observations over a 14.2-day span. Zero rows are simulated.

Source Split: 53.5% from OMEGA mesh hardware vs 46.5% from real third-party networks (NOAA NDBC, Open-Meteo, NWS, CO-OPS).

Coverage: The Python gateway is backed by an automated test suite, providing end-to-end assertions against security, payload tamper, and protocol conformance vectors.

Public + Private

One Envelope, Every Source

Public sources (NOAA NDBC buoys, CO-OPS tide gauges, Open-Meteo marine models) are normalized into the exact same Observation Envelope (the common format every reading is converted to on arrival) as OMEGA's own hardware. Nearly half the database is real third-party data sitting beside the mesh's own readings, queryable identically. See the envelope →

The Receipts: Detection

OMEGA Analysed It: Storm Regime-Shift.

The Python gateway's statistical suite analyzes the data it collects. Below, OMEGA's own statistics ran over public NOAA buoy 46013 wave data to spot the moment the sea state shifted. The algorithm correctly identifies a significant regime shift (a -0.77 m drop at 2026-06-08) as a synoptic storm event subsides.

The Significance: This proves the system can recognize large-scale weather events happening across the external buoys, which can then be cross-correlated and verified against the telemetry coming from OMEGA's own physical edge nodes.

The honest line: OMEGA's algorithm detected the shift, but a human chose the example.

Storm regime shift at NOAA buoy 46013 with OMEGA changepoint marker
How It Works

The Life of a Frame.

The OMEGA Gateway is a large Python backend, including OGC SensorThings API v1.1 and ERDDAP-compatible read surfaces for standards-based interop. Designed to run on embedded Linux (e.g. Raspberry Pi 5) deployed directly at the coastal shore, it acts as the master ingestion point for the entire Delay Tolerant Network.

(The Delay Tolerant Network is OMEGA's offshore radio mesh, built on the assumption that links appear and vanish without warning.) The clearest way to see what the gateway does with that traffic is to follow a single frame ashore, in six steps: it arrives, proves who sent it, is normalized into a common envelope, passes quality control, lands in the database, and is served back out live.

Life of a Frame, Step 1: A Frame Arrives

T-ETH-ELITE & The Ingest Contract.

The OMEGA federated network now runs on specialized, headless edge gateways; Phase 1 relied on a single USB-tethered relay node. These gateways are entirely "dumb pipes"; they do not decrypt or decode payloads, allowing any community member to safely operate a gateway node.

Gateway Silicon

T-ETH-ELITE (ESP32-S3)

The physical gateway consists of a LilyGo T-ETH-ELITE baseboard stacked with a T-SX1302 8-channel concentrator shield. This lets the node listen to 8 LoRa channels at once, catching bursts of DTN bundles across the mesh.

Data Transfer

Semtech UDP Protocol

Operating via the custom esxp1302 packet forwarder, the gateway captures raw RF frames using the 0x34 public sync word. It immediately wraps these raw bytes into standard Semtech UDP packets and fires them over Ethernet or Wi-Fi to the central FastAPI ingest engine.

The Universal API

The Ingest Contract

The gateway only POSTs raw base64 data to /v1/ingest/frame. The centralized OMEGA database manages all deduplication by tracking the origin key and sequence, allowing 5 different community gateways to hear and forward the same packet safely.

Life of a Frame, Step 2: Prove Who Sent It

Elliptic Curve Cryptography (ECC).

The LoRa constraint is 50 bytes. Standard web security relies on RSA (Rivest–Shamir–Adleman), which requires 2048-bit keys, and that translates mathematically to 256 bytes of pure cryptographic overhead per packet. RSA is physically impossible at that size.

Ed25519 Signatures

EdDSA over Curve25519

OMEGA signs packets with Ed25519 (EdDSA over the twisted Edwards Curve25519). It provides roughly a 128-bit security level using 32-byte public keys and 64-byte signatures, which keeps the cryptographic overhead small enough to fit the constrained RF airtime.

AES-GCM Authentication

Galois/Counter Mode

To encrypt payloads dynamically, OMEGA uses Authenticated Encryption with Associated Data (AEAD). The GCM mode calculates a mathematical GHASH tag appended to the end of the payload. If a rogue actor intercepts the packet and flips a single bit, the GHASH tag is instantly destroyed, forcing the gateway to silently drop the packet.

Cryptographic Handshake
sequenceDiagram
    participant E as Edge Node (ESP32)
    participant G as Gateway (Python)
    
    Note over E,G: 1. Asymmetric Key Exchange
    E->>G: Hello (Buoy Public Key: Ed25519)
    G->>E: Acknowledge (Gateway Public Key)
    
    Note over E,G: 2. ECDH Shared Secret Generation
    E->>E: Math: (Gateway Pub * Buoy Priv) = Secret
    G->>G: Math: (Buoy Pub * Gateway Priv) = Secret
    
    Note over E,G: 3. Symmetric AEAD Tunnel Established
    E->>G: AES-GCM Encrypted Telemetry + GHASH Tag
    G->>G: Decrypt using Shared Secret. Verify GHASH.
    G-->>E: 200 OK (Encrypted ACK)
Hardware Identity

Immutable Cryptographic Identity.

To prevent malicious impersonation or the "wrong firmware on wrong board" cascade, the mesh protocol verifies the silicon behind every frame alongside the self-reported node_id.

Execution: Every JSON telemetry and command frame now carries an immutable physical_mac (the chip's factory eFuse-burned MAC address) and a physical_board_tag (e.g., tbeam-supreme-physical) baked in at flash time. The gateway bridge actively cross-checks these tags against the expected hardware profile for the assigned node. If an edge node claims to be a relay but its physical tags identify it as a Supreme sensor board, the bridge loudly flags the mismatch and isolates the node.

Honesty Note: Signature Verification

The signing pipeline is proven on the real code path in test databases, but the external publisher feeds (NOAA/NDBC, Open-Meteo) are unsigned, so live signature verification against third-party traffic isn't demonstrated yet.

Life of a Frame, Step 3: Normalize It

The Observation Envelope.

Disparate marine sensors natively produce chaotic, proprietary data formats: a YSI sonde outputs ASCII strings, while a BlueRobotics pressure sensor outputs raw hex. OMEGA standardizes all incoming telemetry into a strict Observation Envelope schema.

This schema is the common currency of the OMEGA network. Every measurement entering the system carries a ULID message_id, an ISO-8601 timestamp, explicit SI units, and spatial coordinates (Latitude/Longitude/Depth); the boundary layer enforces spatial bounding-box constraints on those coordinates.

How it works: By enforcing this envelope at the boundary layer via Pydantic models, downstream systems (such as bathymetry processors, machine learning models, or QARTOD Quality Control algorithms) all read one format, whatever manufacturer the reading came from. They ingest the normalized Envelope, process the payload, and output a new Envelope. This strict data contract enables broad interoperability across the fleet.

Raw Data Structures

The Observation Envelope Payload.

The observation-envelope.json is the fundamental atomic unit of the OMEGA network. This payload standardizes disparate sensor data into a strict schema. It uses SenML (Sensor Measurement Lists) under the payload.records array to explicitly define physical units (e.g., `Cel` for Celsius, `m` for meters), so a downstream data scientist always knows what unit a floating-point value carries.

Each measurement also carries a ULID message_id, a lexicographically sortable identifier that prevents database collisions across thousands of edge nodes. The ttl_s (Time-To-Live in seconds) parameter is important for the DTN mesh; it dictates how long this packet should live inside a node's NVRAM buffer before being purged to save memory.

observation-envelope.example.json
{
  "spec": "omega.observation-envelope/1",
  "message_id": "01HSJ9R2XW6T4Q3AP7D3R5K8NE",
  "message_type": "observation",
  "origin": {
    "node_id": "urn:OA:node:site-a:buoy-02",
    "device_id": "water-quality-probe-main",
    "capability_ref": "https://example.invalid/omega/things/site-a-buoy-02-water-quality.td.json",
    "firmware_version": "0.1.0"
  },
  "routing": {
    "priority": "normal",
    "ttl_s": 86400,
    "ack_mode": "gateway",
    "max_hops": 8
  },
  "sample": {
    "sampled_at": "2026-04-18T18:30:00Z",
    "sequence": 1842,
    "location": {
      "lat": 36.8054,
      "lon": -121.7891,
      "depth_m": 4.2
    }
  },
  "tags": {
    "site": "site-a",
    "platform": "buoy",
    "medium": "water"
  },
  "payload": {
    "mode": "senml",
    "content_type": "application/senml+json",
    "schema_ref": "urn:ietf:rfc:8428",
    "records": [
      {
        "bn": "urn:OA:thing:site-a:buoy-02:water-quality/",
        "bt": 1776537000
      },
      {
        "n": "temperature",
        "u": "Cel",
        "v": 13.42
      },
      {
        "n": "salinity",
        "u": "psu",
        "v": 33.91
      },
      {
        "n": "dissolved-oxygen",
        "u": "mg/L",
        "v": 8.11
      },
      {
        "n": "battery-voltage",
        "u": "V",
        "v": 3.92
      }
    ]
  }
}
Strict Validation

JSON Schema Enforcement.

To protect the core SQLite database from malformed, corrupt, or actively malicious payloads injected by rogue edge nodes, OMEGA relies on strict JSON schema validation located in the schemas/ directory.

Execution: Before a network packet is ever parsed by the Python backend, it is rapidly validated against the observation-envelope.schema.json definition using the jsonschema library. Any payload missing critical routing arrays, origin UUIDs, or containing the wrong data type is instantly dropped, ensuring database integrity is never compromised by field errors.

observation-envelope.schema.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.invalid/omega/observation-envelope.schema.json",
  "title": "OMEGA Observation Envelope",
  "description": "Canonical application-level envelope for sensor observations.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "spec",
    "message_id",
    "message_type",
    "origin",
    "routing",
    "sample",
    "payload"
  ]
}
Life of a Frame, Step 4: Quality Control

Automated Quality Control.

Raw marine data is scientifically useless until it is vetted. Before a sensor measurement is allowed to enter the normalized SQLite database, it must pass through the Gateway's strict IOOS QARTOD compliance engine.

Execution: The Python backend (gateway/qc.py) uses the Median Absolute Deviation (MAD) to calculate a Robust Sigma over the trailing time-series window. This sigma flags incoming measurements for spikes, sensor flat-lines (indicating a fouled probe), or gross-range biological violations, appending a 1-4 quality flag to the Observation Envelope. A separate spatial buddy-check (gateway/buddy_check.py) compares each station against its neighbours.

gateway/qc.py
def _threshold_bundle(values: list[float]) -> dict[str, float] | None:
    center = median(values)
    sigma = _robust_sigma(values)
    return {
        "center": center,
        "sigma": sigma,
        "gross_range_suspect_min": center - sigma * 3,
        "gross_range_suspect_max": center + sigma * 3,
        "gross_range_fail_min": center - sigma * 6,
        "gross_range_fail_max": center + sigma * 6,
        "rate_of_change_suspect": sigma * 3,
        "rate_of_change_fail": sigma * 6,
        "spike_suspect": sigma * 3,
        "spike_fail": sigma * 6,
    }
Life of a Frame, Step 5: Store It

Handling Many Readings at Once.

Database Architecture: Telemetry arrives asynchronously via UDP and Serial ports at high volumes. A standard SQLite configuration would instantly lock and crash under this concurrent write pressure. The Python backend physically rewrites the SQLite PRAGMA at boot, enforcing Write-Ahead Logging (WAL) mode and NORMAL synchronous behavior. This decouples the read/write locks, allowing the Mission Portal to execute large SELECT queries over the historical arrays while the edge node bridges concurrently INSERT live TLV frames without blocking.

Background Tasks

Heavy normalization operations are pushed to a background job, so the sender gets an instant acknowledgement instead of waiting for the slow work to finish.

gateway/main.py
    @asynccontextmanager
    async def _lifespan(fastapi_app: FastAPI) -> AsyncIterator[None]:
        scheduler = getattr(fastapi_app.state, "scheduler", None)
        notif_bus = getattr(fastapi_app.state, "notification_bus", None)
        
        # Attach internal NotificationBus to the async loop
        if notif_bus is not None:
            notif_bus.attach_loop(asyncio.get_running_loop())
            
        # Start periodic tasks (e.g. evaluating active watches)
        if scheduler is not None:
            await scheduler.start()
            
        try:
            yield
        finally:
            if scheduler is not None:
                await scheduler.stop()
            if notif_bus is not None:
                notif_bus.detach_loop()

    app = FastAPI(
        title="OMEGA Gateway",
        description="Gateway API for a mixed-bearer environmental sensor mesh.",
        lifespan=_lifespan,
    )
Database Engineering

SQLite Normalization & WAL.

A distributed mesh generates continuous, erratic, write-heavy load. The gateway uses a SQLite store specifically designed for mesh provenance (multi-gateway sightings, dedup on `(origin, sequence)`, idempotent ingest). Traditional SQLite configurations use database-level locks; when a write occurs, the entire file is locked, which causes `database is locked` exceptions for any dashboard attempting to read the data concurrently.

To eliminate this bottleneck, the OMEGA gateway configures its SQLite engine in Write-Ahead Logging (WAL) mode using explicit PRAGMA statements on startup. A write appends its changes to a separate `.wal` file and leaves the main database file unlocked.

Relevance: This allows readers (the Mission Portal fetching historical graphs) to concurrently access the database without ever being blocked by writers (the continuous telemetry ingest). `PRAGMA synchronous=NORMAL` also relaxes the rigid sync constraints, raising write throughput on the SD cards of Raspberry Pi gateways without risking file-system corruption.

SQLite Configuration
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA cache_size=-64000;
Life of a Frame, Step 6: Serve It Out

The Pub/Sub Pattern.

The same bus that protects ingest is how a stored reading leaves: on insert, the NotificationBus fans the event out to every connected WebSocket client, while REST queries (and the SensorThings v1.1 and ERDDAP-compatible read surfaces noted above) serve the stored history.

The bus exists because direct calls are fragile. If the Python script receiving radio packets directly calls the database insert() function, a slow SD card write will physically block the processor from receiving the next radio packet, dropping critical telemetry.

Producers (Publishers)

The Radio Receiver

The receiver script does exactly one thing: it parses raw bytes from the UART serial bus. Once verified, it blindly fires an emit("telemetry.received", payload) event onto the memory bus and immediately returns to listening for the next radio packet.

Consumers (Subscribers)

The Database Writer

Decoupled from the radio, the database writer script runs in an infinite asyncio loop, pulling payloads off the memory bus at its own speed and writing them to SQLite. If the database locks up, the memory queue grows, but no live RF packets are ever dropped.

gateway/notifications.py (NotificationBus)
class NotificationBus:
    """In-memory asyncio bus attached to the running event loop."""
    def attach_loop(self, loop: asyncio.AbstractEventLoop) -> None:
        self._loop = loop

    def publish(self, event: dict) -> None:
        # Called on INSERT; fan out to every connected client queue.
        for queue in self._subscribers:
            self._loop.call_soon_threadsafe(queue.put_nowait, event)
gateway/routers/websockets.py
@router.websocket("/ws/live")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            # The client just holds the TCP socket open.
            # We push JSON from the NotificationBus directly to the
            # browser client (the vanilla-JS portal).
            data = await websocket.receive_text()
    except WebSocketDisconnect:
        manager.disconnect(websocket)
The Hard Problems

What Actually Made This Difficult.

A pipeline diagram never shows the fights. These are the problems that shaped this service: each one real, each with the fix that shipped. Two more (knowing an attacker's real address behind a proxy, and stopping password-guessing bots) get their full write-ups, code included, just below.

Field Incident

HTTP/1.1 Socket Starvation

The portal initially hung over field connections. Debugging in DevTools revealed the cause: a browser allows only six live connections to one server, and two always-open update streams were using all of them. Fixing it required lazy-loading the SSE streams (SSE: Server-Sent Events, those always-open update streams) to unblock the map fetches. Read the full journal →

Throughput

Surviving Telemetry Bursts

The problem: telemetry arrives asynchronously over UDP and serial at high volumes; a standard SQLite configuration would instantly lock and crash under that concurrent write pressure, and a slow SD-card write can physically block the processor from receiving the next radio packet. The fix: decouple everything. The radio receiver just fires an event onto an in-memory bus and returns to listening; heavy normalization is pushed to a background job so the sender gets an instant acknowledgement; and the database runs in Write-Ahead Logging mode so readers never block writers. If the database locks up, the memory queue grows; no live RF packets are dropped. See the storage step →

Zero Trust Security

Knowing the Attacker's Real Address.

When a gateway is deployed behind a TLS-terminating reverse proxy (like Cloudflare or an Nginx ingress), naive applications see the proxy's IP for every incoming request. This destroys rate-limiting, as a single attacker will cause the proxy itself to be banned, locking out the entire legitimate team.

Execution: OMEGA implements strict proxy-trust topology via trusted_proxy_ips. The Python backend extracts the leftmost X-Forwarded-For header only if the direct peer is a cryptographically trusted proxy. This ensures that a brute-force attacker is isolated and penalized by their true origin IP, preventing large-scale Denial of Service (DoS) cascades.

gateway/middleware.py
class ProxyTrustMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        client_ip = request.client.host
        
        # Only parse X-Forwarded-For if the direct connection is from a trusted proxy
        if client_ip in TRUSTED_PROXIES:
            x_forwarded = request.headers.get("X-Forwarded-For")
            if x_forwarded:
                # The true client is the leftmost IP in the chain
                real_ip = x_forwarded.split(",")[0].strip()
                request.state.real_ip = real_ip
        else:
            # Direct connection (no proxy), or untrusted proxy (spoofing attempt)
            request.state.real_ip = client_ip
            
        return await call_next(request)
Penalty Box

Dynamic IP Rate Limiting.

Marine gateways are often deployed on static public IPs with minimal perimeter defenses, making them prime targets for automated SSH and HTTP brute-force bots.

Execution: The authentication engine tracks failed login vectors in memory. After 5 sequential failures against a single username within a 10-minute sliding window, the source IP is dynamically parked in a cooldown penalty box. This halts dictionary attacks while allowing legitimate admins to use the new Settings panel to manually clear the blocklist and restore access.

gateway/auth.py
def record_failed_login(ip_address: str, username: str):
    # Retrieve existing failures from fast memory cache
    failures = cache.get(f"auth_fail:{ip_address}") or 0
    failures += 1
    
    # 5-Strike Sliding Window Penalty
    if failures >= 5:
        logger.warning(f"PENALTY BOX: Locking IP {ip_address} for 10 minutes.")
        cache.set(f"lockout:{ip_address}", True, expire=600)
        
        # Log immutable security event
        db_session.add(SecurityEvent(
            type="rate_limit_enforced",
            target_ip=ip_address,
            description="Exceeded 5 failed authentication attempts."
        ))
        db_session.commit()
    else:
        # Increment failure count with a 60-second sliding window
        cache.set(f"auth_fail:{ip_address}", failures, expire=60)
The Rest of the Service

Beyond the Pipeline.

The rest of the gateway, grouped: the open-standards surface it exposes to other software, the public ocean data it fuses in beside OMEGA's own hardware, the analysis that runs on top, day-to-day fleet operations, who is allowed to do what, and how the whole service is structured and deployed.

Semantic APIs

W3C Web of Things.

OMEGA describes every sensor in one common, open format: W3C Semantic Web of Things (WoT) Thing Descriptions. That gets around proprietary vendor lock-in, a major failure of modern marine technology; a YSI sonde cannot natively talk to a Teledyne acoustic modem.

Relevance: This broad abstraction layer exposes every single physical edge node as a standardized RESTful or CoAP entity (e.g., coap://gateway.local/things/buoy-02/properties/temperature). Downstream analytical applications or university partners query the semantic property and receive the normalized SI metric. The same call works against a $10,000 CTD and a $2 thermistor.

water-quality-node.td.json
{
  "@context": [
    "https://www.w3.org/2022/wot/td/v1.1"
  ],
  "id": "urn:OA:thing:site-a:buoy-02:water-quality-probe",
  "title": "Buoy 02 Water Quality Probe",
  "description": "Gateway-hosted Thing Description for a water quality probe reachable through the mesh.",
  "version": {
    "instance": "0.1.0"
  },
  "securityDefinitions": {
    "nosec_sc": {
      "scheme": "nosec"
    }
  },
  "security": "nosec_sc",
  "properties": {
    "temperature": {
      "title": "Water Temperature",
      "type": "number",
      "unit": "Cel",
      "readOnly": true,
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/properties/temperature",
          "contentType": "application/json",
          "op": [
            "readproperty"
          ]
        }
      ]
    },
    "salinity": {
      "type": "number",
      "unit": "psu",
      "readOnly": true,
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/properties/salinity",
          "contentType": "application/json",
          "op": [
            "readproperty"
          ]
        }
      ]
    },
    "dissolvedOxygen": {
      "type": "number",
      "unit": "mg/L",
      "readOnly": true,
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/properties/dissolvedOxygen",
          "contentType": "application/json",
          "op": [
            "readproperty"
          ]
        }
      ]
    },
    "batteryVoltage": {
      "type": "number",
      "unit": "V",
      "readOnly": true,
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/properties/batteryVoltage",
          "contentType": "application/json",
          "op": [
            "readproperty"
          ]
        }
      ]
    },
    "samplingIntervalS": {
      "type": "integer",
      "minimum": 10,
      "readOnly": false,
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/properties/samplingIntervalS",
          "contentType": "application/json",
          "op": [
            "readproperty",
            "writeproperty"
          ]
        }
      ]
    }
  },
  "actions": {
    "sampleNow": {
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/actions/sampleNow",
          "contentType": "application/json",
          "op": [
            "invokeaction"
          ]
        }
      ]
    }
  },
  "events": {
    "observation": {
      "data": {
        "type": "array",
        "description": "Observation pack encoded as SenML JSON."
      },
      "forms": [
        {
          "href": "coap://gateway.local/things/buoy-02-water-quality/events/observation",
          "contentType": "application/senml+json",
          "op": [
            "subscribeevent"
          ]
        }
      ]
    }
  }
}
Public Ingestion

NOAA NDBC & CO-OPS Public Loader.

OMEGA runs a Public Loader daemon alongside its own hardware. It scrapes NOAA National Data Buoy Center (NDBC) buoys, CO-OPS tide/met products, and Open-Meteo marine models.

Those diverse public sources are normalized into the exact same Observation Envelope schema used by OMEGA hardware, so the frontend renders public buoys interchangeably with private fleet assets.

Oceanographic Formats

ERDDAP & NetCDF Structures.

Marine research runs on context. A surface temperature reading from a remote sensor only means something once it is federated with regional satellite data. OMEGA integrates heavily with institutional ERDDAP (Environmental Research Division Data Access Program) servers.

Execution: The erddap.py ingestor runs as a background asyncio task. It queries large tabular datasets (like NOAA buoy arrays or the Copernicus Marine Service) using the ERDDAP REST API. Because returning full NetCDF arrays over HTTP is slow, OMEGA enforces spatial bounding-box constraints (Lat/Lon/Time) derived from its active edge nodes before making the HTTP GET request, only downloading the bytes relevant to the current fleet operation.

gateway/erddap.py
async def fetch_regional_sst(lat_min: float, lat_max: float, lon_min: float, lon_max: float):
    # Poll NOAA ERDDAP for Sea Surface Temperature within the edge node bounding box.
    base_url = "https://coastwatch.pfeg.noaa.gov/erddap/griddap/jplMURSST41.csv"
    
    # Construct strict spatial constraints to avoid downloading the entire ocean
    query = f"?analysed_sst[(last)][({lat_min}):({lat_max})][({lon_min}):({lon_max})]"
    
    async with httpx.AsyncClient() as client:
        response = await client.get(base_url + query, timeout=30.0)
        response.raise_for_status()
        
        return _parse_erddap_csv(response.text)
Climate Models

NASA EarthData & Copernicus.

The gateway integrates NASA EarthData CMR-STAC endpoints and the Copernicus Marine catalog. This allows OMEGA to query multi-petabyte federated cloud datasets, pulling specific climate variables (like Chlorophyll-a concentrations from Sentinel-3) to compare against real-time, local water-quality buoy data.

Satellite Physics

Global Map Fusion.

To measure global Sea Surface Temperature (SST), satellites use advanced radiometers to detect thermal infrared radiation emitted by the ocean's skin layer. To model ocean currents and wave heights, they use radar altimetry, bouncing precise microwave pulses off the ocean surface to measure minute differences in sea surface height.

Fetching this volume of real-time planetary data requires interacting with complex, rate-limited APIs from Copernicus, NASA, and NOAA. The OMEGA Gateway acts as a caching proxy for these external endpoints.

Operational Use: By storing recent satellite tiles and JSON payloads in local Redis or SQLite memory caches, the gateway prevents the Mission Portal from exhausting strict global API rate limits when multiple operators are rapidly zooming and panning across the map interface.

Subsurface Profiles

Argo Float Economics.

Surface sensors only tell half the story. The ocean is composed of distinct thermal and halocline layers. The argo_calibration.py module actively queries the global Argo network, a decentralized fleet of 4,000 autonomous profiling floats that constantly dive to 2,000 meters and resurface.

Economic Metric Argo Profiling Float OMEGA Surface Node
Hardware Cost $20,000 (Titanium/Hydraulics) $200 (ESP32/PVC)
Telemetry Cost $200 / 10 days (Iridium Sat) $0 (Free LoRa RF)
Transmission Limit 1 burst every 10 days Continuous (Solar)
Calibration Strategy Primary Ground Truth Source Cross-references public Argo float data

Execution: OMEGA pulls live, open-source Argo CTD (Conductivity, Temperature, Depth) casts via ERDDAP instead of building its own $20k floats. The gateway cross-references these deep-ocean profiles against the cheap $200 surface buoys as an independent calibration reference.

Hydrodynamics

HFRNet Surface Currents.

Attempting to navigate a small, solar-powered edge node directly against a 4-knot Gulf Stream current will drain its lithium battery instantly, leading to a dead vessel adrift at sea. The hfrnet.py module solves this by ingesting the U.S. High-Frequency Radar Network (HFRNet) data via THREDDS servers.

How it works: This provides a real-time, high-resolution vector field of ocean surface currents. The wayfinding.py module consumes this large vector matrix and executes its A* pathfinding algorithm. The resulting mission plan actively "surfs" the currents, intentionally deviating from a straight line to hitch a ride on localized eddies, extending the sensor's operational range.

Emergency Egress

National Hurricane Center Tracking.

A Category 5 hurricane will physically destroy any edge node or floating relay in its path. The nhc.py daemon acts as an automated emergency egress trigger by constantly polling the National Hurricane Center (NHC) for active cyclone probability cones.

How it works: The gateway mathematically checks the intersections between the fleet's deployed coordinates and the NHC's 48-hour probability cone. If a collision is imminent, the Mission Portal immediately throws a severe weather alarm and automatically commands all edge nodes to execute an emergency Return-To-Base (RTB) protocol or dive to a safe sub-surface depth to ride out the kinetic energy of the storm.

Ecological Monitoring

NOAA Coral Reef Watch.

Coral bleaching events happen rapidly and often in unmonitored remote atolls. By integrating the coral_reef_watch.py adapter, the OMEGA gateway ingests NOAA Coral Reef Watch 5km satellite virtual stations to monitor Degree Heating Weeks (DHW) across global reefs.

Operational Use: Coral Reef Watch is presented as a data layer: operators can see marine-heatwave stress (e.g. Alert Level 2) overlaid on the map next to the fleet. There is no automatic coral-to-waypoint redirect; the gateway does not break a node out of its mission on a bleaching alert. Any ASV waypoint mission toward an affected reef is operator-review-gated, so a human decides whether to redeploy a node to capture acoustic bathymetry and dissolved-oxygen samples during the event.

Biodiversity

OBIS Marine Species Tracking.

The Ocean Biodiversity Information System (obis.py) integration allows the gateway to pull historical and real-time acoustic tag detections for endangered marine life. This data is critical for minimizing the ecological impact of robotic deployments.

Execution: When the OMEGA fleet operates in known biological migration corridors (e.g., Great White Shark breeding grounds or Right Whale transit zones), the gateway automatically establishes an exclusion zone or lowers the sensor polling rate of the edge node to reduce acoustic cavitation signatures, minimizing ecological disturbance to sensitive species.

Fisheries & Security

Global Fishing Watch (GFW).

OMEGA integrates directly with the Global Fishing Watch 4Wings API. It pulls real-time heatmap MVT overlays for apparent fishing effort, AIS vessel presence, and Synthetic Aperture Radar (SAR) detections of "dark targets" (vessels not transmitting AIS).

The gateway also pulls vessel risk and IUU (Illegal, Unreported, and Unregulated) insights, matching detected AIS tracks against global registries to flag vessels fishing within no-take Marine Protected Areas (MPAs).

gateway/gfw_api.py
async def check_iuu_risk(mmsi: str) -> float:
    # Query the Global Fishing Watch 4Wings API for vessel risk
    headers = {"Authorization": f"Bearer {GFW_TOKEN}"}
    
    async with httpx.AsyncClient() as client:
        # Fetch vessel profile using its Maritime Mobile Service Identity (MMSI)
        res = await client.get(f"https://gateway.api.globalfishingwatch.org/v2/vessels/search?query=mmsi:{mmsi}", headers=headers)
        res.raise_for_status()
        
        data = res.json()
        if not data["entries"]: return 0.0
        
        # Calculate IUU probability based on dark-target SAR anomalies
        vessel = data["entries"][0]
        risk_score = vessel.get("implied_risk_score", 0.0)
        
        return risk_score
Maritime Traffic

Live Commercial AIS & MarineCadastre.

For live tactical awareness, the gateway ingests commercial AIS streams (via AISStream), tracking thousands of live vessels and superimposing them onto the OMEGA Map Portal in real-time.

For historical context, the portal registers U.S. MarineCadastre transit-count overlays. These are cached ArcGIS tiles displaying annual vessel-density heatmaps (2019-2025), allowing operators to plan stationary deployment locations that actively avoid historical high-traffic shipping lanes.

Maritime Awareness

Live AIS Data Layers & Active Guard.

Navigating a small, solar-powered buoy near a busy commercial shipping lane is risky. The gateway ingests live AIS vessel positions and exposes them as a data layer on the portal, alongside the historical MarineCadastre transit-density overlays, so operators can see commercial traffic around a deployment.

What it actually does: The gateway's event-driven Active Guard geofence watches a tracked node's own reported position. When a node breaches an operator-defined zone, Active Guard fires on ingest and auto-queues a response COMMAND (with a cooldown to prevent repeated firing). There is no AIS collision-avoidance logic here (no CPA/TCPA closest-point-of-approach computation against vessel tracks), and AIS is presented as situational-awareness data, not an automated maneuver trigger.

Science Endpoints

Calibration Drift & Spectral Coherence.

Beyond per-sample QC, the gateway exposes science endpoints that compare a station against external references and against other stations.

/v1/science/calibration-drift

Calibration-Drift Fit

Pairs a sensor with a co-located reference (nearest-in-time), then least-squares-fits the residual drift over time. It returns the offset, the drift per day, an r² for the fit, and the linear correction to apply; so a slowly biasing probe can be caught and corrected rather than silently trusted. A fitted correction can then be persisted against the station and applied to incoming readings, with an audit trail recording each correction and when it took effect, so calibration changes stay reviewable instead of silently rewriting the data.

/v1/science/coherence

Spectral Coherence

Computes Welch magnitude-squared coherence and phase between two stations: at which periods they co-vary, how strongly, and which one leads. A 95% significance floor separates real shared forcing (e.g. the same tide or storm) from independent local signals, so spurious correlations are not over-read.

Data Science Workflows

The Honu AI Copilot.

The Python gateway includes Honu, an in-portal AI copilot that runs fully offline on a local model (Ollama) or falls back to the cloud (Anthropic). Honu exists because the Mission Portal has too many nested menus for an operator to navigate during a critical mission event. It holds no built-in knowledge; every fact comes from a tool call. The module intercepts natural language queries from the operator and dynamically routes them across ~100 internal tools.

Execution: Because the LLM holds no built-in knowledge of the specific marine deployment, the system uses a strict foundational prompt. It acts as an analytical and navigational bridge, using live tool calls to query the SQLite database, filter nodes by geographic bounds, and summarize observation arrays. The operator asks Honu why Buoy 4 went offline and the copilot executes the diagnostic trace, instead of clicking through 10 buttons.

copilot.py
SYSTEM_PROMPT = """You are Honu, the OMEGA Intelligence Engine — an expert research assistant, data analyst, and interface navigator embedded in the OMEGA open-source marine research portal.
1. READ-ONLY OPERATIONS: You are strictly an analytical and navigational tool.
   - You must NEVER send outbound telemetry or execute hardware controls.
2. DATA PURITY: You hold ZERO built-in knowledge of this deployment.
   - Every fact must come from a tool call against the gateway's live API.
3. AMNESIA PREVENTION: You cannot "see" the user's screen.
   - Before each message, you receive a [PORTAL CONTEXT] block showing the user's current view."""
Autonomous Behavior

Honu's Anomaly Patrol.

The real autonomous behavior on the gateway is a daily scheduled task in gateway/scheduler.py that runs Honu's anomaly patrol. It buddy-checks each station against its spatial neighbours across the core metrics, ranks the outliers, and emits one proactive briefing notification naming the specific stations a human should check.

Honest scope: On a clean sweep it stays silent; it does not generate noise when nothing is wrong, and it does not take any control action. It surfaces a single ranked briefing; the operator decides what to do next.

Asynchronous Loop

The Gateway Scheduler.

The gateway/scheduler.py module manages a strict Python `asyncio` event loop. This cron-like engine dictates when the gateway should pull satellite ephemeris data, when it should poll NOAA for weather updates, and when it should execute the QARTOD compliance engine across the large historical SQLite database.

System Watchdogs

Automated Fleet Watches.

The gateway/watches.py module is an active monitoring service. It constantly evaluates the timestamp of the last received ping from every edge node in the mesh. If a buoy goes completely silent and misses its Delay Tolerant Network heartbeat window, the Watchdog automatically generates a critical "Node Offline" alarm on the Notification Bus.

Resilient Downlink

Coverage-Aware Outbox Leases (CALM).

In a heterogeneous federation with hundreds of overlapping gateways, determining which gateway should transmit a downlink command to a distant buoy is incredibly difficult. If all gateways transmit simultaneously, the RF collisions will destroy the packet. If only a single master gateway transmits, you introduce a total single point of failure.

Execution: OMEGA solves this via CALM (Coverage-Aware Outbox Leases). Every time a gateway ingests an uplink frame, the DB logs its gateway_id and the signal strength (RSSI/SNR). When an operator issues a downlink command, the backend calculates a routing lease. It queries the gateway_sightings provenance table, identifies the single gateway that "hears" the target node the best, and grants that specific gateway a temporary, exclusive lease to transmit the command. If the transmission isn't acknowledged, the lease expires and falls back to the next-best gateway automatically.

Authentication Engine

Role-Based Access Control (RBAC).

OMEGA's gateway is an open, internet-exposed federated service that anyone in the community can stand up and reach, so it needs real access control rather than a single shared password. The gateway features a multi-user authentication engine with Role-Based Access Control (RBAC) and three roles: admin users have global mutating privileges, operator users can execute waypoint missions, and viewer users are restricted to read-only telemetry analysis.

Sessions: When a user logs in, the FastAPI backend issues an opaque server-side session token (32 bytes of random data, stored and revocable server-side). It is delivered in an HttpOnly + SameSite=Lax cookie with a 14-day TTL and an 8-hour idle timeout, so sessions can be invalidated centrally rather than relying on a self-contained token.

Execution: Every mutating API endpoint (e.g. /v1/control/commands) is guarded by FastAPI dependency injection (_require_operator). If an unauthorized researcher attempts to wipe the database, the API rejects the request with an HTTP 403, preventing accidental fleet commands.

Server-side session record
{
  "username": "jcapone",
  "role": "admin",
  "token": "<32-byte random, hashed at rest>",
  "created_at": "2026-06-21T08:00:00Z",
  "expires_at": "2026-07-05T08:00:00Z",
  "idle_timeout_s": 28800,
  "revoked": false
}
gateway/auth_sessions.py
async def _require_operator(
    session_token: str = Depends(cookie_scheme),
    db: Session = Depends(get_db)
):
    session = resolve_session(db, session_token)
    role = session.role

    # Reject unauthorized mutating operations
    if role not in ["operator", "admin"]:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient RBAC clearance for fleet mutation."
        )
    return session
Total Accountability

Immutable Audit Trails.

When a stationary node executes a dangerous maneuver, "who sent the command?" is the most important question. The OMEGA backend now logs a completely immutable, chronological audit trail for every single mutating admin action.

Execution: If an administrator resets a user's password or clears a rate-limited IP, the system generates a system-kind notification with a unique source_id. Operators can use the Honu AI Copilot to query this database in natural language (e.g., "Who cleared the rate limit yesterday?"), providing complete post-incident forensic capabilities.

Architectural Theory

Clean Architecture Principles.

The OMEGA gateway strictly enforces a 3-tier architectural separation of concerns. Each tier has exactly one job, and that is what keeps a Python backend this size maintainable.

Layer 1

The Routers

Routers handle exactly one thing: HTTP mechanics. They parse the JSON payload, check the API tokens, and immediately pass the data down. They contain ZERO business logic.

Layer 2

The Services

The pure business logic layer. Services calculate bounding boxes, execute algorithms, and transform arrays. They know nothing about HTTP requests or databases.

Layer 3

The Repositories

The only place in the codebase where SQL exists. If we ever swap SQLite for PostgreSQL, we only rewrite the Repository layer. The Routers and Services remain completely untouched.

Operational Resilience

Disaster Recovery Snapshots.

Disaster recovery is config-gated. When enabled, a daily task takes integrity-checked online snapshots of the live SQLite database and prunes them to a retention window, so a corrupt or partially-written backup is never kept.

Execution: The restore path is deliberately conservative; it refuses to overwrite a good database with a snapshot that fails its integrity check, so a bad backup cannot destroy a working deployment during recovery.

Deployment

One-Command Containerized Deploy.

A Dockerfile, a docker-compose definition, and scripts/omega-up.sh stand up a gateway on any Docker host (a cloud VM, a NAS, or a Raspberry Pi) with one command.

omega up

Single Command

Running omega up builds and launches the gateway container, waits for the health check to pass, and prints the portal URL. The same script works whether the host is a cloud VM, a NAS, or a Pi on a shelf.

Health-Checked

Compose Stack

The docker-compose stack pins the service, persists the SQLite volume, and gates startup on a health check, so a community member without a Python toolchain can bring up a working node.