Skip to content

ROV CTD TimescaleDB Client

The ROV CTD data is streamed into a TimescaleDB database onboard the Rachel Carson so you can query the data from there using any standard SQL client or using code.

Message Structure

If you use the Python code in the example below you should see a set of record that look something like this:

Latest 5 rows from navproc_seabird_ctd_msg:
--------------------------------------------------------------------------------
{'id': 1640205, 'lcm_channel': 'SEABIRD_CTD_MSG', 'message_type': 'navproc/msg_t', 'pub_id': 'navproc-rcsn:seabird_ctd(3115)', 'pub_sequence': 819580, 'pub_timestamp': datetime.datetime(2025, 10, 8, 21, 47, 1, 705280, tzinfo=datetime.timezone.utc), 'in_water': False, 'temperature': 15.3889, 'conductivity': 0.09939, 'pressure': -0.582, 'analog1': 2.4587, 'analog2': 1.9701, 'analog3': 3.4485, 'analog4': 0.0006, 'sound_velocity': 1468.023}
{'id': 1640204, 'lcm_channel': 'SEABIRD_CTD_MSG', 'message_type': 'navproc/msg_t', 'pub_id': 'navproc-rcsn:seabird_ctd(3115)', 'pub_sequence': 819579, 'pub_timestamp': datetime.datetime(2025, 10, 8, 21, 47, 1, 462006, tzinfo=datetime.timezone.utc), 'in_water': False, 'temperature': 15.3882, 'conductivity': 0.10158, 'pressure': -0.58, 'analog1': 2.4584, 'analog2': 1.9642, 'analog3': 3.4486, 'analog4': 0.0002, 'sound_velocity': 1468.037}
{'id': 1640203, 'lcm_channel': 'SEABIRD_CTD_MSG', 'message_type': 'navproc/msg_t', 'pub_id': 'navproc-rcsn:seabird_ctd(3115)', 'pub_sequence': 819578, 'pub_timestamp': datetime.datetime(2025, 10, 8, 21, 47, 1, 218136, tzinfo=datetime.timezone.utc), 'in_water': False, 'temperature': 15.3886, 'conductivity': 0.1029, 'pressure': -0.57, 'analog1': 2.458, 'analog2': 1.9682, 'analog3': 3.4479, 'analog4': 0.0007, 'sound_velocity': 1468.049}
{'id': 1640202, 'lcm_channel': 'SEABIRD_CTD_MSG', 'message_type': 'navproc/msg_t', 'pub_id': 'navproc-rcsn:seabird_ctd(3115)', 'pub_sequence': 819577, 'pub_timestamp': datetime.datetime(2025, 10, 8, 21, 47, 0, 954557, tzinfo=datetime.timezone.utc), 'in_water': False, 'temperature': 15.3886, 'conductivity': 0.10368, 'pressure': -0.609, 'analog1': 2.4578, 'analog2': 1.9661, 'analog3': 3.4439, 'analog4': 0.0004, 'sound_velocity': 1468.054}
{'id': 1640201, 'lcm_channel': 'SEABIRD_CTD_MSG', 'message_type': 'navproc/msg_t', 'pub_id': 'navproc-rcsn:seabird_ctd(3115)', 'pub_sequence': 819576, 'pub_timestamp': datetime.datetime(2025, 10, 8, 21, 47, 0, 710438, tzinfo=datetime.timezone.utc), 'in_water': False, 'temperature': 15.3891, 'conductivity': 0.10526, 'pressure': -0.609, 'analog1': 2.4571, 'analog2': 1.973, 'analog3': 3.4441, 'analog4': 0.0001, 'sound_velocity': 1468.068}

Python

import psycopg2
from psycopg2 import sql

def query_timescaledb(host, database, table, user, password, port=5432):
    """
    Query the latest 20 rows from TimescaleDB
    """
    try:
        # Connect to the database
        conn = psycopg2.connect(
            host=host,
            database=database,
            user=user,
            password=password,
            port=port
        )

        print(f"Connected to {host}:{port}/{database}")

        # Create a cursor
        cur = conn.cursor()

        # Query for the latest 20 rows ordered by pub_timestamp
        query = sql.SQL("""
            SELECT * FROM {table}
            ORDER BY pub_timestamp DESC
            LIMIT 5
        """).format(table=sql.Identifier(table))

        cur.execute(query)

        # Fetch the results
        rows = cur.fetchall()

        # Get column names
        colnames = [desc[0] for desc in cur.description]

        # Print results
        print(f"\nLatest 5 rows from {table}:")
        print("-" * 80)

        for row in rows:
            print(dict(zip(colnames, row)))
            print()  # Blank line between rows

        # Close cursor and connection
        cur.close()
        conn.close()

        return rows, colnames

    except Exception as e:
        print(f"Error: {e}")
        return None, None

def main():
    # Database connection parameters
    HOST = "coredata-rcsn.rc.mbari.org"
    DATABASE = "navproc"
    TABLE = "navproc_seabird_ctd_msg"
    USER = ""
    PASSWORD = ""
    PORT = 5432

    query_timescaledb(HOST, DATABASE, TABLE, USER, PASSWORD, PORT)

if __name__ == "__main__":
    main()