#!/usr/bin/python # Read data from a Digitek INO2513 multimeter over RS232. # Adam Sampson import serial class MultimeterException(Exception): pass # a # f b # g # e c # d INO2513_DIGITS = { # efadcgb int("1111101", 2): "0", int("0000101", 2): "1", int("1011011", 2): "2", int("0011111", 2): "3", int("0100111", 2): "4", int("0111110", 2): "5", int("1111110", 2): "6", int("0010101", 2): "7", int("1111111", 2): "8", int("0111111", 2): "9", int("0000000", 2): " ", int("1101000", 2): "L", } def decode_ino2513(msg): def bit(n, b): return (msg[n] & (1 << b)) != 0 def digit(n): segs = ((msg[n] & 0x7) << 4) | (msg[n + 1] & 0xF) if not segs in INO2513_DIGITS: raise MultimeterException("unrecognised digit %02x" % segs) return INO2513_DIGITS[segs] # Other bits that I'm not decoding: # ac = bit(0, 3) # dc = bit(0, 2) # auto = bit(0, 1) # diode = bit(9, 0) # tone = bit(10, 0) digits = digit(1) + digit(3) + digit(5) + digit(7) if digits == " 0L ": return ("O.L", None) try: value = float(digits) except ValueError: raise MultimeterException("unrecognised digits: '%s'" % digits) if bit(3, 3): # DP between 1 and 2 value /= 1000.0 elif bit(5, 3): # DP between 2 and 3 value /= 100.0 elif bit(7, 3): # DP between 3 and 4 value /= 10.0 if bit(1, 3): # minus value = -value unit = None if bit(11, 3): unit = "F" if bit(11, 2): unit = "ohm" elif bit(12, 3): unit = "A" elif bit(12, 2): unit = "V" elif bit(12, 1): unit = "Hz" elif bit(13, 2): unit = "degC" if unit is None: raise MultimeterException("unable to determine unit") if bit(9, 3): unit = "u" + unit elif bit(9, 2): unit = "n" + unit elif bit(10, 3): unit = "m" + unit elif bit(9, 1): unit = "k" + unit elif bit(10, 1): unit = "M" + unit return (value, unit) def read_ino2513(device): """A generator that returns readings from a Digitek INO2513 multimeter attached to the given serial port. In the event that you've lost your INO2513 cable, it has a mini barrel jack on one end and a DE9 female on the other. The centre of the barrel jack goes to pin 4, the outside goes to pin 2, and there's a 10k resistor between pin 2 and pin 3. The returned values are pairs (value, unit), where the unit is "{n,u,m,,k,M}{F,ohm,A,V,Hz,degC}" and the value is a float. If the unit is None, then the value is an error message as a string (currently only "O.L").""" ser = serial.Serial(device, 2400) LEN = 14 buf = [0] * LEN while True: c = ord(ser.read(1)) buf = buf[1:] + [c] if (c >> 4) == LEN: ok = True for i in range(LEN): if (buf[i] >> 4) != (i + 1): ok = False break if ok: v = decode_ino2513(buf) if v is not None: yield v def main(): meter = read_ino2513("/dev/ttyUSB0") for (value, unit) in meter: if unit is None: print value else: print "%3.3f %s" % (value, unit) if __name__ == "__main__": main()