# LabJack read task

> Learn how to acquire data from LabJack devices with Synnax.

This task follows the standard [task lifecycle](https://docs.synnaxlabs.com/reference/driver/task-basics#task-lifecycle).

## Task configuration reference

| Parameter     | Type   | Required | Default | Description                                                   |
| ------------- | ------ | -------- | ------- | ------------------------------------------------------------- |
| `device`      | string | Yes      | -       | Key of the LabJack device                                     |
| `sample_rate` | number | No       | `10`    | Samples per second (Hz)                                       |
| `stream_rate` | number | No       | `5`     | Rate data is streamed to Synnax (Hz), must be ≤ `sample_rate` |
| `channels`    | array  | Yes      | -       | List of input channel configurations                          |

## Channel types reference

Analog input ([`analog`](https://support.labjack.com/docs/14-0-analog-inputs-t-series-datasheet))

Reads analog voltage from a specified input terminal. Supports single-ended and differential configurations.

| Parameter  | Type   | Required | Default | Description                                                             |
| ---------- | ------ | -------- | ------- | ----------------------------------------------------------------------- |
| `channel`  | number | Yes      | -       | Synnax channel key                                                      |
| `port`     | string | Yes      | -       | Port location (e.g., `AIN0`, `AIN1`)                                    |
| `range`    | number | No       | `10.0`  | Voltage range (±range volts)                                            |
| `neg_chan` | number | No       | `199`   | Negative channel for differential measurements (199 = single-ended/GND) |
| `scale`    | object | No       | -       | Custom scaling applied to the reading                                   |

Thermocouple ([`thermocouple`](https://support.labjack.com/docs/14-1-1-thermocouple-t7-t8-t-series-datasheet))

Reads temperature from a thermocouple with cold junction compensation (CJC).

> **Performance note** -> Thermocouple channels use LabJack’s built-in thermocouple features, which [reduce the maximum reliable sample rate](https://support.labjack.com/docs/using-a-thermocouple-with-the-t7#UsingaThermocouplewiththeT7-ThermocouplesinStreamMode) compared to tasks with only analog or digital inputs.

| Parameter           | Type   | Required | Default                | Description                                                             |
| ------------------- | ------ | -------- | ---------------------- | ----------------------------------------------------------------------- |
| `channel`           | number | Yes      | -                      | Synnax channel key                                                      |
| `port`              | string | Yes      | -                      | AIN port the positive lead is wired to (e.g., `AIN0`, `AIN1`)           |
| `thermocouple_type` | enum   | No       | `K`                    | `B`, `E`, `J`, `K`, `N`, `R`, `S`, `T`, `C`                             |
| `units`             | enum   | No       | `K`                    | Temperature units (`K`, `C`, `F`)                                       |
| `cjc_source`        | string | No       | `TEMPERATURE_DEVICE_K` | CJC source: `TEMPERATURE_DEVICE_K`, `TEMPERATURE_AIR_K`, or `AIN#`      |
| `cjc_slope`         | number | No       | `1.0`                  | CJC voltage to temperature slope (K/V)                                  |
| `cjc_offset`        | number | No       | `0.0`                  | CJC temperature offset (K)                                              |
| `neg_chan`          | number | No       | `199`                  | Negative channel for differential measurements (199 = single-ended/GND) |
| `scale`             | object | No       | -                      | Custom scaling applied to the reading                                   |

**CJC configuration examples:**

* **Device temp sensor** -> `cjc_source="TEMPERATURE_DEVICE_K"`, `cjc_slope=1.0`, `cjc_offset=0.0`
* **LM34 sensor** -> `cjc_source="AIN1"`, `cjc_slope=55.56`, `cjc_offset=255.37`

Digital input ([`digital`](https://support.labjack.com/docs/13-0-digital-i-o-t-series-datasheet))

Reads digital state (0 or 1) from a specified digital I/O line.

| Parameter | Type   | Required | Default | Description                          |
| --------- | ------ | -------- | ------- | ------------------------------------ |
| `channel` | number | Yes      | -       | Synnax channel key                   |
| `port`    | string | Yes      | -       | Port location (e.g., `DIO4`, `FIO5`) |

## Important rules

* **Thermocouple performance** -> Thermocouple channels lower the maximum sample rate because LJM processes them outside the stream.
* **Stream rate** -> For sample rates under 50 Hz, set the stream rate equal to the sample rate. Above that, keep the stream rate under 50 Hz.

## How-to

**Console**

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/device-drivers/labjack/read-task/lj-read-dark.mp4#t=0.001)

**Python**

Configure and run task

```python
import synnax as sy
from synnax import labjack

client = sy.Synnax()

# Retrieve device
dev = client.devices.retrieve(name="my_labjack")

# Create index channel
ai_time = client.channels.create(
    name="ai_time",
    is_index=True,
    data_type=sy.DataType.TIMESTAMP,
    retrieve_if_name_exists=True,
)

# Create data channels
ai_0 = client.channels.create(
    name="ai_0",
    index=ai_time.key,
    data_type=sy.DataType.FLOAT32,
    retrieve_if_name_exists=True,
)
ai_1 = client.channels.create(
    name="ai_1",
    index=ai_time.key,
    data_type=sy.DataType.FLOAT32,
    retrieve_if_name_exists=True,
)
di_4 = client.channels.create(
    name="di_4",
    index=ai_time.key,
    data_type=sy.DataType.UINT8,
    retrieve_if_name_exists=True,
)

# Create and configure task
task = labjack.ReadTask(
    name="LabJack Read Task",
    device=dev.key,
    sample_rate=sy.Rate.HZ * 100,
    stream_rate=sy.Rate.HZ * 25,
    channels=[
        labjack.AnalogReadChannel(
            channel=ai_0.key,
            port="AIN0",
            range=10.0,
            neg_chan=199,  # Single-ended
        ),
        labjack.AnalogReadChannel(
            channel=ai_1.key,
            port="AIN1",
            range=10.0,
            neg_chan=199,  # Single-ended
        ),
        labjack.DigitalReadChannel(
            channel=di_4.key,
            port="DIO4",
        ),
    ],
)

client.tasks.configure(task)

# Start task and read data
with task.run():
    with client.open_streamer(["ai_0", "ai_1", "di_4"]) as streamer:
        for _ in range(10):
            frame = streamer.read()
            print(frame)
```

Edit task configuration

```python
# Retrieve existing task
task = client.tasks.retrieve(name="LabJack Read Task")
task = labjack.ReadTask(internal=task)

# Update task-level configuration
task.config.auto_start = True
task.config.stream_rate = int(sy.Rate.HZ * 50)

# Update first analog input configuration
task.config.channels[0].port = "AIN2"
task.config.channels[0].range = 5.0

# Update second analog input configuration
task.config.channels[1].port = "AIN3"
task.config.channels[1].range = 1.0

# Update digital input configuration
task.config.channels[2].port = "DIO5"

# Apply changes
client.tasks.configure(task)
```

**TypeScript**

Configure and run task

```typescript
import { Synnax } from "@synnaxlabs/client";

const client = new Synnax();

// Retrieve device
const [dev] = await client.devices.retrieve({ names: ["my_labjack"] });

// Create index channel
const aiTime = await client.channels.create(
  {
    name: "ai_time",
    isIndex: true,
    dataType: "timestamp",
  },
  { retrieveIfNameExists: true },
);

// Create data channels
const ai0 = await client.channels.create(
  {
    name: "ai_0",
    index: aiTime.key,
    dataType: "float32",
  },
  { retrieveIfNameExists: true },
);

const ai1 = await client.channels.create(
  {
    name: "ai_1",
    index: aiTime.key,
    dataType: "float32",
  },
  { retrieveIfNameExists: true },
);

const di4 = await client.channels.create(
  {
    name: "di_4",
    index: aiTime.key,
    dataType: "uint8",
  },
  { retrieveIfNameExists: true },
);

// Create and configure task
const task = await client.tasks.create({
  name: "LabJack Read Task",
  rack: dev.rack,
  type: "labjack_read",
  config: {
    device: dev.key,
    sampleRate: 100,
    streamRate: 25,
    channels: [
      {
        type: "analog",
        channel: ai0.key,
        port: "AIN0",
        range: 10.0,
        negChan: 199,
      },
      {
        type: "analog",
        channel: ai1.key,
        port: "AIN1",
        range: 10.0,
        negChan: 199,
      },
      {
        type: "digital",
        channel: di4.key,
        port: "DIO4",
      },
    ],
  },
});

// Start task
await task.start();

// Read data
const streamer = await client.openStreamer(["ai_0", "ai_1", "di_4"]);
for (let i = 0; i < 10; i++) {
  const frame = await streamer.read();
  console.log(frame);
}

// Stop task
await task.stop();
await streamer.close();
```

Edit task configuration

```typescript
import { labjack } from "@synnaxlabs/client";

// Retrieve existing task
const task = await client.tasks.retrieve({ name: "LabJack Read Task" });

// Parse and update configuration
const config = labjack.readConfigZ.parse(task.config);

// Update task-level configuration
config.autoStart = true;
config.streamRate = 50;

// Update first analog input configuration
const firstAnalog = config.channels[0] as labjack.AnalogReadChannel;
firstAnalog.port = "AIN2";
firstAnalog.range = 5.0;

// Update second analog input configuration
const secondAnalog = config.channels[1] as labjack.AnalogReadChannel;
secondAnalog.port = "AIN3";
secondAnalog.range = 1.0;

// Update digital input configuration
const digital = config.channels[2] as labjack.DigitalReadChannel;
digital.port = "DIO5";

// Apply changes
await client.tasks.create({
  key: task.key,
  rack: task.rack,
  name: task.name,
  type: task.type,
  config,
});
```
