Skip to content

RingServerSender Job

The RingServerSender thread forwards live seismic data to an external EarthScope ringserver using the DataLink protocol (TCP port 16000). Once data arrives at the ringserver it is immediately available to any SeedLink client on the network.


Running an rpi-seism station in isolation records data locally. Connecting to a ringserver unlocks:

SeedLink Distribution

Any SeedLink client (SeisComP, ObsPy, SWARM) can subscribe and receive your data with sub-second latency.

Amateur Networks Integration

Amateur networks can ingest your stream directly into their processing pipelines without manual file transfers.

Archive Redundancy

The ringserver maintains a configurable ring buffer (typically hours to days), acting as a secondary off-site archive.

Standard Formats

Data is forwarded as FDSN-compliant MiniSEED records — the same format written to the local SDS archive.


Reader thread
data_queue ──► RingServerSender
buffer samples
per channel
build MiniSEED
record (ObsPy)
DataLink TCP
(port 16000)
ringserver process
SeedLink port
(port 18000)
SeisComP / ObsPy / SWARM
jAmaseis …
  • Input: shared data_queue — identical raw packet dict to the one consumed by MSeedWriter.
  • Transport: DataLink over TCP (EarthScope open protocol).
  • Output: MiniSEED records injected into the ringserver ring buffer.

DataLink is an EarthScope/IRIS protocol designed for real-time seismic data exchange. The daemon acts as a DataLink producer (source); the ringserver acts as a DataLink server (sink). Once records are stored in the ring buffer the ringserver makes them available to SeedLink consumers.

Key characteristics:

PropertyValue
TransportTCP
Default port16000
Record formatMiniSEED (any record length)
Connection modelPersistent TCP; reconnect on drop
Flow controlServer-side acknowledgement per record

The RingServerSender does not write one MiniSEED record per raw packet — that would produce ~100 tiny records per second per channel. Instead it accumulates samples in a per-channel buffer and flushes at a configurable interval.

  1. Receive — raw packet dict {"timestamp": float, "measurements": [...]} dequeued from data_queue.
  2. Demux — each channel’s int32 value is appended to the corresponding channel buffer along with its timestamp.
  3. Interval check — when the elapsed time since the last flush exceeds flush_interval (configurable, default a few seconds), flush all channels.
  4. MiniSEED build — for each channel, construct an ObsPy Trace with correct FDSN metadata (network, station, location, channel, sampling rate, start time) and serialise to MiniSEED bytes via st.write(buf, format="MSEED").
  5. DataLink write — send each record to the ringserver over the persistent TCP connection using the DataLink WRITE command. The ringserver acknowledges each record.
  6. Reset — clear the channel buffer and record the new start timestamp.

Records sent to the ringserver follow the same conventions as the local SDS archive:

MetadataSource
Network codesettings.station.network
Station codesettings.station.station
Location codesettings.station.location_code
Channel codeChannel name from settings (e.g. EHZ)
Sampling ratesettings.mcu.sampling_rate
Start timeUnix timestamp of first sample in buffer
Data typeint32 raw ADC counts

Data is forwarded as raw counts, instrument response removal happens downstream in ObsPy or SeisComP, using the station.xml file that the daemon generates on first run.


RingServerSender settings live under jobs_settings in config.yml:

config.yml (excerpt)
jobs_settings:
ringserver:
host: "127.0.0.1" # ringserver hostname or IP
port: 16000 # DataLink TCP port
flush_interval: 5.0 # seconds between MiniSEED flushes
enabled: true
FieldDefaultDescription
host127.0.0.1Hostname or IP of the ringserver
port16000DataLink TCP port
flush_interval5.0Seconds between per-channel MiniSEED flushes
enabledtrueSet to false to disable without removing the thread

The sender maintains a single persistent TCP connection. If the connection drops (network interruption, ringserver restart), the thread:

  1. Logs a warning and closes the socket.
  2. Enters an exponential back-off retry loop (initial 2 s, maximum 60 s).
  3. Continues buffering incoming samples during the outage — up to a configurable maximum to bound memory usage.
  4. Resumes transmission once the connection is re-established; samples buffered during the outage are sent first.

Data buffered during a disconnect is delivered in order once connectivity is restored. However, if the outage is longer than the in-memory buffer window, the oldest samples are dropped to prevent unbounded memory growth.


RingServerSender and MSeedWriter operate independently on parallel queues. A disconnect from the ringserver does not affect local archiving, and vice versa.

ConcernMSeedWriterRingServerSender
Storage targetLocal SDS on SD cardRemote ringserver ring buffer
Write triggerPeriodic (30 min) + earthquake flushPeriodic (configurable, seconds)
Data unitsRaw countsRaw counts
LatencyMinutes to hoursSeconds
Fault toleranceLocal disk failure onlyNetwork outages, buffered

Once data is flowing into the ringserver, any SeedLink client can connect to port 18000 (default) to receive the live stream:

from obspy.clients.seedlink.easyseedlink import create_client
def handle_data(trace):
print(trace)
client = create_client("my-ringserver.local", on_data=handle_data)
client.select_stream("XX", "RPI3", "EH?")
client.run()

For self-hosted testing, the EarthScope ringserver is straightforward to deploy:

Terminal window
# Build from source
git clone https://github.com/EarthScope/ringserver.git
cd ringserver && make
# Run with a 1 GB ring buffer
./ringserver -mseedwrite /sds/%Y/%n/%s/%c.D/... \
-DataLinkPort 16000 \
-SeedLinkPort 18000 \
ringserver.ini

The -mseedwrite flag mirrors arriving MiniSEED to a local SDS archive on the server, giving a second independent copy of your data at zero extra cost.