Each board reports the 96-bit STM32 unique ID as its USB serial number (Application/usb_descriptors.c), so a board can be told apart from the others and is recognised again on any COM port. ptlogger: - find_devices()/find_device() resolve a board by port, UID (or its tail) or an assigned name; VID/PID 0xCAFE:0x4001 with a product-string fallback - persistent uid -> name map in pt_devices.json ($PT_DEVICE_DB to relocate) - PTLogger knows its uid/name, adds open(), rename() and reconnect() log_to_csv: - takes several devices or --all; all boards are sampled in parallel per tick, so one CSV row is one moment in time - columns prefixed with the board name, --split writes one file per board - --name DEV=NAME to label a board, --list shows port/uid/name - a board that drops off the bus leaves empty cells and is picked up again automatically, following its UID to whatever port it gets - <file>.meta.json records which board produced which columns Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PT1000 Temperature Logger
A Python host-side library and logging utility for a 12-channel PT1000 temperature logger device.
Overview
This project provides:
- ptlogger.py: Host-side library for communicating with a 12-channel PT1000 temperature logger via USB-CDC protocol
- log_to_csv.py: Example logger utility that continuously samples all channels and logs temperatures to CSV files
Features
- 12-channel temperature monitoring
- Real-time temperature readout
- Several boards logged simultaneously, sampled in parallel onto one time axis
- Device recognition by UID — each board reports its STM32 unique ID as USB serial number, so it is identified again on any COM port
- Persistent per-board names (
pt_devices.json) used as CSV column prefixes - Automatic reconnect when a board is unplugged/replugged mid-run
- Per-channel state monitoring (OK, open, short, fault, communication error)
- CSV logging with timestamps
- Configurable sampling intervals
- Zero-calibration support
- Reliable serial communication via pyserial
Installation
- Ensure Python 3.6+ is installed
- Install dependencies:
pip install -r requirements.txt
Usage
List Connected Boards and Serial Ports
python log_to_csv.py --list
Shows every logger board with its port, UID and name, then all serial ports, then boards that are known by name but currently not plugged in.
Start Logging (Default: 1 second interval)
python log_to_csv.py COM5
Log All Connected Boards at Once
python log_to_csv.py --all
All boards are read in parallel each tick, so one CSV row is one moment in time.
Name the Boards (Recognition)
python log_to_csv.py --name COM5=oven --name COM7=bath --list
The name is stored against the board's UID in pt_devices.json, so it survives a
replug and a different COM port. Afterwards boards can be addressed by name:
python log_to_csv.py oven bath -i 5 -o run1.csv
A device argument may be a port (COM5), a UID or its last digits (0A1B2C), or
an assigned name (oven).
One CSV Per Board
python log_to_csv.py --all --split -o run1.csv
Writes run1_oven.csv, run1_bath.csv, ... instead of one wide file.
Zero-Calibrate Before Logging
python log_to_csv.py --all -z
Calibrate all sensors of every board (each board's sensors must be in a homogeneous bath). Per-channel offsets are stored on the device.
Command-Line Options
devices: One or more boards — port, UID (or its tail), or assigned name-a, --all: Log every connected logger board-o, --output: CSV file name (default:pt_log_<date_time>.csv)-i, --interval: Sample interval in seconds (default: 1.0)-z, --zero: Zero-calibrate before logging--split: One CSV per board instead of one combined file--name DEV=NAME: Permanently name a board by its UID (repeatable)--list: List connected boards / serial ports and exit
Device Identification
The firmware exposes the 96-bit STM32 unique ID as the USB serial-number string
(Application/usb_descriptors.c), and the board uses VID/PID 0xCAFE:0x4001.
The host library uses this to:
- find all logger boards on the bus (
find_devices()) - map a UID to a stable, user-chosen name (
pt_devices.json, override the location with thePT_DEVICE_DBenvironment variable) - follow a board to a new COM port after a replug, during a running log
Library Usage
from ptlogger import PTLogger, find_devices, set_device_name
for dev in find_devices():
print(dev.name, dev.port, dev.uid)
# open by port, by UID, or by name
with PTLogger.open("oven") as pt:
print(pt.name, pt.uid, pt.version())
for ch, (temp, state) in enumerate(pt.read_all()):
print(f"Channel {ch}: {temp}°C (state: {pt.state_name(state)})")
# several boards at the same time
boards = [PTLogger.open(spec) for spec in ("oven", "bath")]
CSV Output Format
Combined file (default): a timestamp column plus 12 temperature columns per board, prefixed with the board name:
timestamp,oven_T0_degC,...,oven_T11_degC,bath_T0_degC,...,bath_T11_degC
2026-06-18T12:29:56.000,25.3,...,25.1,31.0,...,30.8
With --split, each board gets its own file with plain T0_degC ... T11_degC
columns.
Empty cells indicate a disconnected or faulty channel — or a board that was
temporarily off the bus (shown as .... in the live console view, while an open
channel shows ----).
Next to the CSV a <file>.meta.json records which board (name, UID, port,
firmware) produced which columns.
Requirements
- Python 3.6+
- pyserial >= 3.5
Notes
- Stop logging by pressing Enter (recommended for reliable exit) or Ctrl+C
- CSV files are flushed after every row, ensuring no data loss on interrupt
- Per-channel state codes match the MAX31865 sensor states