Connect your HP 34970A to InfluxDB and monitor your data acquisition in real-time.
Project description
daqmon – HP 34970A Data Acquisition Monitor
A Python CLI tool for configuring, scanning, and logging data from the HP/Agilent 34970A Data Acquisition / Switch Unit via serial (RS-232). Readings are logged to the CSV and written to InfluxDB v2.
Installation
pip:
pip install daqmon
uv (installs into the current project or virtual environment):
uv add daqmon
uvx (run without installing — useful for one-off use):
uvx daqmon identify
Quick start
# Create the default config file at ~/.config/daqmon/config.json
daqmon init
# Edit the config to set your serial port and InfluxDB connection
nano ~/.config/daqmon/config.json
# Scaffold a scan definition at ./scan.json
daqmon init-scan
# Identify the instrument
daqmon identify
# Run a scan (Ctrl-C to stop)
daqmon scan myscan.json
# Download the current instrument configuration
daqmon backup -o backup.json
Development
# Clone and install in editable mode with dev dependencies
git clone https://github.com/ameares/daqmon
cd daqmon
uv sync
# Run the CLI from source
uv run daqmon identify
# Lint, format, type-check, test
uv run ruff check src/
uv run ruff format src/
uv run mypy src/
uv run pytest tests/
Files
| File | Purpose |
|---|---|
config.json |
Serial port and InfluxDB connection settings |
myscan.json |
Scan definition (channels, types, interval) |
backup.json |
Downloaded instrument configuration (same format as myscan.json) |
config.json
{
"serial": {
"port": "/dev/ttyUSB0", // Serial port path
"baudrate": 9600, // 9600 default for 34970A
"timeout": 10.0 // Read timeout in seconds
},
"influxdb": {
"enabled": true,
"url": "http://localhost:8086",
"token": "my-token",
"org": "my-org",
"bucket": "daqmon",
"measurement": "hp34970a"
}
}
Scan definition (myscan.json / backup.json)
Top-level fields
| Field | Type | Default | Description |
|---|---|---|---|
description |
string | "" |
Human-readable label for this scan |
scan_interval |
float | 10.0 |
Seconds between sweeps |
scan_count |
int | 0 |
Number of sweeps to run; 0 = infinite (Ctrl-C to stop) |
ambient_correction |
bool | false |
If true, adds a _rise reading for each temperature channel (value minus ambient) |
ambient_channel |
int | — | Channel number to use as the ambient reference (required when ambient_correction is true) |
channels |
array | — | List of channel definitions (see below) |
Channel fields
| Field | Type | Default | Applies to | Description |
|---|---|---|---|---|
channel |
int | required | all | Channel number: slot × 100 + line (101–120, 201–220, 301–320) |
name |
string | required | all | Friendly name written as an InfluxDB tag |
function |
string | "dc_voltage" |
all | Measurement function (see table below) |
range |
string | "auto" |
dc_voltage, ac_voltage, dc_current, ac_current, resistance_2w, resistance_4w, frequency, period | Measurement range or "auto" |
nplc |
float | 1.0 |
dc_voltage, dc_current, resistance_2w, resistance_4w, temperature | Integration time in power-line cycles (0.02–100) |
tc_type |
string | "K" |
temperature, thermocouple | Thermocouple type: J, K, T, E, R, S, B, N |
ref_junction |
string | "internal" |
temperature, thermocouple | Reference junction: internal, fixed, or external |
ref_fixed_temp |
float | — | temperature, thermocouple | Fixed reference junction temperature in °C (only when ref_junction is "fixed") |
ref_channel |
int | — | temperature, thermocouple | Channel number of external reference junction (only when ref_junction is "external") |
ac_bandwidth |
float | — | ac_voltage, ac_current | AC bandwidth filter in Hz: 3, 20, or 200 |
unit |
string | "" |
all | Unit label written to InfluxDB |
gain |
float | 1.0 |
all | Multiplier applied to raw reading: result = raw × gain + offset |
offset |
float | 0.0 |
all | Offset added after gain: result = raw × gain + offset |
delay |
float | — | all | Relay settling time in seconds inserted after this channel is configured |
Supported measurement functions
| Key | SCPI function | range | nplc | ac_bandwidth |
|---|---|---|---|---|
dc_voltage |
VOLT:DC | ✓ | ✓ | |
ac_voltage |
VOLT:AC | ✓ | ✓ | |
dc_current |
CURR:DC | ✓ | ✓ | |
ac_current |
CURR:AC | ✓ | ✓ | |
resistance_2w |
RES (2-wire) | ✓ | ✓ | |
resistance_4w |
FRES (4-wire) | ✓ | ✓ | |
frequency |
FREQ | ✓ | ||
period |
PER | ✓ | ||
temperature |
TEMP (thermocouple) | ✓ | ||
thermocouple |
TEMP (alias) | ✓ | ||
digital_input |
DIG | |||
totalize |
TOT |
Range values
| Function | Valid range strings |
|---|---|
dc_voltage |
"auto", "0.1", "1", "10", "100", "300" |
ac_voltage |
"auto", "0.1", "1", "10", "100", "300" |
dc_current |
"auto", "0.01", "0.1", "1" |
ac_current |
"auto", "0.01", "0.1", "1" |
resistance_2w / resistance_4w |
"auto", "100", "1000", "10000", "100000", "1000000", "10000000", "100000000" |
frequency / period |
"auto", "0.1", "1", "10", "100", "300" (input voltage range) |
Example: full-featured scan
{
"description": "Thermal test – oven channels + power supply",
"scan_interval": 5.0, // Sweep every 5 seconds
"scan_count": 0, // Run until Ctrl-C
"ambient_correction": true, // Add _rise readings for temperature channels
"ambient_channel": 110, // Channel 110 is the ambient reference
"channels": [
{
// Thermocouple – internal cold junction reference
"channel": 101,
"name": "oven_top",
"function": "temperature",
"tc_type": "K",
"ref_junction": "internal",
"nplc": 5.0,
"unit": "degC"
},
{
// Thermocouple – fixed cold junction reference
"channel": 102,
"name": "oven_bottom",
"function": "temperature",
"tc_type": "K",
"ref_junction": "fixed",
"ref_fixed_temp": 23.5, // Reference junction is 23.5 °C
"unit": "degC"
},
{
// Thermocouple – external cold junction on another channel
"channel": 103,
"name": "sample",
"function": "temperature",
"tc_type": "T",
"ref_junction": "external",
"ref_channel": 110, // Cold junction measured on channel 110
"unit": "degC"
},
{
// Ambient reference channel (used for _rise correction above)
"channel": 110,
"name": "ambient",
"function": "temperature",
"tc_type": "K",
"ref_junction": "internal",
"unit": "degC"
},
{
// DC voltage with explicit range and high integration time
"channel": 201,
"name": "psu_output",
"function": "dc_voltage",
"range": "10", // 10 V range
"nplc": 10.0, // Slow, high-accuracy
"unit": "V"
},
{
// DC current with gain/offset scaling
"channel": 202,
"name": "load_current",
"function": "dc_current",
"range": "auto",
"nplc": 1.0,
"gain": 1000.0, // Convert A → mA
"offset": 0.0,
"unit": "mA"
},
{
// AC voltage with bandwidth filter
"channel": 203,
"name": "mains_voltage",
"function": "ac_voltage",
"range": "300",
"ac_bandwidth": 20, // 20 Hz bandwidth filter
"unit": "Vrms"
},
{
// 4-wire resistance
"channel": 204,
"name": "heater_resistance",
"function": "resistance_4w",
"range": "auto",
"nplc": 2.0,
"unit": "ohm",
"delay": 0.05 // 50 ms relay settling delay
},
{
// Frequency measurement
"channel": 205,
"name": "fan_speed_freq",
"function": "frequency",
"range": "auto",
"unit": "Hz"
},
{
// Digital input (returns integer bitmask)
"channel": 301,
"name": "door_switch",
"function": "digital_input"
}
]
}
CLI reference
daqmon [-c CONFIG] [-v] {scan,backup,identify}
-c, --config Path to config.json (default: config.json)
-v, --verbose Enable DEBUG logging
scan SCAN_FILE Upload config and start scanning
--poll-interval Polling rate in seconds (default: 2.0)
backup [-o OUTPUT] Download instrument config to JSON (default: backup.json)
identify Print *IDN? response
Architecture
cli.py argparse entry point, signal handling, orchestration
instrument.py HP34970A SCPI driver over pyserial
config.py ScanConfig / ChannelConfig dataclasses + JSON I/O
scanner.py Channel configuration, scan loop, data parsing
influx.py InfluxDB v2 writer
backup.py Download instrument config to JSON
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file daqmon-0.1.1.tar.gz.
File metadata
- Download URL: daqmon-0.1.1.tar.gz
- Upload date:
- Size: 54.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29966935f0af791937c0cd7655657590a3ee0e1d51e13df6a73ca22d5474929e
|
|
| MD5 |
683378a002176b641f6281d12cbdc64b
|
|
| BLAKE2b-256 |
1e201c0f281031b9ca899a2040ee9f538ef0ec448799c193f1fdbcb006f9347b
|
Provenance
The following attestation bundles were made for daqmon-0.1.1.tar.gz:
Publisher:
publish.yml on ameares/daqmon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
daqmon-0.1.1.tar.gz -
Subject digest:
29966935f0af791937c0cd7655657590a3ee0e1d51e13df6a73ca22d5474929e - Sigstore transparency entry: 1200892832
- Sigstore integration time:
-
Permalink:
ameares/daqmon@917eb793662a45ff20e3db60f46664ac3557e84e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/ameares
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@917eb793662a45ff20e3db60f46664ac3557e84e -
Trigger Event:
push
-
Statement type:
File details
Details for the file daqmon-0.1.1-py3-none-any.whl.
File metadata
- Download URL: daqmon-0.1.1-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28c099252a8086e1f402873755e47212e820303feb8a46fb881f4dac3e96dfe3
|
|
| MD5 |
9668f1fd8729ca336f64a5dc46de1983
|
|
| BLAKE2b-256 |
5dfe487946e2fb243ab9fd863d90f9751f74fe433e6cfdea577bd33d34eafc0a
|
Provenance
The following attestation bundles were made for daqmon-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on ameares/daqmon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
daqmon-0.1.1-py3-none-any.whl -
Subject digest:
28c099252a8086e1f402873755e47212e820303feb8a46fb881f4dac3e96dfe3 - Sigstore transparency entry: 1200892848
- Sigstore integration time:
-
Permalink:
ameares/daqmon@917eb793662a45ff20e3db60f46664ac3557e84e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/ameares
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@917eb793662a45ff20e3db60f46664ac3557e84e -
Trigger Event:
push
-
Statement type: