Usage and Examples

The following example shows some basic usage of the seabird_ctd code

import seabird_ctd

def handle_records(records):
        This function receives the read data as a list of dicts, and you
        can handle the data however you like in here. In this case, we
        instantiate a new django model (not defined in this example)
        and set its values to match the records received before saving.

    for record in records:
        new_record = CTD()
        new_record.temp = record["temperature"]
        new_record.conductivity = record["conductivity"]
        new_record.pressure = record["pressure"]
        new_record.datetime = record["datetime"]

ctd = seabird_ctd.CTD(port="COM6", baud=9600, timeout=5)  # connect to the device itself over pyserial
if not ctd.is_sampling:  # if it's not sampling, set the datetime to match current device, otherwise, we can't
    ctd.set_datetime()  # this just demonstrates some of the attributes it parses from the status message
else:"CTD already logging. Listening in")

ctd.start_autosample(interval=60, realtime="Y", handler=handle_records, no_stop=True)  # start listening in to autosampling results. If it's already sampling, it can stop it, reset parameters, and start it again, or leave it alone, depending on the options you define here


Seabird CTD library is developed for Python 3. Most code should be compatible with Python 2.7, but has not been tested. If you’d like to make it Python 2.7 compatible, please submit a pull request.

Simple Setup

This library, with few dependencies, can send commands directly to the device and monitor and parse responses.

seabird_ctd requires two external packages for simple setup:

  • six (for Python 2/3 compatibility)
  • pyserial (for communication with the CTD)

After installing those packages and seabird_ctd, you are set up to use the package

When instantiating the CTD object in your code, no arguments are required except the COM port that the CTD communicates on. If you wish to not specify it in each script, you can also set an environment variable SEABIRD_CTD_PORT, which will be checked. Other options are available, including baud rate and the timeout for reading data (in seconds).

In simple mode, if you initialize autosampling, then the program goes into a loop that it won’t exit from waiting for CTD data. To exit, you will need to either break/interrupt the program (Ctrl+C) or kill the process.

Advanced Setup

Advanced setup allows you to send manual commands to the CTD while it is sampling. It uses a different architecture that listens for commands and sends those when they are received while still monitoring for data from samples.

Advanced setup requires significant external setup and small changes to your code. To use this mode, you must install:

  • Erlang (for RabbitMQ)
  • RabbitMQ
  • Pika python package

You must then set up and configure Rabbit MQ with a virtual host and a user account that has config privileges in that virtual host.

Then, in your code, prior to initiating autosampling, you call


Then, you can send commands via rabbit_mq to the queue in the virtual host that is named by COM port. So, if your CTD runs on COM4, then send messages to the queue “COM4”. Example code, again, as a Django management command, follows:

class Command(BaseCommand):
    help = 'Sends commands to the CTD while autosampling'

    def add_arguments(self, parser):
        parser.add_argument('--server', nargs='+', type=str, dest="server", default=False,)
        parser.add_argument('--queue', nargs='+', type=str, dest="queue", default=False,)
        parser.add_argument('--command', nargs='+', type=str, dest="command", default=True,)

    def handle(self, *args, **options):
        queue = None
        if options['queue']:
            queue = options['queue'][0]
            queue = os.environ['SEABIRD_CTD_PORT']

        server = None
        if options['server']:
            server = options['server'][0]
            server = ""  # set a default RabbitMQ server if not specified

        command = options['command'][0]  # get the actual command to send

        # connect to RabbitMQ
        connection = pika.BlockingConnection(pika.ConnectionParameters(host=server, virtual_host="moo", credentials=PlainCredentials(local_settings.RABBITMQ_USERNAME, local_settings.RABBITMQ_PASSWORD)))
        channel =


        # send the command message
        print(" [x] Sent {}".format(command))

You can send any command that the CTD supports executing while autosampling. See the manual for your CTD for more information on that. You can also send three special commands. READ_DATA initiates an immediate read of the data and sends it to the configured handler. STOP_MONITORING leaves the CTD recording data, but stops the Python code from checking for data. DISCONNECT is closely related to stop monitoring, but also sends a sleep command to the device and closes the serial connection.

Extending the code to a new CTD

CTDs have slightly different command styles, behaviors, and syntaxes and the authors of this package don’t have access to all of the CTDs Seabird produces. While the package has been tested with a handful of CTDs and firmware versions (SeacatPlus (SBE19plus), SBE39 firmware 1.5, SBE39 firmware 6, and SBE37), other models do not have support yet. This code is meant to provide a structure where it can be extended to support other, newer models, quickly (15 minutes to a few hours). Until further documentation is written, the best way to see how this is handled is to take a look at the objects for each CTD in the code in the file They define specific parsing information and command syntax for the CTDs.