◢ SALISH SIGINT
Node 04 · Fusion Layer

Citizen SIGINT for the Salish Sea
— four cheap nodes, one bus.

The previous three pages each give you a sensor. This page is the part that makes them useful: a small MQTT broker, a correlation engine, and a dashboard that fuses your own SDR, LoRa, and iPhone feeds with public AIS, ADS-B, OrcaSound hydrophone streams, NOAA buoys, and intentionally-public marine RTSP cameras. The result is an Elliott Bay panopticon for whale watchers — built from open feeds, on a single $5 VPS, with a serious legal/ethical floor.

The mesh, drawn

                              ╔══════════════════════════════════════╗
   ┌──────────────────────────╣      MQTT bus (mosquitto, TLS)       ╠────────────┐
   │                          ╚══════════════════════════════════════╝            │
   │                                                                              │
   │  topics:                                                                     │
   │    sdr/<node>/ais/raw            sdr/<node>/marine/wx                        │
   │    buoy/<id>/event               hydrophone/<id>/detection                   │
   │    feed/orcasound/<site>         feed/ais/marinetraffic                      │
   │    feed/cam/<site>/keyframe      alert/correlated                            │
   │                                                                              │
   ▼                                                                              │
 ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
 │ SigDigger│  │ LoRa     │  │ iPhone   │  │  Public  │  │ Public   │  │ Public   │
 │ + Pi5    │  │ buoy ×N  │  │ hydro    │  │  AIS     │  │ OrcaSound│  │ RTSP cams│
 │ AIS/WX   │  │ events   │  │ stream + │  │  feed    │  │ feeds    │  │ (curated │
 │ raw      │  │ (32B)    │  │ CoreML   │  │ (NOAA/   │  │ (open    │  │ public-  │
 │          │  │          │  │ events   │  │ MT API)  │  │ stream)  │  │ list)    │
 └──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘
       │             │             │             │             │             │
       └─────────────┴─────────────┴──────┬──────┴─────────────┴─────────────┘
                                          ▼
                              ┌────────────────────────┐
                              │  Correlation engine    │
                              │  (Node-RED / Python)   │
                              │   rules → alerts       │
                              └─────────────┬──────────┘
                                            ▼
                              ┌────────────────────────┐
                              │  Public dashboard      │
                              │  Leaflet map + HLS +   │
                              │  spectrogram strip     │
                              └────────────────────────┘

Sensor inventory

SourceWhat it givesOwnerTopic
SigDigger / RTL-SDR at Pier 70AIS, marine VHF, NOAA WX, Coast Guard P25Yousdr/pier70/*
LoRa buoys (×N)32-byte tonal-call events with SNR & CNN classYoubuoy/<id>/event
iPhone hydrophoneLive HLS audio + CoreML detection metadataYouhydrophone/pier70/*
OrcaSound public feedsLive audio from 4 Salish Sea sites — CC-BYOrcasoundfeed/orcasound/*
NOAA AIS NDBC APIVessel position / class / speed; sea-stateNOAA — publicfeed/ais/noaa
MarineTraffic API (free tier)Cross-validate against your own AISMarineTrafficfeed/ais/mt
OpenSky Network ADS-BAircraft over the bay (overflight noise)OpenSkyfeed/adsb/opensky
Public RTSP marine camsVisual confirmation; vessel IDVarious — see ethicsfeed/cam/<site>
NOAA NDBC buoy APIWind, wave, sea temp at 46087, 46088, etc.NOAA — publicfeed/buoy/ndbc

Shodan, but ethically — what role it actually plays

Read this twice

Shodan indexes any device that answers a probe on the open Internet. Some of those devices are intentionally public (a marina's "view of our slip" RTSP, a port authority's webcam, a research station's data feed). Some are misconfigured consumer cameras whose owners did not consent. Hitting the second class is unauthorized access. CFAA in the US, Computer Misuse Act in the UK — same answer either way.

This project uses Shodan in exactly one role: discovery of feeds whose operators have published or advertised them as public, with manual review and a written-down "yes, this is public" check before they go in the curated cam list. It is not a tool for finding unsecured cameras. If a feed lacks a clear public banner, social-media post, or About page, it doesn't go on the list.

The discovery query that is reasonable

# Find INTENTIONALLY-public marine/port webcams to add to the curated list.
# Then go look at each result, find their About page, and only include those
# with a clear "this is public" statement.
shodan search 'product:"Sensoray Camera Server" port:80 has_banner:true' --limit 20
shodan search 'http.title:"Live Marina Cam" country:US' --limit 20
shodan search 'org:"Port of Seattle" product:webcam' --limit 5

Better data sources, no Shodan needed

For this project, that's the camera list. Shodan doesn't add anything you can't get through these channels.

Correlation rules — turning sensors into alerts

Correlation is the entire point. Each rule is a filter on the MQTT bus that emits to alert/correlated when the conjunction holds.

Rule 1 — Vessel-strike risk

# Pseudo: Node-RED / Python correlator
if orca_call_within(buoy.id, last_60s) and \
   ais_vessel_within_km(buoy.lat, buoy.lon, 1.5) and \
   ais_vessel.speed_kts > 7.0:
    emit_alert({
        "type": "vessel-strike-risk",
        "buoy": buoy.id,
        "vessel": ais_vessel.mmsi,
        "distance_km": ais_vessel.dist,
        "severity": "high",
    })

Rule 2 — Pod direction-of-travel estimate

Two LoRa buoys + one iPhone hydrophone with synced clocks → time-difference-of-arrival on a tonal call gives you a hyperbolic intersection. Not a position, but a direction-of-travel sketch you can overlay on the map.

Rule 3 — Unknown emitter

SigDigger sees an AIS/Marine-VHF burst whose MMSI is not in the AIS catalog → flag for review. Useful for catching radio tests, foreign vessels, or fishery patrols.

Rule 4 — Quiet-bay window

OrcaSound + your buoys agree there's no orca activity AND AIS shows no vessel within 5 km AND the wind is < 5 kt → emit "good listening" — drives a "go to the dock now" push notification.

The bus — minimal mosquitto + TLS

# /etc/mosquitto/conf.d/salish.conf
listener 8883
cafile /etc/letsencrypt/live/sigint.example/chain.pem
certfile /etc/letsencrypt/live/sigint.example/cert.pem
keyfile  /etc/letsencrypt/live/sigint.example/privkey.pem

allow_anonymous false
password_file /etc/mosquitto/passwd

acl_file /etc/mosquitto/aclfile
# aclfile excerpt:
#   user buoy-001
#     topic write buoy/001/event
#   user dashboard
#     topic read #

The dashboard — Leaflet, HLS, spectrogram

One static page on this site (or a Netlify build) that subscribes to the MQTT bus over WebSockets and renders:

It runs in a tab. It does not need a backend beyond the broker.

The legal/ethical floor — non-negotiable

Ground rules

  1. SRKWs are endangered. If a public alert from this project ends up summoning a crowd of boats to a sighting, that's harm. Alerts are time-delayed and location-fuzzed to a 1-km grid for non-trusted subscribers. Only researchers and partners get exact coords.
  2. No active acoustic. Passive listening only. No pingers, no ATOC, no nothing.
  3. Public feeds only. If a camera's source isn't publicly advertised by its operator, it is not on the list. Period. Shodan is a discovery aid, not a license.
  4. Attribution. Every external feed gets credit on the dashboard. OrcaSound is CC-BY; treat it accordingly.
  5. Open data out. Your own sensor data is published under CC-BY-SA. No takesy-backsies.
  6. Coordinate with the pros. Talk to Center for Whale Research and Orca Network. They are not threatened by citizen instrumentation; they are tired of bad citizen instrumentation. Don't be that.

Build order

  1. Stand up the broker. $5 VPS, mosquitto + TLS + WebSockets. Test with mosquitto_pub.
  2. Wire the SDR. Pi 5 + RTL-SDR Blog v4 → SoapySDRServer → SigDigger remote. Get AIS decoding into sdr/pier70/ais/raw.
  3. Pull the public feeds. Tiny Python service (feeds.py) that polls NOAA, OrcaSound, OpenSky, MarineTraffic and republishes to MQTT.
  4. iPhone hydrophone. Larix → MediaMTX → HLS. Add CoreML detection metadata to hydrophone/pier70/detection.
  5. First buoy. Heltec V3 + DIY piezo. Get heartbeat + threshold detector packets flowing.
  6. Correlation rules. Node-RED first (visual, fast iteration), Python later.
  7. Dashboard. Static page, Leaflet + mqtt.js + Web Audio. Ship.
  8. Then more buoys for direction-of-travel triangulation.

Estimated cost (one operator, 1 buoy + 1 SDR + 1 phone)

Hardware
~$272 buoy + $40 SDR/Pi adders + ~$385 iPhone rig = $697
Monthly
$5 VPS + $15 cellular SIM = $20/mo
Time to first packet
2 weekends if you're patient with antennas

What this is, and what it isn't

It is

  • A real, working citizen sensing rig you can build
  • Open, attributable, locally-hosted
  • Useful for personal whale-watching, port-watching, vessel-noise journaling
  • A teaching scaffold for SDR / IoT / fusion engineering

It is not

  • Calibrated marine-mammal science — that needs IRB-equivalent process
  • An OSINT toolkit for surveilling people
  • A replacement for licensed Coast Guard / NOAA infrastructure
  • An excuse to deploy gear without permission

Sibling nodes

Node 01 · Spectrum ← SigDigger SDR Console Node 02 · Telemetry ← LoRa Whale Buoy Node 03 · Acoustic ← iPhone Hydrophone
Salish SIGINT · Node 04 / 04 · Capstone Built by humans, for whales · CC-BY-SA