Skip to content

NATS Clients

The Navproc API consists of a NATS messaging service. It contains both streaming messages as well as a key-value store (called a bucket). You can either subscribe to a stream of messaging to get all messages in real time or query for the lastest values from the key-value store.

Subscribing to Message Streams

One option for getting data from the ships is to subscribe to a NATS message stream. You just need to know the message subject you are interested in receiving and subscribe. This is not the complete list of subjects available on each ship, but it is a good start.

  1. Rachel Carson
    1. navproc.NAV4D_UDPIN
    2. navproc.NAV_4D_MSG
    3. navproc.NMEA_GPS_TCPIN
    4. navproc.NMEA_GPS_MSG
    5. navproc.SEABIRD_CTD_SERIN
    6. navproc.SEABIRD_CTD_MSG
    7. navproc.SEABIRD_CTD_STAT
    8. navproc.SHIP_GYRO_TCPIN
    9. navproc.SHIP_GYRO_MSG
  2. David Packard
    1. navproc.PT_CONTROL_LAPBOX_4K
    2. navproc.LAPBOX_4K_MSG
    3. navproc.CAMERA_4K_MSG
    4. navproc.NAV4D_UDPIN
    5. navproc.NAV_4D_MSG
    6. navproc.NMEA_GPS_TCPIN
    7. navproc.NMEA_GPS_MSG
    8. navproc.SEABIRD_CTD_SERIN
    9. navproc.SEABIRD_CTD_MSG
    10. navproc.SEABIRD_CTD_STAT
    11. navproc.SHIP_GYRO_TCPIN
    12. navproc.SHIP_GYRO_MSG
    13. navproc.ROV_UHS_MSG

Python Message Client

Below is an example of a Python client that gets a list of all the available subjects from the messaging service and then subscribes to one particular stream. Before using this client you will need to install the nats-py library using pip install nats-py

import asyncio
from nats.aio.client import Client as NATS

async def main():
    nc = NATS()
    await nc.connect("nats://coredata-dpkd.dp.mbari.org:4222")

    print("Subscribing to navproc.NMEA_GPS_MSG")

    async def message_handler(msg):
        subj = msg.subject
        data = msg.data.decode()
        print(f"Received a message on '{subj}': {data}")

    await nc.subscribe("navproc.NMEA_GPS_MSG", cb=message_handler)

    print("Listening ... press Ctrl+C to exit")
    try:
        while True:
            await asyncio.sleep(1)
    except KeyboardInterrupt:
        await nc.close()

if __name__ == "__main__":
    asyncio.run(main())

Which will print out statements like the following:

Received a message on 'navproc.NMEA_GPS_MSG': {"bool_list":[{"key":"gga_diff_mode","value":1},{"key":"gll_data_valid","value":0}],"integer_list":[{"key":"gga_quality","value":2},{"key":"gga_nsats","value":8}],"lcm_channel":"NMEA_GPS_MSG","message_type":"navproc/msg_t","num_bools":2,"num_integers":2,"num_reals":7,"num_strings":3,"pub_id":"navproc-dpkd-spare:nmea_gps(3885)","pub_sequence":3750240,"pub_timestamp":1752703757.8218985,"real_list":[{"key":"latitude","value":36.48820726666667},{"key":"longitude","value":-122.99442368333334},{"key":"gga_hdop","value":1.2},{"key":"gga_fix_age_seconds","value":0.24760150909423828},{"key":"gll_fix_age_seconds","value":1752703757.821892},{"key":"zda_utc_seconds","value":1752703757.0},{"key":"zda_fix_age_seconds","value":0.33203125}],"string_list":[{"key":"sentence","value":"$GPGST,220917.44,1.46,0.570,0.453,32,0.540,0.488,1.334*44\r\n"},{"key":"fix_time","value":"22:09:17"},{"key":"zda_date_time","value":"2025-07-16T22:09:17Z"}]}

Note that the server address for the Carson is coredata-rcsn.rc.mbari.org and for the Packard it's coredata-dpkd.dp.mbari.org

Buckets (key-value)

If, instead, you want to pull that latest value for a specific item, you can use the key-value pair store that NATS supports.

Python Key-Value Client

Here is an example Python script to pull the ship's latitude every 5 seconds.

# bucket.py
import asyncio
from nats.aio.client import Client as NATS

async def main():
    nc = NATS()
    await nc.connect("nats://coredata-dpkd.dp.mbari.org:4222")

    js = nc.jetstream()

    bucket_name = 'dpkd'
    kv = await js.key_value(bucket_name)

    # List all keys
    keys = await kv.keys()
    if not keys:
        print(f"No keys in bucket '{bucket_name}'")
        return
    print(f"Keys in bucket '{bucket_name}': {keys}")

    key = 'SHIP.GPS.LAT'
    print(f"Watching key '{key}' in bucket '{bucket_name}'...")

    while True:
        try:
            entry = await kv.get(key)
            print(f"[{key}] = {entry.value.decode()}")
        except Exception as e:
            print(f"Failed to get key: {e}")
        await asyncio.sleep(5)

if __name__ == "__main__":
    asyncio.run(main())

Which will print out something like this:

Keys in bucket 'dpkd': ['NAV4D.GPS.RAW', 'ROV.GPS.DIFFERENTIAL', 'ROV.GPS.GLL.DATA_VALID', 'ROV.GPS.QUALITY', 'ROV.GPS.NSATS', 'ROV.POSITION.LAT', 'ROV.POSITION.LON', 'ROV.GPS.HDOP', 'ROV.GPS.GGA.FIX_AGE', 'ROV.GPS.GLL.FIX_AGE', 'ROV.GPS.TIME', 'ROV.GPS.ZDA.FIX_AGE', 'CAMERA.4K.LEAK', 'CAMERA.4K.ZOOM', 'CAMERA.4K.FOCUS', 'CAMERA.4K.IRIS', 'CAMERA.4K.TEMP', 'CAMERA.4K.HUMIDITY', 'CAMERA.4K.PRESSURE', 'CAMERA.4K.SERIAL_PORT_NAME', 'LAPBOX.4K.TILT_SWAP_BTN_VAL', 'LAPBOX.4K.TILT_SWAP_ENABLED', 'LAPBOX.4K.AUX_CAM_BTN_VAL', 'LAPBOX.4K.MAIN_CAM_BTN_VAL', 'LAPBOX.4K.PORT_LIGHT_BTN_VAL', 'LAPBOX.4K.STBD_LIGHT_BTN_VAL', 'LAPBOX.4K.TILT_SWAP_BTN_CNT', 'LAPBOX.4K.AUX_CAM_BTN_CNT', 'LAPBOX.4K.MAIN_CAM_BTN_CNT', 'LAPBOX.4K.PORT_LIGHT_BTN_CNT', 'LAPBOX.4K.STBD_LIGHT_BTN_CNT', 'LAPBOX.4K.PAN_RAW', 'LAPBOX.4K.TILT_RAW', 'LAPBOX.4K.PAN_CMD', 'LAPBOX.4K.TILT_CMD', 'LAPBOX.4K.SERIAL_PORT_NAME', 'BDFSERVER.HEADER', 'BDFSERVER.LOG_LINE', 'ROVCTDLOGR.HEADER', 'ROVCTDLOGR.LOG_LINE', 'ROV.CTD.RECEIVING_DATA', 'VIDEOLOGR.HEADER', 'VIDEOLOGR.LOG_LINE', 'M3RSLOGR.HEADER', 'M3RSLOGR.LOG_LINE', 'DATAPROBELOGR.HEADER', 'DATAPROBELOGR.LOG_LINE', 'NAV4DLOGR.HEADER', 'NAV4DLOGR.LOG_LINE', 'SHIPNAVLOGR.HEADER', 'SHIPNAVLOGR.LOG_LINE', 'SHIP.GPS.RAW', 'SHIP.GPS.DIFFERENTIAL', 'SHIP.GPS.GLL.DATA_VALID', 'SHIP.GPS.QUALITY', 'SHIP.GPS.NSATS', 'SHIP.GPS.LAT', 'SHIP.GPS.LON', 'SHIP.GPS.HDOP', 'SHIP.GPS.GGA.FIX_AGE', 'SHIP.GPS.GLL.FIX_AGE', 'SHIP.GPS.TIME', 'SHIP.GPS.ZDA.FIX_AGE', 'SHIP.GYRO.DEGREES', 'SHIP.GYRO.HEADING_RATE', 'SHIP.GYRO.HEADING_AGE', 'SHIP.GYRO.HEADING_RATE_AGE', 'ROV.UHS.WINCH_MODE', 'ROV.UHS.DRIVE_ALARM', 'ROV.UHS.ALARM_FLAGS', 'ROV.UHS.ROV_SET_LENGTH', 'ROV.UHS.ROV_WIRE_LENGTH', 'ROV.UHS.ROV_WIRE_SPEED', 'ROV.UHS.ROV_TENSION', 'ROV.UHS.CTD_SET_LENGTH', 'ROV.UHS.CTD_WIRE_LENGTH', 'ROV.UHS.CTD_WIRE_SPEED', 'ROV.UHS.CTD_TENSION']
Watching key 'SHIP.GPS.LAT' in bucket 'dpkd'...
[SHIP.GPS.LAT] = 36.483204
[SHIP.GPS.LAT] = 36.48314403333333