{"id":19824706,"url":"https://github.com/tshaddack/dl24","last_synced_at":"2026-06-11T17:31:53.839Z","repository":{"id":245710109,"uuid":"819024527","full_name":"tshaddack/dl24","owner":"tshaddack","description":"DL24.py, python control for DL24P and other Atorch artificial loads","archived":false,"fork":false,"pushed_at":"2024-06-23T15:05:49.000Z","size":36,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-28T20:43:19.004Z","etag":null,"topics":["artificial-load","atorch","dl24","power-load","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tshaddack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-23T15:03:43.000Z","updated_at":"2025-01-01T19:55:58.000Z","dependencies_parsed_at":"2024-06-23T16:26:06.590Z","dependency_job_id":null,"html_url":"https://github.com/tshaddack/dl24","commit_stats":null,"previous_names":["tshaddack/dl24"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tshaddack/dl24","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tshaddack%2Fdl24","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tshaddack%2Fdl24/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tshaddack%2Fdl24/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tshaddack%2Fdl24/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tshaddack","download_url":"https://codeload.github.com/tshaddack/dl24/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tshaddack%2Fdl24/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34211061,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artificial-load","atorch","dl24","power-load","python"],"created_at":"2024-11-12T11:05:35.011Z","updated_at":"2026-06-11T17:31:53.811Z","avatar_url":"https://github.com/tshaddack.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Autogenerated from [https://www.improwis.com/projects/sw_dl24/](https://www.improwis.com/projects/sw_dl24/)\n\n\n\n\n\n\nDL24.py, python control for DL24P and other Atorch artificial loads\n\n\n\n\n\n\n\n\nDL24.py, python control for DL24P and other Atorch artificial loads\n===================================================================\n\n\n\n---\n\n![](thumb.ATorchDL24P-adhoc.jpg)\n\n[Why](#Why \"#Why\")  \n[Hardware description](#Hardwaredescription \"Hardware description\")  \n      [load modes](#loadmodes \"Hardware description.load modes\")  \n      [hardware architecture](#hardwarearchitecture \"Hardware description.hardware architecture\")  \n            [connectors](#connectors \"Hardware description.hardware architecture.connectors\")  \n            [buttons](#buttons \"Hardware description.hardware architecture.buttons\")  \n[How](#How \"How\")  \n      [dependencies](#dependencies \"How.dependencies\")  \n      [protocol](#protocol \"How.protocol\")  \n            [PX100 protocol](#PX100nbspprotocol \"How.protocol.PX100 protocol\")  \n            [\"Atorch\" protocol](#Atorchprotocol \"How.protocol.\")  \n            [transaction examples](#transactionexamples \"How.protocol.transaction examples\")  \n[Usage](#Usage \"Usage\")  \n      [hardware configuration](#hardwareconfiguration \"Usage.hardware configuration\")  \n      [commands](#commands \"Usage.commands\")  \n      [settings](#settings \"Usage.settings\")  \n      [miniscripts](#miniscripts \"Usage.miniscripts\")  \n            [loops](#loops \"Usage.miniscripts.loops\")  \n            [stdin](#stdin \"Usage.miniscripts.stdin\")  \n            [data on one line](#dataononeline \"Usage.miniscripts.data on one line\")  \n            [connection persistence](#connectionpersistence \"Usage.miniscripts.connection persistence\")  \n      [verbosity](#verbosity \"Usage.verbosity\")  \n      [temperatures](#temperatures \"Usage.temperatures\")  \n      [autoconfiguration](#autoconfiguration \"Usage.autoconfiguration\")  \n      [debug](#debug \"Usage.debug\")  \n            [protocol reverse engineering aids](#protocolreverseengineeringaids \"Usage.debug.protocol reverse engineering aids\")  \n[Files](#Files \"Files\")  \n[TODO](#TODO \"TODO\")  \n\n\n---\n\nWhy\n---\n\n\n\nIt was necessary to control an Atorch DL24P constant-current load for some lab automation purposes.\nThe stock software was useless for the purpose, surprise surprise.\n\n\n\n\nThere is a fragmentary documentation of the protocol online, all over the Internet and over various\ncode implementations of varying completeness.\n\n\n\n\nThe device communicates over a standard UART at 9600 bps, no parity, 1 stopbit (the most common setting),\nusing a custom packet-based protocol.\n\n\n\n\nThe serial bus can be accessed over either a USB-serial converter based on CH340G chip (warning: no\ngalvanic isolation!), or via Bluetooth serial interface, using a /dev/rfcommX port. Addition of\nwifi-accessible serial interface is also possible, using eg. the expedient plain\n[serial-over-TCP](https://www.improwis.com/projects/hw_SerialOverTCP \"local project\") (\"TasmoCOM\") solution was chosen, leveraging ESP8266\nand [Tasmota](https://en.wikipedia.org/wiki/Tasmota \"Wikipedia link: Tasmota\"), a proven cheap and opensource approach.\n\n\n\n\nThe code is a variant on the control system for [RD60](https://www.improwis.com/projects/sw_rd60 \"local project\"), Riden RD60xx and RK60xx power supplies.\n\n\n\n\nTested with:\n* DL24P\n\n\n\n\n\n---\n\nHardware description\n--------------------\n\n\n### load modes\n\n\n\nThe device nominally supports several different load modes:\n* CC - constant current, sinking preset current despite input voltage fluctuations\n* CR - constant resistance, behaving like a preset-value resistor, decreasing load with falling voltage\n* CP - constant power, increasing load with falling voltage\n* CV - constant voltage, maintaining voltage over the load\n\n\n\n\nOnly the CC mode is fully supported. The protocol does not allow selecting other modes, changing values for them,\nnor even querying what mode is set.\n\n\n\n\nThe hardware in its current (2023) version looks like just slightly modified AC/DC power consumption measuring\ndevice, with load control tacked on it. For sensing, separate dedicated load-measuring chips are used, and the\nmicrocontroller communicated with them via internal UART bus. The Rx/Tx comm is naturally abysmally slow, dooming\nany closed-loop regulation involving CPU to be abysmally unstable and often useless with more dynamic source.\n\n\n\n\nThe load itself is realized as a big MOSFET on an even bigger actively cooled heatsink, likely a surplus for\nolder CPUs. The MOSFET gate is fed with voltage from an op-amp, comparing signal from a current-sensing resistor\nwith a reference voltage coming from a RC-filtered PWM from the controller. This is a pretty good closed-loop\nregulation, bog-standard approach with minimal demands on the CPU; in a pinch, a potentiometer can be used\nfor setting the reference.\n\n\n\n\nThe advantage of using dedicated power consumption sensing chips is more reliable integration of the\nconsumed energy. Which is useful for the device's primary purpose - testing batteries. For this use,\nthe device has a voltage cutoff preset.\n\n\n\n### hardware architecture\n\n\n* [schematics (PDF)](DL24P-loadtester-schematic.pdf \"local link: DL24P-loadtester-schematic.pdf\") (thanks to Someone Unknown somewhere on the Internet)\n\n\nThe device is built around several chips:\n* control, user interface\n+ HC32F030E8PA, Arm Cortex M0+ microcontroller, 64k flash/8k RAM (possibly, chip top is sanded off)\n+ color TFT LCD SPI display\n\n\n\n* communication\n+ CH340G USB-UART converter, non-isolated\n+ bluetooth module, type can be JDY-23 (CC2541) or some SOIC8 single-chip Bluetooth-serial from JieLi, likely AC6329A or AC6328A, on the board on hand labeled BP05235-29A1\n* data acquisition\n+ RN8209C, a utility smart meter power consumption integrator\n- three sigma-delta ADCs, fully differential\n- read via internal UART at fixed 4800 bps\n* current sensing resistor on channel A, using internal amplifier\n* voltage sensing on channel C, using resistive divider\n* external 10k NTC as temperature probe on channel B\n* power control\n+ two LM321 in SOT23-5 case marked A63A\n+ STPS41H100CG, double Schottky diode in series with the MOSFET, to protect it from reverse load\n+ IRFP260, a power N-MOSFET\n\n\nThe MOSFET is a switching one, abused here in linear duty. Word goes along that some sellers use fake or reused ones,\nand this component dies often. Prepare to replace it.\n\n\n\n\nThe UART has pins available near the Bluetooth chip, left to right:\n* GND (bluetooth chip pin 3)\n* Rx (bluetooth chip Tx, pin 8)\n* Tx (bluetooth chip Rx, pin 7)\n* 3.3V (bluetooth chip pin 1)\n\nThis is a tentative place to hook up the wifi serial module.\n\n\n\n#### connectors\n\n\n\nOn the left side there is a 4-pin screw clamp, for attaching source (outer pins) and source sensing (inner pins).\nEither use a [Kelvin connection](https://en.wikipedia.org/wiki/Kelvin_connection \"Wikipedia link: Kelvin connection\") or connect pins 1 to 2 and 3 to 4 and neglect the (often significant) voltage drop on the cables.\n\n\n\n\nOn 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.\nAn adapter with a barrel jack and USB-mini, USB-micro and USB-C connector is often available.\n\n\n\n\nOn the right side there is also the microUSB connector with USB-UART CH340G interface.\n\n\n\n\nOn 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,\n3.3v linear regulator).\n\n\n\n#### buttons\n\n\n\nThe unit has four buttons in a diamond layout.\n* top: SETTING\n+ short press selects next item (cursor in the Is (set current) field, fields in setting mode\n+ long press allows selecting mode and accessing other variables - Vcut, timer...\n\n* left: MINUS\n+ decreases value under cursor\n\n* right: PLUS\n+ increases value under cursor\n+ long press of MINUS and PLUS together\n\n* bottom: START\n+ short press switches the load on or off\n+ long press in OFF mode accesses settings menu (language, calibration, power limit...)\n\n\n\n\n\n---\n\nHow\n---\n\n\n\ndl24.py, a python-based (for portability) script, was written. The software allows both\nusing a tty-style port and a raw TCP socket, with no fancy RFC2217 support. If the latter is needed, URI-style\npyserial syntax is available with the port.\n\n\n\n\nThe software defines a hierarchy of classes:\n* class LowLevelSerPort - for wired /dev/ttyX ports or full virtual ports\n* class LowLevelTcpPort - for raw TCP sockets, TasmoCOM style\n* class Instr\\_Atorch - functions specific for the DL24P and other Atorch devices, protocol, commands\n* class PowerLoad - command interpreter, configfile reader\n\n\n\n### dependencies\n\n\n\nThe software tries to minimize dependencies.\n\n\n\n\nThe mandatory ones, and mostly standard ones, are:\n* socket (for TCP communication)\n* time (for sleep)\n* select (for nonblocking stdin reads)\n* struct (pack/unpack, for conversion of packets to/from byte stream)\n\nThe nonmandatory, imported only as needed (so the process would run when a missing dependency is not required), are:\n* serial (pyserial, for serial ports)\n* datetime (for date/time settings)\n* json (for JSON format output)\n\n\n\n### protocol\n\n\n\nThe device communicates over a bidirectional serial stream. There seem to be two different protocols, mixed together:\n* PX100 or PX-100, older, with fixed prefix and suffix and a prayer for data integrity\n* a newer one, let's call it \"Atorch\", with fixed prefix and a checksum\n\n\n\n#### PX100 protocol\n\n\n\nChallenge-response, master-slave protocol. The device listens and only reacts to the data sent.\n* [https://github.com/misdoro/Electronic\\_load\\_px100/blob/master/protocol\\_PX-100\\_2\\_70.md](https://github.com/misdoro/Electronic_load_px100/blob/master/protocol_PX-100_2_70.md \"remote link: https://github.com/misdoro/Electronic_load_px100/blob/master/protocol_PX-100_2_70.md\")\n\n\n\n\n```\n request packet format:\n\n        0xB1 0xB2 [cmd] [d1] [d2] 0xB6\n on/off             01   xx   00       xx=01 for on, 00 for off\n set current        02   xx   yy       xx=integer, yy=decimal (00..99d)\n set cutoff v       03   xx   yy       \"\"\n set timeout        04   xx   yy       xxyy as unsigned int in seconds\n reset counters     05   00   00\n\n command response format: a single byte, 0x6F (PROTO_SHORTACK)\n\n query response:\n                  0xCA 0xCB [d1] [d2] [d3] 0xCE 0xCF\n             for cmd code\n load enabled      10        00   00   xx          xx=00 (off) or 01 (on)\n measured mV       11        xx   yy   zz          0xXXYYZZ, 24bit integer\n measured mA       12        xx   yy   zz\n timer value       13        hh   mm   ss\n cap mAh           14        xx   yy   zz\n cap mWh           15        xx   yy   zz\n mosfet 'c         16        xx   yy   zz\n preset current    17        xx   yy   zz          10s mA\n preset cutoff     18        xx   yy   zz          10s mV\n preset timer      19        hh   mm   ss\n\n [cmd] code ranges 0x0? for command (with short response) and query (with long 7-byte response)\n\n On invalid command there is no response, the command timeouts.\n\n```\n#### \"Atorch\" protocol\n\n\n\nMore modern protocol, combining fixed-format status updates in one-second intervals and challenge-response commands\n* [https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md](https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md \"remote link: https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md\")\n* [https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md](https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md \"remote link: https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md\")\n* [https://werner.rothschopf.net/microcontroller/202204\\_atorch\\_dt24hd\\_power\\_sensor\\_en.htm](https://werner.rothschopf.net/microcontroller/202204_atorch_dt24hd_power_sensor_en.htm \"remote link: https://werner.rothschopf.net/microcontroller/202204_atorch_dt24hd_power_sensor_en.htm\") - incl. parser decompiled from app\n* [https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P](https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P \"remote link: https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P\")\n\n\n\n\nThe packets have a fixed overall structure with variable length:\n* 0xFF 0x55 - a fixed prefix, magic number\n* type - packet type\n+ 0x01 - periodic message, slave to master, 36 bytes total\n+ 0x02 - reply to request, slave to master, 8 bytes total\n+ 0x11 - request, master to slave, 10 bytes total\n\n* ADU - device type\n+ 0x01 - AC power consumption meter\n+ 0x02 - DC power consumption meter or artificial load; use for DL24\n+ 0x03 - DC power consumption meter for USB power analyzers/monitors\n\n* payload - variable length and content\n+ type 0x01: 31 bytes\n+ type 0x02: 3 bytes\n+ type 0x03: 5 bytes\n\n* checksum - one byte, sum of bytes from (incl.) type to end of payload\n+ byte by byte entire packet minus first two and one last bytes, AND 0xFF, XOR 0x44\n+ use result for outgoing requests, check last byte for match for incoming messages\n\n\n\n\n```\n Atorch protocol, type 0x01: 1-per-second, 36-byte: (pfct=power factor, bk=backlight)\n                   x4               x8               xc               x10               x14               x18              x1c              x20\n                   4                8                12               16                20                24               28               32\n [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]\n [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]\n          t   01  -volt*0.1?-  -milliamps-  ---power---  ----energy-----   --price?--   -freq-   -pfct-   -temp-                   bk\n          t   02  -volt*0.1--  -milliamps-  -amphours--  ----energy-----   --price?--            -pfct-   -temp-  --hhhh---mm--ss  bk\n          t   03  -volt*0.1?-  -milliamps-  -amphours--  ----energy-----    usbd+   usbd-   -temp-   --hhhh---mm--ss  bk\n             ADU      0.1v       0.001a       0.01Ah\n\n\n type 0x02, reply:\n [FF][55][02] [val0][val1][val2][val3] [checksum]\n for a good command (0x32, button) the response is 01 01 00 00\n for a bad command (0x36) the response is 01 03 00 00\n 01 01 seems to be good command\n 01 03 seems to be unimplemented command\n\n sample push of ON/OFF button: (cmd=0x32, values=[0,0,0,0])\n SEND: ff:55:11:02: 32 :00:00:00:00 :01\n RECV: ff:55:02: 01:01:00:00 :40\n\n\n type 0x11, request:\n [FF][55][11][ADU] [cmd] [val0][val1][val2][val3] [checksum]  - val1 seems to be always 0x00\n\n sample requests, as by http://bukys.eu/project/powermon/start :\n\n   Commands for UD18 UD24 (USB)\n     WH reset            FF 55 11 03 01 00 00 00 00 51\n     AH reset            FF 55 11 03 02 00 00 00 00 52\n     TIME reset          FF 55 11 03 03 00 00 00 00 53\n     ALL reset           FF 55 11 03 05 00 00 00 00 5d\n     SETUP Button        FF 55 11 03 31 00 00 00 00 01\n     ENTER Button        FF 55 11 03 32 00 00 00 00 02\n     [+] Button          FF 55 11 03 33 00 00 00 00 03\n     [-] Button          FF 55 11 03 34 00 00 00 00 0C\n\n  Commands for S1-B (USB)\n     WH reset            FF 55 11 03 01 00 00 00 00 51\n     Internal relay      FF 55 11 03 02 00 00 00 00 52\n     TIME reset          FF 55 11 03 03 00 00 00 00 53\n\n```\n#### transaction examples\n\n\n\nusing protocol reverse engineering commands with VERB:CM\n\n```\n CMD: RAWPX100:30\n SEND: b1:b2:30:00:00:b6\n REPLY TIMEOUT\n SEND: b1:b2:30:00:00:b6\n REPLY TIMEOUT\n SEND: b1:b2:30:00:00:b6\n REPLY TIMEOUT\n\n CMD: RAWPX100:01\n SEND: b1:b2:01:00:00:b6\n RECV: 6f\n\n CMD: RAWPX100:10\n SEND: b1:b2:10:00:00:b6\n RECV: ca:cb:00:00:00:ce:cf\n\n CMD: RAWPROTO:32\n SEND: ff:55:11:02:32:00:00:00:00:01\n RECV: ff:55:02:01:01:00:00:40\n\n CMD: RAWPROTO:FF\n SEND: ff:55:11:02:ff:00:00:00:00:56\n RECV: ff:55:02:01:03:00:00:42\n\n```\n\n\n\n\n\n---\n\nUsage\n-----\n\n\n\n```\nAtorch DL24 artificial control\nUsage: ./dl24.py \u003ccommand\u003e [command]...\nCommands:\n\n  ON             enable output\n  OFF            disable output\n\n  nn.nnVCUT      set cutoff voltage\n  nn.nnMA        set output current\n  nn.nnA         set output current\n\n  QV             query actual voltage\n  QMV            query actual voltage, integer millivolts\n  QA             query actual current\n  QMA            query actual current, integer milliamps\n  QTI            query internal temperature\n  QVCUT          query cutoff voltage\n\n  QAH            query amp-hour counter\n  QMAH           query amp-hour counter in integer mAh\n  QWH            query watt-hour counter\n  QMWH           query watt-hour counter in integer mWh\n  RESET          reset energy counters\n\n  STATE[:opts]   print setting state in JSON format\n  STATEJ[:opts]  print setting state in JSON format, like opts=J\n          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\n  LISTEN[:opts[:count]]  listen to status reports, query data, handle stdin\n  LISTEN[:opts[:off]]    listen, until off\n          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\n\n  TCP=addr[:port]           set connection via TCP\n  PORT=/dev/ttyport[@baud]  set connection via serial port\n  WAIT           wait for communication from device\n  ROBUST         increase timeouts and retries\n  OFFOFF         switch output off on program exit\n  STOPOFF        stop loop on output off\n\n  STDIN          read commands from stdin\n  LOOP:[xx]      loop for xx time or endless if not specified\n  SLEEPxx        sleep for xx seconds\n  VERB[:opts]    list operations\n          opts:  P=port, C=communication, D=dataflow, M=commands\n  LINE           output the Q-queries as space-separated instead of newline-separated\n  TYPE           print detected device type\n  CFGFILE        generate config file template to stdout\n\n  RAWPROTO:xx[:xx:xx:xx:xx]   raw Atorch protocol send, cmd + 4 payloads\n  RAWPX100:xx[:xx:xx]         raw PX100 protocol send, cmd + 2 payloads\n  RAWSEND:xx[:xx:xx:...]      raw serial protocol data send\n  NORETRY                     do not retry timeouted commands\n\nFor volt and amp setting, prefixing the value with + or - marks it as relative, to be added/subtracted to the current value\nCommands are executed in sequence. Writes are cached and grouped together to minimize bus transactions.\nCommands are case-insensitive.\nCommand \"-\" forces a newline into output.\n\n```\n### hardware configuration\n\n\n\nThe host:port or serport:baudrate are saved in ~/.dl24.cfg (or other name, where filename is derived from\nthe command by stripping the .py suffix and prefixing a home directory and a dot). This variability allows\nto use several symlinks for different power supplies simultaneously used, eg. as dl24a, dl24b,...\n\n\n\n\nThe configfile template can be generated on demand by command CFGFILE.\n\n\n\n\nDirectly, the devices may be specified as TCP=\u003chost\u003e[:port]  or PORT=/dev/ttyUSBx@baudrate,\neg. TCP=10.0.1.15:8888 or PORT=/dev/rfcomm0 or PORT=/dev/ttyUSB1 (default speed is 9600, cannot be changed).\n\n\n\n\nThe PORT directive, both in command and in config, also supports the [URL form](https://pyserial.readthedocs.io/en/latest/url_handlers.html \"remote link: https://pyserial.readthedocs.io/en/latest/url_handlers.html\").\n\n\n\n\nFor /dev/rfcomm devices used with Bluetooth, a [wait](https://en.wikipedia.org/wiki/wait \"Wikipedia link: wait\") directive is needed. The port takes its\nprecious time to initialize, and waiting for first incoming data packet prevents initial timeouts.\n\n\n\n### commands\n\n\n\nThe script takes a sequence of commands from commandline, separated by spaces. Each command is a single token,\noptionally containing separator characters.\n\n\n\n\nThe commands can be a fixed string (STATE, QV, ...) or a prefix with value, or value with suffix (12.5A,\nSLEEP1.5, QVCUT...)\n\n\n\n\nQ-commands can be used to directly access the measured or set values:\n* QV, QA - for querying output voltage/amperage\n* QMV, QMA - same, but integer value in millivolts/milliamps instead of float, for bash comparisons\n\n\n\n### settings\n\n\n\nThe load current and voltage cutoff can be set with suffix-based commands.\nFor the value of 1.23, the commands are\n* 1.23A - set load current\n* 1230MA - set load current in milliamps\n* 1.23VCUT - set voltage cutoff\n* +1.23A - increase load current\n* -1.23A - decrease load current\n* +1230MA - increase load current in milliamps\n\n\n\n\nVoltage cutoff does not support relative values, absolute shall be used.\n\n\n\n### miniscripts\n\n\n\nThe commands are executed in order.\n\n\n\n* set voltage cutoff and current, enable output\n+ dl24.py 10.5vcut 550ma on\n\n* toggle output, wait half second, show state\n+ dl24.py toggle sleep0.5 state\n\n* set output to 5 amps and enable, wait a second, increase by an amo, wait a second, increase by another two amps, show state and power off\n+ dl24.py on 5a sleep1 +1a sleep1 +2a sleep0.5 state off\n\n* show input voltage and current\n+ dl24.py qv qa\n\n* show input voltage in millivolts and current in milliamps, space-separated\n+ dl24.py qmv qma | tr '\\n' ' '\n\n* disable output, set cutoff voltage and current, enable output\n+ dl24.py off 4.9vcut 1250ma on\n\n#### loops\n\n\n\nThe LOOP: statement can be used for repeating of commands. The subsequent command set is repeated forever, or for specified number of times.\n\n\n\n* show status in JSON format, forever\n+ dl24.py loop: jstate\n\n* ramp current by 20mA over time, from 0 to 1A, watch status with timestamps:\n+ dl24.py 0a on loop:50 +20ma sleep1 stat:jt\n\n#### stdin\n\n\n\nThe 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.\n* enable output, take file with currents, send in one per second, then disable output\n+ cat file.txt | while read x; do echo $x; sleep 1; done | ./dl24.py on stdin; ./dl24.py off\n\n\n\n#### data on one line\n\n\n\nThe 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.\n* check every 5 seconds, send millivolts, milliamps, integrated amp-hours and watt-hours\n+ dl24.py line loop: qmv qma qah qwh sleep5\n\n\n\n#### connection persistence\n\n\n\nThe connection to the port is opened when first needed, then kept open until the process closes.\n\n\n\n\nIn some cases this may be detrimental to reliability (connection fail crashes the process). Running it anew each time may be beneficial then.\n\n\n\n### verbosity\n\n\n\nTo see the port/socket opening/closing, and the bus transactions dumped in hex, use VERB as the first command.\n\n\n\n./dl24.py verb:pc state\n```\nCONFIGFILE:filename: /root/.dl24.cfg\nCONFIGFILE:FAIL: [Errno 2] No such file or directory: '/root/.dl24.cfg'\nSERPORT:connecting to /dev/rfcomm0 @ 9600\nSERPORT:connected\nwaiting for incoming data\nRECV: 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\nSEND: b1:b2:10:00:00:b6\nRECV: ca:cb:00:00:01:ce:cf\nSEND: b1:b2:11:00:00:b6\nRECV: ca:cb:00:00:00:ce:cf\nSEND: b1:b2:12:00:00:b6\nRECV: ca:cb:00:00:00:ce:cf\nSEND: b1:b2:14:00:00:b6\nRECV: ca:cb:00:00:00:ce:cf\nSEND: b1:b2:15:00:00:b6\nRECV: ca:cb:00:00:00:ce:cf\nSEND: b1:b2:17:00:00:b6\nRECV: ca:cb:00:00:63:ce:cf\nSEND: b1:b2:18:00:00:b6\nRECV: ca:cb:00:00:00:ce:cf\nSEND: b1:b2:16:00:00:b6\nRECV: ca:cb:00:00:17:ce:cf\nSERPORT:closed\n\n```\n### temperatures\n\n\n\nThe board has a connector for an external NTC probe temperature. The firmware does not support querying it as of late 2023.\n\n\n\n### autoconfiguration\n\n\n\nThere is no way to query the specific device type.\nThere is a hint in the protocol, the ADU field in the status packet. It can have different values describing the\npacket format, the field meanings; 1 is for AC sensors, 2 for DC sensors, 3 for USB DC sensors.\n\n\n\n\nThe TYPE command will show this value.\n\n\n\n\nDT24 devices are of type 2.\n\n\n\n### debug\n\n\n\nThe verbose mode, VERB, provides access to several kinds of data:\n* verb:P for port-related behavior (open/close)\n* verb:C for communication data\n* verb:D for data flow (less verbose comm)\n* verb:M for coMmands\n\n\n\n#### protocol reverse engineering aids\n\n\n\nFor understanding the current, and checking the future. Best used with VERB:PCM to see the response.\n* RAWPROTO:XXXXXXXXXX - send raw bytes via Atorch protocol, command + 4 payloads in hex, auto-pads with zeroes\n* RAWPX100:XXXXXX - send raw bytes via PX100 protocol, command + 2 payloads in hex, auto-pads with zeroes\n* RAWSEND:XX.... - send raw bytes directly to port\n* NORETRY - do not retry timeouted commands, for PX100 protocol to speed up reaction and reduce clutter\n\n\n\n\nExample of RAWSEND to elicit response from a UM34C power monitor (protocol (described at [Sigrok wiki](https://sigrok.org/wiki/RDTech_UM_series \"remote link: https://sigrok.org/wiki/RDTech_UM_series\")\nunsupported by this software, hence the discard: messages on the response). 0xF0 requests the data packet.\n\n```\nCMD: VERB:PCM\nCMD: RAWSEND:F0\nSEND: f0\nRECV: 0d:4c:01:f8:00:a5:00:00:03:3f:00:18:00:4c:00:00\ndiscard: 0d 4c 01 f8 00 a5 00 00 03 3f 00 18 00 4c 00 00\nRECV: 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\ndiscard: 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\nRECV: 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\ndiscard: 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\nRECV: 00:00:a7:a9:00:02:00:01:6a:41:00:01:00:00:00:04:00:00:01:31:00:00:97:07\ndiscard: 00 00 a7 a9 00 02 00 01 6a 41 00 01 00 00 00 04 00 00 01 31 00 00 97 07\nREPLY TIMEOUT\n\n```\n\n\n\n\n\n---\n\nFiles\n-----\n\n\n* **[dl24.py](dl24.py \"local file\")** - code itself\n\n\n\n---\n\nTODO\n----\n\n\n* better windows compatibility\n* tests on some USB power meters\n* better pictures\n* [SCPI](https://en.wikipedia.org/wiki/Standard_Commands_for_Programmable_Instruments \"Wikipedia link: Standard Commands for Programmable Instruments\") emulation/gateway\n* hardware mods\n+ more robust MOSFET, reverse-protection diodes\n+ MOSFET gate protection with zener/transil\n+ isolated 5-12v converter for powering from standard 5v usb, galvanically isolated from the rest\n+ maybe galv isolation of the USB, like RD60xx have; unlike that one, a pair of lousy optocouplers will do here as 9k6 is slow\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftshaddack%2Fdl24","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftshaddack%2Fdl24","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftshaddack%2Fdl24/lists"}