back to index

DL24.py, python control for DL24P and other Atorch artificial loads


Why
Hardware description
      load modes
      hardware architecture
            connectors
            buttons
How
      dependencies
      protocol
            PX100 protocol
            "Atorch" protocol
            transaction examples
Usage
      hardware configuration
      commands
      settings
      miniscripts
            loops
            stdin
            data on one line
            connection persistence
      verbosity
      temperatures
      autoconfiguration
      debug
            protocol reverse engineering aids
Files
TODO

Why

It was necessary to control an Atorch DL24P constant-current load for some lab automation purposes. The stock software was useless for the purpose, surprise surprise.

There is a fragmentary documentation of the protocol online, all over the Internet and over various code implementations of varying completeness.

The device communicates over a standard UART at 9600 bps, no parity, 1 stopbit (the most common setting), using a custom packet-based protocol.

The serial bus can be accessed over either a USB-serial converter based on CH340G chip (warning: no galvanic isolation!), or via Bluetooth serial interface, using a /dev/rfcommX port. Addition of wifi-accessible serial interface is also possible, using eg. the expedient plain serial-over-TCP ("TasmoCOM") solution was chosen, leveraging ESP8266 and Tasmota, a proven cheap and opensource approach.

The code is a variant on the control system for RD60, Riden RD60xx and RK60xx power supplies.

Tested with:


Hardware description

load modes

The device nominally supports several different load modes:

Only the CC mode is fully supported. The protocol does not allow selecting other modes, changing values for them, nor even querying what mode is set.

The hardware in its current (2023) version looks like just slightly modified AC/DC power consumption measuring device, with load control tacked on it. For sensing, separate dedicated load-measuring chips are used, and the microcontroller communicated with them via internal UART bus. The Rx/Tx comm is naturally abysmally slow, dooming any closed-loop regulation involving CPU to be abysmally unstable and often useless with more dynamic source.

The load itself is realized as a big MOSFET on an even bigger actively cooled heatsink, likely a surplus for older CPUs. The MOSFET gate is fed with voltage from an op-amp, comparing signal from a current-sensing resistor with a reference voltage coming from a RC-filtered PWM from the controller. This is a pretty good closed-loop regulation, bog-standard approach with minimal demands on the CPU; in a pinch, a potentiometer can be used for setting the reference.

The advantage of using dedicated power consumption sensing chips is more reliable integration of the consumed energy. Which is useful for the device's primary purpose - testing batteries. For this use, the device has a voltage cutoff preset.

hardware architecture

The device is built around several chips:

The MOSFET is a switching one, abused here in linear duty. Word goes along that some sellers use fake or reused ones, and this component dies often. Prepare to replace it.

The UART has pins available near the Bluetooth chip, left to right:

This is a tentative place to hook up the wifi serial module.

connectors

On the left side there is a 4-pin screw clamp, for attaching source (outer pins) and source sensing (inner pins). Either use a Kelvin connection or connect pins 1 to 2 and 3 to 4 and neglect the (often significant) voltage drop on the cables.

On the right side there is a 5.5/2.1mm barrel jack, connected in parallel to the source pins. Do not mistake for the other connector on the back. An adapter with a barrel jack and USB-mini, USB-micro and USB-C connector is often available.

On the right side there is also the microUSB connector with USB-UART CH340G interface.

On the back side there is one 5.5/2.1mm barrel jack for a 9-to-12v power supply. This one feeds the internal electronics (fan, op-amps, 3.3v linear regulator).

buttons

The unit has four buttons in a diamond layout.


How

dl24.py, a python-based (for portability) script, was written. The software allows both using a tty-style port and a raw TCP socket, with no fancy RFC2217 support. If the latter is needed, URI-style pyserial syntax is available with the port.

The software defines a hierarchy of classes:

dependencies

The software tries to minimize dependencies.

The mandatory ones, and mostly standard ones, are:

The nonmandatory, imported only as needed (so the process would run when a missing dependency is not required), are:

protocol

The device communicates over a bidirectional serial stream. There seem to be two different protocols, mixed together:

PX100 protocol

Challenge-response, master-slave protocol. The device listens and only reacts to the data sent.

 request packet format:

        0xB1 0xB2 [cmd] [d1] [d2] 0xB6
 on/off             01   xx   00       xx=01 for on, 00 for off
 set current        02   xx   yy       xx=integer, yy=decimal (00..99d)
 set cutoff v       03   xx   yy       ""
 set timeout        04   xx   yy       xxyy as unsigned int in seconds
 reset counters     05   00   00

 command response format: a single byte, 0x6F (PROTO_SHORTACK)

 query response:
                  0xCA 0xCB [d1] [d2] [d3] 0xCE 0xCF
             for cmd code
 load enabled      10        00   00   xx          xx=00 (off) or 01 (on)
 measured mV       11        xx   yy   zz          0xXXYYZZ, 24bit integer
 measured mA       12        xx   yy   zz
 timer value       13        hh   mm   ss
 cap mAh           14        xx   yy   zz
 cap mWh           15        xx   yy   zz
 mosfet 'c         16        xx   yy   zz
 preset current    17        xx   yy   zz          10s mA
 preset cutoff     18        xx   yy   zz          10s mV
 preset timer      19        hh   mm   ss

 [cmd] code ranges 0x0? for command (with short response) and query (with long 7-byte response)

 On invalid command there is no response, the command timeouts.

"Atorch" protocol

More modern protocol, combining fixed-format status updates in one-second intervals and challenge-response commands

The packets have a fixed overall structure with variable length:

 Atorch protocol, type 0x01: 1-per-second, 36-byte: (pfct=power factor, bk=backlight)
                   x4               x8               xc               x10               x14               x18              x1c              x20
                   4                8                12               16                20                24               28               32
 [FF][55][01][02] [00][00][00] [00][00][00] [00][00][12] [00][00][00][00] [00][00][00] [00][00] [00][00] [00][17][00][00] [0A][33][3c][00] [00][00][00][E1]
 [FF][55][01][02] [00][00][33] [00][00][00] [00][00][12] [00][00][00][00] [00][00][00] [00][00] [00][00] [00][17][00][00] [0A][33][3c][00] [00][00][00][9C]
          t   01  -volt*0.1?-  -milliamps-  ---power---  ----energy-----   --price?--   -freq-   -pfct-   -temp-                   bk
          t   02  -volt*0.1--  -milliamps-  -amphours--  ----energy-----   --price?--            -pfct-   -temp-  --hhhh---mm--ss  bk
          t   03  -volt*0.1?-  -milliamps-  -amphours--  ----energy-----    usbd+   usbd-   -temp-   --hhhh---mm--ss  bk
             ADU      0.1v       0.001a       0.01Ah


 type 0x02, reply:
 [FF][55][02] [val0][val1][val2][val3] [checksum]
 for a good command (0x32, button) the response is 01 01 00 00
 for a bad command (0x36) the response is 01 03 00 00
 01 01 seems to be good command
 01 03 seems to be unimplemented command

 sample push of ON/OFF button: (cmd=0x32, values=[0,0,0,0])
 SEND: ff:55:11:02: 32 :00:00:00:00 :01
 RECV: ff:55:02: 01:01:00:00 :40


 type 0x11, request:
 [FF][55][11][ADU] [cmd] [val0][val1][val2][val3] [checksum]  - val1 seems to be always 0x00

 sample requests, as by http://bukys.eu/project/powermon/start :

   Commands for UD18 UD24 (USB)
     WH reset            FF 55 11 03 01 00 00 00 00 51
     AH reset            FF 55 11 03 02 00 00 00 00 52
     TIME reset          FF 55 11 03 03 00 00 00 00 53
     ALL reset           FF 55 11 03 05 00 00 00 00 5d
     SETUP Button        FF 55 11 03 31 00 00 00 00 01
     ENTER Button        FF 55 11 03 32 00 00 00 00 02
     [+] Button          FF 55 11 03 33 00 00 00 00 03
     [-] Button          FF 55 11 03 34 00 00 00 00 0C

  Commands for S1-B (USB)
     WH reset            FF 55 11 03 01 00 00 00 00 51
     Internal relay      FF 55 11 03 02 00 00 00 00 52
     TIME reset          FF 55 11 03 03 00 00 00 00 53

transaction examples

using protocol reverse engineering commands with VERB:CM

 CMD: RAWPX100:30
 SEND: b1:b2:30:00:00:b6
 REPLY TIMEOUT
 SEND: b1:b2:30:00:00:b6
 REPLY TIMEOUT
 SEND: b1:b2:30:00:00:b6
 REPLY TIMEOUT

 CMD: RAWPX100:01
 SEND: b1:b2:01:00:00:b6
 RECV: 6f

 CMD: RAWPX100:10
 SEND: b1:b2:10:00:00:b6
 RECV: ca:cb:00:00:00:ce:cf

 CMD: RAWPROTO:32
 SEND: ff:55:11:02:32:00:00:00:00:01
 RECV: ff:55:02:01:01:00:00:40

 CMD: RAWPROTO:FF
 SEND: ff:55:11:02:ff:00:00:00:00:56
 RECV: ff:55:02:01:03:00:00:42


Usage

Atorch DL24 artificial control
Usage: ./dl24.py <command> [command]...
Commands:

  ON             enable output
  OFF            disable output

  nn.nnVCUT      set cutoff voltage
  nn.nnMA        set output current
  nn.nnA         set output current

  QV             query actual voltage
  QMV            query actual voltage, integer millivolts
  QA             query actual current
  QMA            query actual current, integer milliamps
  QTI            query internal temperature
  QVCUT          query cutoff voltage

  QAH            query amp-hour counter
  QMAH           query amp-hour counter in integer mAh
  QWH            query watt-hour counter
  QMWH           query watt-hour counter in integer mWh
  RESET          reset energy counters

  STATE[:opts]   print setting state in JSON format
  STATEJ[:opts]  print setting state in JSON format, like opts=J
          opts:  J=JSON, S=short (V/A only), T=show time, U=show UTC time, A=show all, B=force battery, M=minimize queries, L=listen-only
  LISTEN[:opts[:count]]  listen to status reports, query data, handle stdin
  LISTEN[:opts[:off]]    listen, until off
          opts:  J=JSON, S=short (V/A only), T=show time, U=show UTC time, A=show all, B=force battery, M=minimize queries, L=listen-only

  TCP=addr[:port]           set connection via TCP
  PORT=/dev/ttyport[@baud]  set connection via serial port
  WAIT           wait for communication from device
  ROBUST         increase timeouts and retries
  OFFOFF         switch output off on program exit
  STOPOFF        stop loop on output off

  STDIN          read commands from stdin
  LOOP:[xx]      loop for xx time or endless if not specified
  SLEEPxx        sleep for xx seconds
  VERB[:opts]    list operations
          opts:  P=port, C=communication, D=dataflow, M=commands
  LINE           output the Q-queries as space-separated instead of newline-separated
  TYPE           print detected device type
  CFGFILE        generate config file template to stdout

  RAWPROTO:xx[:xx:xx:xx:xx]   raw Atorch protocol send, cmd + 4 payloads
  RAWPX100:xx[:xx:xx]         raw PX100 protocol send, cmd + 2 payloads
  RAWSEND:xx[:xx:xx:...]      raw serial protocol data send
  NORETRY                     do not retry timeouted commands

For volt and amp setting, prefixing the value with + or - marks it as relative, to be added/subtracted to the current value
Commands are executed in sequence. Writes are cached and grouped together to minimize bus transactions.
Commands are case-insensitive.
Command "-" forces a newline into output.

hardware configuration

The host:port or serport:baudrate are saved in ~/.dl24.cfg (or other name, where filename is derived from the command by stripping the .py suffix and prefixing a home directory and a dot). This variability allows to use several symlinks for different power supplies simultaneously used, eg. as dl24a, dl24b,...

The configfile template can be generated on demand by command CFGFILE.

Directly, the devices may be specified as TCP=<host>[:port] or PORT=/dev/ttyUSBx@baudrate, eg. TCP=10.0.1.15:8888 or PORT=/dev/rfcomm0 or PORT=/dev/ttyUSB1 (default speed is 9600, cannot be changed).

The PORT directive, both in command and in config, also supports the URL form.

For /dev/rfcomm devices used with Bluetooth, a wait directive is needed. The port takes its precious time to initialize, and waiting for first incoming data packet prevents initial timeouts.

commands

The script takes a sequence of commands from commandline, separated by spaces. Each command is a single token, optionally containing separator characters.

The commands can be a fixed string (STATE, QV, ...) or a prefix with value, or value with suffix (12.5A, SLEEP1.5, QVCUT...)

Q-commands can be used to directly access the measured or set values:

settings

The load current and voltage cutoff can be set with suffix-based commands. For the value of 1.23, the commands are

Voltage cutoff does not support relative values, absolute shall be used.

miniscripts

The commands are executed in order.

loops

The LOOP: statement can be used for repeating of commands. The subsequent command set is repeated forever, or for specified number of times.

stdin

The commands can be sent from another script, via stdin. The STDIN statement has to be the last on the command line, everything after it is ignored.

data on one line

The LINE command sets the separator character between Q-values from default newline to a space. Groups of values then can be sent as single lines.

connection persistence

The connection to the port is opened when first needed, then kept open until the process closes.

In some cases this may be detrimental to reliability (connection fail crashes the process). Running it anew each time may be beneficial then.

verbosity

To see the port/socket opening/closing, and the bus transactions dumped in hex, use VERB as the first command.

./dl24.py verb:pc state
CONFIGFILE:filename: /root/.dl24.cfg
CONFIGFILE:FAIL: [Errno 2] No such file or directory: '/root/.dl24.cfg'
SERPORT:connecting to /dev/rfcomm0 @ 9600
SERPORT:connected
waiting for incoming data
RECV: ff:55:01:02:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:17:00:00:00:04:3c:00:00:00:00:1e
SEND: b1:b2:10:00:00:b6
RECV: ca:cb:00:00:01:ce:cf
SEND: b1:b2:11:00:00:b6
RECV: ca:cb:00:00:00:ce:cf
SEND: b1:b2:12:00:00:b6
RECV: ca:cb:00:00:00:ce:cf
SEND: b1:b2:14:00:00:b6
RECV: ca:cb:00:00:00:ce:cf
SEND: b1:b2:15:00:00:b6
RECV: ca:cb:00:00:00:ce:cf
SEND: b1:b2:17:00:00:b6
RECV: ca:cb:00:00:63:ce:cf
SEND: b1:b2:18:00:00:b6
RECV: ca:cb:00:00:00:ce:cf
SEND: b1:b2:16:00:00:b6
RECV: ca:cb:00:00:17:ce:cf
SERPORT:closed

temperatures

The board has a connector for an external NTC probe temperature. The firmware does not support querying it as of late 2023.

autoconfiguration

There is no way to query the specific device type. There is a hint in the protocol, the ADU field in the status packet. It can have different values describing the packet format, the field meanings; 1 is for AC sensors, 2 for DC sensors, 3 for USB DC sensors.

The TYPE command will show this value.

DT24 devices are of type 2.

debug

The verbose mode, VERB, provides access to several kinds of data:

protocol reverse engineering aids

For understanding the current, and checking the future. Best used with VERB:PCM to see the response.

Example of RAWSEND to elicit response from a UM34C power monitor (protocol (described at Sigrok wiki unsupported by this software, hence the discard: messages on the response). 0xF0 requests the data packet.

CMD: VERB:PCM
CMD: RAWSEND:F0
SEND: f0
RECV: 0d:4c:01:f8:00:a5:00:00:03:3f:00:18:00:4c:00:00
discard: 0d 4c 01 f8 00 a5 00 00 03 3f 00 18 00 4c 00 00
RECV: 00:00:21:6f:00:00:a7:a9:00:01:70:0b:00:07:34:e2:00:01:86:9f:00:0c:2c:22:00:00:07:3d:00:00:22:e2:00:00:00:00:00:00:00:00:00:00:00:00
discard: 00 00 21 6f 00 00 a7 a9 00 01 70 0b 00 07 34 e2 00 01 86 9f 00 0c 2c 22 00 00 07 3d 00 00 22 e2 00 00 00 00 00 00 00 00 00 00 00 00
RECV: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01:00:00:00:08:00:00:04:2c:00:00:14:d4:00:00:4d:ef:00:01:87:d9:00:75:00:75:00:08:00:00:21:6f
discard: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 08 00 00 04 2c 00 00 14 d4 00 00 4d ef 00 01 87 d9 00 75 00 75 00 08 00 00 21 6f
RECV: 00:00:a7:a9:00:02:00:01:6a:41:00:01:00:00:00:04:00:00:01:31:00:00:97:07
discard: 00 00 a7 a9 00 02 00 01 6a 41 00 01 00 00 00 04 00 00 01 31 00 00 97 07
REPLY TIMEOUT


Files


TODO


If you have any comments or questions about the topic, please let me know here:
Your name:
Your email:
Spambait
Leave this empty!
Only spambots enter stuff here.
Feedback: