Blog der Heimetli Software AG

Peaktech 2025a über USB mit Linux Auslesen

Ich habe lange gegoogelt aber nichts gefunden was den USB-Anschluss vom Paektech 2025a genau beschreibt.

Schlussendlich habe ich das Gerät einfach gekauft und ausprobiert. Die Ergebnisse sind hier dokumentiert.

Verbindung per USB

Der Anschluss des Multimeters erfolgt auf der Rückseite, siehe Foto. So wie es aussieht ist die USB-Buchse galvanisch vom Gerät getrennt. Das passende Kabel wird praktischerweise gleich mitgeliefert.

USB-Anschluss vom Peaktech 2025a

Linux erkennt einen USB-Seriell Adapter und erzeugt ein Device-File mit dem Namen /dev/ttyUSB0:

[ 2665.194290] usb 2-3: new full-speed USB device number 10 using xhci_hcd
[ 2665.336193] usb 2-3: New USB device found, idVendor=10c4, idProduct=ea60, bcdDevice= 1.00
[ 2665.336203] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2665.336207] usb 2-3: Product: CP2102 USB to UART Bridge Controller
[ 2665.336209] usb 2-3: Manufacturer: Silicon Labs
[ 2665.336212] usb 2-3: SerialNumber: 0001
[ 2665.338536] cp210x 2-3:1.0: cp210x converter detected
[ 2665.341616] usb 2-3: cp210x converter now attached to ttyUSB0

Die Rohdaten

Die Messwerte kommen als Zeilen mit fester Länge an. Sie sind aber nicht direkt nutzbar weil einige Bytes binär codiert sind:

b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0004 11H@\x80\x00\r\n'
b'+0005 11H@\x80\x00\r\n'
b'+0003 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'-0002 11H@\x80\x00\r\n'
b'-0004 11H@\x80\x00\r\n'
b'+0006 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0062 11H@\x80\x00\r\n'
b'+0016 11H@\x80\x00\r\n'
b'+0017 11H@\x80\x00\r\n'
b'+0022 11H@\x80\x00\r\n'
b'+0019 11H@\x80\x00\r\n'
b'+0388 11H@\x80\x00\r\n'
b'+ OL  3\x10\x00\x00\x80<\r\n'
b'+1444 31H\x00\x80\x03\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+1444 31H\x00\x80\x0e\r\n'
b'+0000 1\x10\x00@\x80\x0e\r\n'
b'+0011 11H@\x80\x00\r\n'
b'+0010 11H@\x80\x00\r\n'
b'+0009 11H@\x80\x00\r\n'
b'+0007 11H@\x80\x00\r\n'
b'+0005 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'-0001 11H@\x80\x00\r\n'
b'-1107 11H@\x80\x00\r\n'
b'-4498 11H@\x80\x0b\r\n'
b'+ OL  3\x10\x00\x00\x80<\r\n'
b'+0000 1\x10\x00@\x80,\r\n'
b'+ OL  3\x10\x00\x00\x80<\r\n'
b'-1444 31H\x00\x80\x00\r\n'
b'-0809 31H\x00\x80\x0e\r\n'
b'-1427 31H\x00\x80\x08\r\n'
b'-1443 31H\x00\x80\x0e\r\n'
b'-1443 31H\x00\x80\x0e\r\n'
b'-1443 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1444 31H\x00\x80\x0e\r\n'
b'-1362 31H\x00\x80\x0e\r\n'
b'+0000 1\x10\x00@\x80\r\r\n'
b'-0003 11H@\x80\x00\r\n'
b'-0006 11H@\x80\x00\r\n'
b'-0005 11H@\x80\x00\r\n'
b'-0005 11H@\x80\x00\r\n'
b'-0004 11H@\x80\x00\r\n'
b'-0004 11H@\x80\x00\r\n'
b'-0003 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'-0002 11H@\x80\x00\r\n'
b'-0007 11H@\x80\x00\r\n'
b'+0002 11H@\x80\x00\r\n'
b'+0001 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'
b'+0000 11H@\x80\x00\r\n'

Zum 2025a findet man gar nichts, aber wenn man lange genug sucht findet man eine Beschreibung der Daten für das 2025. Zum Glück gilt die Dokumentation auch für des 2025a. Anscheinend stammt das PDF direkt von Peaktech, aber auf ihrer Website ist es nicht zu finden.

Problematisch sind die Zeilen mit " OL " denn die kann man nicht in Zahlen konvertieren. Diese Werte setzt das Script auf math.inf.

Einlesen und Decodieren der Messwerte

Erledigt das folgende Python-Script:

from serial import Serial
from math import inf
import sys

def read_peaktech( port ):
    try:
        with Serial( port ) as ser:
            while True:
                line = ser.read_until( b"\n" )
                if (len(line) == 14) and (line[5] == 0x20):
                    try:
                        value = float( line[0:5].decode("ascii") )

                        if line[6] == 0x31:
                            value /= 10
                        elif line[6] == 0x32:
                            value /= 100
                        elif line[6] == 0x33:
                            value /= 1000
                        elif line[6] == 0x34:
                            value /= 10000
                    except:
                        value = inf

                    if (line[9] & 0x80) != 0:
                        prefix = "µ"
                    elif (line[9] & 0x40) != 0:
                        prefix = "m"
                    elif (line[9] & 0x20) != 0:
                        prefix = "k"
                    elif (line[9] & 0x20) != 0:
                        prefix = "M"
                    else:
                        prefix = ""

                    if (line[10] & 0x80) != 0:
                        unit = "V"
                    elif (line[10] & 0x40) != 0:
                        unit = "A"
                    elif (line[10] & 0x20) != 0:
                        unit = "Ω"
                    elif (line[10] & 0x10) != 0:
                        unit = "hFE"
                    elif (line[10] & 0x08) != 0:
                        unit = "Hz"
                    elif (line[10] & 0x04) != 0:
                        unit = "F"
                    elif (line[10] & 0x02) != 0:
                        unit = "℃"
                    elif (line[10] & 0x01) != 0:
                        unit = "℉"
                    else:
                        unit = ""

                    print( f"{value}{prefix}{unit}" )
    except KeyboardInterrupt:
        pass
    except Exception as ex:
        print( "Exception:", ex )

if __name__  == "__main__":
    port = "/dev/ttyUSB0"

    if len(sys.argv) > 1:
        port = sys.argv[1]

    read_peaktech( port )

In den Daten sind noch weitere Flags enthalten für Max, Min und ähnliche Betriebsarten des Multimeters. Weil ich die voraussichtlich nie verwende werden sie nicht decodiert.

Decodierte Messwerte

Aus den oben gezeigten Zeilen hat das Script folgende Messwerte ausgelesen:

0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.2mV
0.2mV
0.2mV
0.4mV
0.5mV
0.3mV
0.0mV
-0.2mV
-0.4mV
0.6mV
0.2mV
0.2mV
0.2mV
0.2mV
0.2mV
0.2mV
6.2mV
1.6mV
1.7mV
2.2mV
1.9mV
38.8mV
infV
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
1.444V
0.0mV
1.1mV
1.0mV
0.9mV
0.7mV
0.5mV
0.1mV
0.0mV
0.0mV
0.0mV
-0.1mV
-110.7mV
-449.8mV
infV
0.0mV
infV
-1.444V
-0.809V
-1.427V
-1.443V
-1.443V
-1.443V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.444V
-1.362V
0.0mV
-0.3mV
-0.6mV
-0.5mV
-0.5mV
-0.4mV
-0.4mV
-0.3mV
0.0mV
0.0mV
0.1mV
0.0mV
0.0mV
0.2mV
0.1mV
0.1mV
0.1mV
-0.2mV
-0.7mV
0.2mV
0.1mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV
0.0mV