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.
- Rachel Carson
navproc.NAV4D_UDPINnavproc.NAV_4D_MSGnavproc.NMEA_GPS_TCPINnavproc.NMEA_GPS_MSGnavproc.SEABIRD_CTD_SERINnavproc.SEABIRD_CTD_MSGnavproc.SEABIRD_CTD_STATnavproc.SHIP_GYRO_TCPINnavproc.SHIP_GYRO_MSG
- David Packard
navproc.PT_CONTROL_LAPBOX_4Knavproc.LAPBOX_4K_MSGnavproc.CAMERA_4K_MSGnavproc.NAV4D_UDPINnavproc.NAV_4D_MSGnavproc.NMEA_GPS_TCPINnavproc.NMEA_GPS_MSGnavproc.SEABIRD_CTD_SERINnavproc.SEABIRD_CTD_MSGnavproc.SEABIRD_CTD_STATnavproc.SHIP_GYRO_TCPINnavproc.SHIP_GYRO_MSGnavproc.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