-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathidx.html
642 lines (599 loc) · 38.9 KB
/
idx.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="pragma" content="no-cache; charset=utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DL24.py, python control for DL24P and other Atorch artificial loads</title>
<style type="text/css">
body {background-color:#FFFFDD}
//td {vertical-align:top;padding:0px;margin:0px}
p {text-align:justify;margin-bottom:0px}
td.gchord {font-size:75%;font-weight:bold;padding:0px;margin:0px;padding-top:0px;padding-right:3px;text-align:left;font-family:verdana,arial;color:#888888;position:relative;top:3px}
td.gtxt {text-align:left}
.dettitle {border-bottom:1px lightgray dashed}
.dettitle2 {border-bottom:1px lightgray dashed}
h2 {margin-top:20px; background-color:xgray}
h3 {background-color:xyellow;margin-top:30px;text-decoration:underline}
h4 {padding-left:0px;margin-left:0px;text-decoration:underline;color:#333333}
ul {margin-top:0px;padding-top:0px}
.ref {color:gray}
.gr {color:gray}
.grsm {color:gray;font-size:80%}
.err {color:red;font-weight:bold}
a {text-color:blue;text-decoration:underline}
a:HOVER {border-bottom:1px blue;color:red}
a.index {text-decoration:none}
a.index:HOVER {text-decoration:underline;color:red}
.preFile {background-color:lightgray;padding:0.5em}
td.imgthumb {vertical-align:top;padding:5px;font-size:80%}
img.ico {width:12px;height:12px;overflow:visible;position:relative;margin-top:-5px}
.imginc {max-width:100%;max-height:80vh}
.imginccap {text-align:left;padding-bottom:0.5em}
div.code {margin:0px;padding:0px;padding-left:30px;}
.code {font-family:courier,fixed;color:green;}
.cmd {font-family:courier,fixed;color:red;background-color:#FFEEDD;font-weight:bold;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;padding-top:0.5em;padding-bottom:0.5em}
.cmd::first-line {color:darkred;}
.cmd::before {content:'> ';}
.cmdresp {font-family:courier,fixed;color:blue;background-color:#EEEEFF;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.cmdresp::first-line {color:darkblue;}
.cmdresp::before {content:' ';}
.comm {font-family:courier,fixed;color:red;background-color:#FFEEDD;font-weight:bold;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.comm::first-line {color:darkred;}
.comm::before {content:'> ';}
.commresp {font-family:courier,fixed;color:blue;background-color:#EEEEFF;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.commresp::first-line {color:darkblue;}
.commresp::before {content:'< ';}
.bang {font-weight:bold;color:red}
// unsupported by everything except apple, so far
//@media screen and (inverted-colors: inverted) {
//.cmd {background-color:#0000CC;color:lightblue;}
//.cmd::first-line: {color:blue}
//.cmdresp {background-color:#CC0000;color:lightred}
//.cmdresp::first-line: {color:red}
//}
@media print{
body {font-size:80%}
.noprint {display:none;visibility:hidden}
.xnopbr {page-break-inside:avoid}
td.gchord: {color:black}
.nopbr {}
.preFile {background-color:white;border:1px dotted black}
}
</style>
<meta property="og:title" content="DL24.py, python control for DL24P and other Atorch artificial loads" />
<meta property="og:type" content="website" />
<meta property="og:x-url" content="http://:" />
<meta property="og:description" content="software for control of Atorch DL24P artificial load and some others" />
<meta property="og:image" content="http://thumb.ATorchDL24P-adhoc.jpg" />
</head>
<body>
<h1>DL24.py, python control for DL24P and other Atorch artificial loads</h1><hr class="noprint" /><div class="noprint"><img src="thumb.ATorchDL24P-adhoc.jpg" width="320" height="427" align="right" style="padding-left:20px" />
</a>
<a class="index indexlev2" href="#Why" title="">Why</a><br /><a class="index indexlev2" href="#Hardwaredescription" title="Hardware description">Hardware description</a><br /> <small><a class="index indexlev3" href="#loadmodes" title="Hardware description.load modes">load modes</a></small><br /> <small><a class="index indexlev3" href="#hardwarearchitecture" title="Hardware description.hardware architecture">hardware architecture</a></small><br /> <small><a class="index indexlev4" href="#connectors" title="Hardware description.hardware architecture.connectors">connectors</a></small><br /> <small><a class="index indexlev4" href="#buttons" title="Hardware description.hardware architecture.buttons">buttons</a></small><br /><a class="index indexlev2" href="#How" title="How">How</a><br /> <small><a class="index indexlev3" href="#dependencies" title="How.dependencies">dependencies</a></small><br /> <small><a class="index indexlev3" href="#protocol" title="How.protocol">protocol</a></small><br /> <small><a class="index indexlev4" href="#PX100nbspprotocol" title="How.protocol.PX100 protocol">PX100 protocol</a></small><br /> <small><a class="index indexlev4" href="#Atorchprotocol" title="How.protocol."Atorch" protocol">"Atorch" protocol</a></small><br /> <small><a class="index indexlev4" href="#transactionexamples" title="How.protocol.transaction examples">transaction examples</a></small><br /><a class="index indexlev2" href="#Usage" title="Usage">Usage</a><br /> <small><a class="index indexlev3" href="#hardwareconfiguration" title="Usage.hardware configuration">hardware configuration</a></small><br /> <small><a class="index indexlev3" href="#commands" title="Usage.commands">commands</a></small><br /> <small><a class="index indexlev3" href="#settings" title="Usage.settings">settings</a></small><br /> <small><a class="index indexlev3" href="#miniscripts" title="Usage.miniscripts">miniscripts</a></small><br /> <small><a class="index indexlev4" href="#loops" title="Usage.miniscripts.loops">loops</a></small><br /> <small><a class="index indexlev4" href="#stdin" title="Usage.miniscripts.stdin">stdin</a></small><br /> <small><a class="index indexlev4" href="#dataononeline" title="Usage.miniscripts.data on one line">data on one line</a></small><br /> <small><a class="index indexlev4" href="#connectionpersistence" title="Usage.miniscripts.connection persistence">connection persistence</a></small><br /> <small><a class="index indexlev3" href="#verbosity" title="Usage.verbosity">verbosity</a></small><br /> <small><a class="index indexlev3" href="#temperatures" title="Usage.temperatures">temperatures</a></small><br /> <small><a class="index indexlev3" href="#autoconfiguration" title="Usage.autoconfiguration">autoconfiguration</a></small><br /> <small><a class="index indexlev3" href="#debug" title="Usage.debug">debug</a></small><br /> <small><a class="index indexlev4" href="#protocolreverseengineeringaids" title="Usage.debug.protocol reverse engineering aids">protocol reverse engineering aids</a></small><br /><a class="index indexlev2" href="#Files" title="Files">Files</a><br /><a class="index indexlev2" href="#TODO" title="TODO">TODO</a><br /></div><hr /><a name="Why"></a><h2> Why
</h2>
<p>
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.
</p>
<p>
There is a fragmentary documentation of the protocol online, all over the Internet and over various
code implementations of varying completeness.
</p>
<p>
The device communicates over a standard UART at 9600 bps, no parity, 1 stopbit (the most common setting),
using a custom packet-based protocol.
</p>
<p>
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
<a class="P" href="https://www.improwis.com/projects/hw_SerialOverTCP" title="local project" target="_blank">serial-over-TCP</a> ("TasmoCOM") solution was chosen, leveraging ESP8266
and <a class="w" href="https://en.wikipedia.org/wiki/Tasmota" title="Wikipedia link: Tasmota" target="_blank">Tasmota</a>, a proven cheap and opensource approach.
</p>
<p>
The code is a variant on the control system for <a class="P" href="https://www.improwis.com/projects/sw_rd60" title="local project" target="_blank">RD60</a>, Riden RD60xx and RK60xx power supplies.
</p>
<p>
Tested with:
<ul><li> DL24P
</li></ul></p>
<hr /><a name="Hardwaredescription"></a><h2> Hardware description
</h2>
<a name="loadmodes"></a><h3> load modes
</h3>
<p>
The device nominally supports several different load modes:
<ul><li> CC - constant current, sinking preset current despite input voltage fluctuations
</li><li> CR - constant resistance, behaving like a preset-value resistor, decreasing load with falling voltage
</li><li> CP - constant power, increasing load with falling voltage
</li><li> CV - constant voltage, maintaining voltage over the load
</li></ul></p>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<a name="hardwarearchitecture"></a><h3> hardware architecture
</h3>
<ul><li> <a class="a" href="DL24P-loadtester-schematic.pdf" title="local link: DL24P-loadtester-schematic.pdf" target="_blank">schematics (PDF)</a> (thanks to Someone Unknown somewhere on the Internet)
</li></ul><p>
The device is built around several chips:
<ul><li> control, user interface
</li><ul><li> HC32F030E8PA, Arm Cortex M0+ microcontroller, 64k flash/8k RAM (possibly, chip top is sanded off)
</li><li> color TFT LCD SPI display
</li></ul></ul></p>
<ul><li> communication
</li><ul><li> CH340G USB-UART converter, non-isolated
</li><li> 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
</li></ul></ul><ul><li> data acquisition
</li><ul><li> RN8209C, a utility smart meter power consumption integrator
</li><ul><li> three sigma-delta ADCs, fully differential
</li><li> read via internal UART at fixed 4800 bps
</li><ul><li> current sensing resistor on channel A, using internal amplifier
</li><li> voltage sensing on channel C, using resistive divider
</li><li> external 10k NTC as temperature probe on channel B
</li></ul></ul></ul></ul><ul><li> power control
</li><ul><li> two LM321 in SOT23-5 case marked A63A
</li><li> STPS41H100CG, double Schottky diode in series with the MOSFET, to protect it from reverse load
</li><li> IRFP260, a power N-MOSFET
</li></ul></ul><p>
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.
</p>
<p>
The UART has pins available near the Bluetooth chip, left to right:
<ul><li> GND (bluetooth chip pin 3)
</li><li> Rx (bluetooth chip Tx, pin 8)
</li><li> Tx (bluetooth chip Rx, pin 7)
</li><li> 3.3V (bluetooth chip pin 1)
</li></ul>This is a tentative place to hook up the wifi serial module.
</p>
<a name="connectors"></a><h4> connectors
</h4>
<p>
On the left side there is a 4-pin screw clamp, for attaching source (outer pins) and source sensing (inner pins).
Either use a <a class="w" href="https://en.wikipedia.org/wiki/Kelvin_connection" title="Wikipedia link: Kelvin connection" target="_blank">Kelvin connection</a> or connect pins 1 to 2 and 3 to 4 and neglect the (often significant) voltage drop on the cables.
</p>
<p>
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.
</p>
<p>
On the right side there is also the microUSB connector with USB-UART CH340G interface.
</p>
<p>
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).
</p>
<a name="buttons"></a><h4> buttons
</h4>
<p>
The unit has four buttons in a diamond layout.
<ul><li> top: SETTING
</li><ul><li> short press selects next item (cursor in the Is (set current) field, fields in setting mode
</li><li> long press allows selecting mode and accessing other variables - Vcut, timer...
</li></ul><li> left: MINUS
</li><ul><li> decreases value under cursor
</li></ul><li> right: PLUS
</li><ul><li> increases value under cursor
</li><li> long press of MINUS and PLUS together
</li></ul><li> bottom: START
</li><ul><li> short press switches the load on or off
</li><li> long press in OFF mode accesses settings menu (language, calibration, power limit...)
</li></ul></ul></p>
<hr /><a name="How"></a><h2> How
</h2>
<p>
<span class="code">dl24.py</span>, 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.
</p>
<p>
The software defines a hierarchy of classes:
<ul><li> <span class="code">class LowLevelSerPort</span> - for wired /dev/ttyX ports or full virtual ports
</li><li> <span class="code">class LowLevelTcpPort</span> - for raw TCP sockets, TasmoCOM style
</li><li> <span class="code">class Instr_Atorch</span> - functions specific for the DL24P and other Atorch devices, protocol, commands
</li><li> <span class="code">class PowerLoad</span> - command interpreter, configfile reader
</li></ul></p>
<a name="dependencies"></a><h3> dependencies
</h3>
<p>
The software tries to minimize dependencies.
</p>
<p>
The mandatory ones, and mostly standard ones, are:
<ul><li> <span class="code">socket</span> (for TCP communication)
</li><li> <span class="code">time</span> (for sleep)
</li><li> <span class="code">select</span> (for nonblocking stdin reads)
</li><li> <span class="code">struct</span> (pack/unpack, for conversion of packets to/from byte stream)
</li></ul>The nonmandatory, imported only as needed (so the process would run when a missing dependency is not required), are:
<ul><li> <span class="code">serial</span> (pyserial, for serial ports)
</li><li> <span class="code">datetime</span> (for date/time settings)
</li><li> <span class="code">json</span> (for JSON format output)
</li></ul></p>
<a name="protocol"></a><h3> protocol
</h3>
<p>
The device communicates over a bidirectional serial stream. There seem to be two different protocols, mixed together:
<ul><li> PX100 or PX-100, older, with fixed prefix and suffix and a prayer for data integrity
</li><li> a newer one, let's call it "Atorch", with fixed prefix and a checksum
</li></ul></p>
<a name="PX100nbspprotocol"></a><h4> PX100 protocol
</h4>
<p>
Challenge-response, master-slave protocol. The device listens and only reacts to the data sent.
<ul><li> <a class="a" href="https://github.com/misdoro/Electronic_load_px100/blob/master/protocol_PX-100_2_70.md" title="remote link: https://github.com/misdoro/Electronic_load_px100/blob/master/protocol_PX-100_2_70.md" target="_blank">https://github.com/misdoro/Electronic_load_px100/blob/master/protocol_PX-100_2_70.md</a>
</li></ul></p>
<pre class=""> 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.
</pre><a name="Atorchprotocol"></a><h4> "Atorch" protocol
</h4>
<p>
More modern protocol, combining fixed-format status updates in one-second intervals and challenge-response commands
<ul><li> <a class="a" href="https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md" title="remote link: https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md" target="_blank">https://github.com/devanlai/webvoltmeter/blob/master/REVERSE.md</a>
</li><li> <a class="a" href="https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md" title="remote link: https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md" target="_blank">https://github.com/syssi/esphome-atorch-dl24/blob/main/docs/protocol-design.md</a>
</li><li> <a class="a" href="https://werner.rothschopf.net/microcontroller/202204_atorch_dt24hd_power_sensor_en.htm" title="remote link: https://werner.rothschopf.net/microcontroller/202204_atorch_dt24hd_power_sensor_en.htm" target="_blank">https://werner.rothschopf.net/microcontroller/202204_atorch_dt24hd_power_sensor_en.htm</a> - incl. parser decompiled from app
</li><li> <a class="a" href="https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P" title="remote link: https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P" target="_blank">https://www.ordinoscope.net/index.php/Electronique/Hardware/Outils/Atorch/DL24P</a>
</li></ul></p>
<p>
The packets have a fixed overall structure with variable length:
<ul><li> <span class="code">0xFF 0x55</span> - a fixed prefix, magic number
</li><li> <span class="code">type</span> - packet type
</li><ul><li> <span class="code">0x01</span> - periodic message, slave to master, 36 bytes total
</li><li> <span class="code">0x02</span> - reply to request, slave to master, 8 bytes total
</li><li> <span class="code">0x11</span> - request, master to slave, 10 bytes total
</li></ul><li> <span class="code">ADU</span> - device type
</li><ul><li> <span class="code">0x01</span> - AC power consumption meter
</li><li> <span class="code">0x02</span> - DC power consumption meter or artificial load; use for DL24
</li><li> <span class="code">0x03</span> - DC power consumption meter for USB power analyzers/monitors
</li></ul><li> <span class="code">payload</span> - variable length and content
</li><ul><li> type 0x01: 31 bytes
</li><li> type 0x02: 3 bytes
</li><li> type 0x03: 5 bytes
</li></ul><li> <span class="code">checksum</span> - one byte, sum of bytes from (incl.) type to end of payload
</li><ul><li> byte by byte entire packet minus first two and one last bytes, AND 0xFF, XOR 0x44
</li><li> use result for outgoing requests, check last byte for match for incoming messages
</li></ul></ul></p>
<pre class=""> 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
</pre><a name="transactionexamples"></a><h4> transaction examples
</h4>
<p>
using protocol reverse engineering commands with <span class="code">VERB:CM</span>
<pre class=""> 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
</pre></p>
<hr /><a name="Usage"></a><h2> Usage
</h2>
<pre class="preFile">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.
</pre><a name="hardwareconfiguration"></a><h3> hardware configuration
</h3>
<p>
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,...
</p>
<p>
The configfile template can be generated on demand by command <span class="code">CFGFILE</span>.
</p>
<p>
Directly, the devices may be specified as <span class="code">TCP=<host>[:port] </span> or <span class="code">PORT=/dev/ttyUSBx@baudrate</span>,
eg. <span class="code">TCP=10.0.1.15:8888</span> or <span class="code">PORT=/dev/rfcomm0</span> or <span class="code">PORT=/dev/ttyUSB1</span> (default speed is 9600, cannot be changed).
</p>
<p>
The PORT directive, both in command and in config, also supports the <a class="a" href="https://pyserial.readthedocs.io/en/latest/url_handlers.html" title="remote link: https://pyserial.readthedocs.io/en/latest/url_handlers.html" target="_blank">URL form</a>.
</p>
<p>
For <span class="code">/dev/rfcomm</span> devices used with Bluetooth, a <a class="w" href="https://en.wikipedia.org/wiki/wait" title="Wikipedia link: wait" target="_blank">wait</a> directive is needed. The port takes its
precious time to initialize, and waiting for first incoming data packet prevents initial timeouts.
</p>
<a name="commands"></a><h3> commands
</h3>
<p>
The script takes a sequence of commands from commandline, separated by spaces. Each command is a single token,
optionally containing separator characters.
</p>
<p>
The commands can be a fixed string (<span class="code">STATE</span>, <span class="code">QV</span>, ...) or a prefix with value, or value with suffix (12.5<span class="code">A</span>,
<span class="code">SLEEP</span>1.5, <span class="code">Q</span>VCUT...)
</p>
<p>
Q-commands can be used to directly access the measured or set values:
<ul><li> <span class="code">QV</span>, <span class="code">QA</span> - for querying output voltage/amperage
</li><li> <span class="code">QMV</span>, <span class="code">QMA</span> - same, but integer value in millivolts/milliamps instead of float, for bash comparisons
</li></ul></p>
<a name="settings"></a><h3> settings
</h3>
<p>
The load current and voltage cutoff can be set with suffix-based commands.
For the value of 1.23, the commands are
<ul><li> <span class="code">1.23A</span> - set load current
</li><li> <span class="code">1230MA</span> - set load current in milliamps
</li><li> <span class="code">1.23VCUT</span> - set voltage cutoff
</li><li> <span class="code">+1.23A</span> - increase load current
</li><li> <span class="code">-1.23A</span> - decrease load current
</li><li> <span class="code">+1230MA</span> - increase load current in milliamps
</li></ul></p>
<p>
Voltage cutoff does not support relative values, absolute shall be used.
</p>
<a name="miniscripts"></a><h3> miniscripts
</h3>
<p>
The commands are executed in order.
</p>
<ul><li> set voltage cutoff and current, enable output
</li><ul><li> <span class="code">dl24.py 10.5vcut 550ma on</span>
</li></ul><li> toggle output, wait half second, show state
</li><ul><li> <span class="code">dl24.py toggle sleep0.5 state</span>
</li></ul><li> 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
</li><ul><li> <span class="code">dl24.py on 5a sleep1 +1a sleep1 +2a sleep0.5 state off</span>
</li></ul><li> show input voltage and current
</li><ul><li> <span class="code">dl24.py qv qa</span>
</li></ul><li> show input voltage in millivolts and current in milliamps, space-separated
</li><ul><li> <span class="code">dl24.py qmv qma | tr '\n' ' '</span>
</li></ul><li> disable output, set cutoff voltage and current, enable output
</li><ul><li> <span class="code">dl24.py off 4.9vcut 1250ma on</span>
</li></ul></ul><a name="loops"></a><h4> loops
</h4>
<p>
The <span class="code">LOOP:</span> statement can be used for repeating of commands. The subsequent command set is repeated forever, or for specified number of times.
</p>
<ul><li> show status in JSON format, forever
</li><ul><li> <span class="code">dl24.py loop: jstate</span>
</li></ul><li> ramp current by 20mA over time, from 0 to 1A, watch status with timestamps:
</li><ul><li> <span class="code">dl24.py 0a on loop:50 +20ma sleep1 stat:jt</span>
</li></ul></ul><a name="stdin"></a><h4> stdin
</h4>
<p>
The commands can be sent from another script, via stdin. The <span class="code">STDIN</span> statement has to be the last on the command line, everything after it is ignored.
<ul><li> enable output, take file with currents, send in one per second, then disable output
</li><ul><li> <span class="code">cat file.txt | while read x; do echo $x; sleep 1; done | ./dl24.py on stdin; ./dl24.py off</span>
</li></ul></ul></p>
<a name="dataononeline"></a><h4> data on one line
</h4>
<p>
The <span class="code">LINE</span> command sets the separator character between Q-values from default newline to a space. Groups of values then can be sent as single lines.
<ul><li> check every 5 seconds, send millivolts, milliamps, integrated amp-hours and watt-hours
</li><ul><li> <span class="code">dl24.py line loop: qmv qma qah qwh sleep5</span>
</li></ul></ul></p>
<a name="connectionpersistence"></a><h4> connection persistence
</h4>
<p>
The connection to the port is opened when first needed, then kept open until the process closes.
</p>
<p>
In some cases this may be detrimental to reliability (connection fail crashes the process). Running it anew each time may be beneficial then.
</p>
<a name="verbosity"></a><h3> verbosity
</h3>
<p>
To see the port/socket opening/closing, and the bus transactions dumped in hex, use <span class="code">VERB</span> as the first command.
</p>
<div class="cmd">./dl24.py verb:pc state</div><pre class="">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
</pre><a name="temperatures"></a><h3> temperatures
</h3>
<p>
The board has a connector for an external NTC probe temperature. The firmware does not support querying it as of late 2023.
</p>
<a name="autoconfiguration"></a><h3> autoconfiguration
</h3>
<p>
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; <span class="code">1</span> is for AC sensors, <span class="code">2</span> for DC sensors, <span class="code">3</span> for USB DC sensors.
</p>
<p>
The <span class="code">TYPE</span> command will show this value.
</p>
<p>
DT24 devices are of type 2.
</p>
<a name="debug"></a><h3> debug
</h3>
<p>
The verbose mode, <span class="code">VERB</span>, provides access to several kinds of data:
<ul><li> verb:<span class="code">P</span> for port-related behavior (open/close)
</li><li> verb:<span class="code">C</span> for communication data
</li><li> verb:<span class="code">D</span> for data flow (less verbose comm)
</li><li> verb:<span class="code">M</span> for coMmands
</li></ul></p>
<a name="protocolreverseengineeringaids"></a><h4> protocol reverse engineering aids
</h4>
<p>
For understanding the current, and checking the future. Best used with <span class="code">VERB:PCM</span> to see the response.
<ul><li> <span class="code">RAWPROTO:XXXXXXXXXX</span> - send raw bytes via Atorch protocol, command + 4 payloads in hex, auto-pads with zeroes
</li><li> <span class="code">RAWPX100:XXXXXX</span> - send raw bytes via PX100 protocol, command + 2 payloads in hex, auto-pads with zeroes
</li><li> <span class="code">RAWSEND:XX....</span> - send raw bytes directly to port
</li><li> <span class="code">NORETRY</span> - do not retry timeouted commands, for PX100 protocol to speed up reaction and reduce clutter
</li></ul></p>
<p>
Example of <span class="code">RAWSEND</span> to elicit response from a UM34C power monitor (protocol (described at <a class="a" href="https://sigrok.org/wiki/RDTech_UM_series" title="remote link: https://sigrok.org/wiki/RDTech_UM_series" target="_blank">Sigrok wiki</a>
unsupported by this software, hence the discard: messages on the response). 0xF0 requests the data packet.
<pre class="">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
</pre></p>
<hr /><a name="Files"></a><h2> Files
</h2>
<ul><li> <b><a class="F" href="dl24.py" title="local file">dl24.py</a></b> - code itself
</li></ul><hr /><a name="TODO"></a><h2> TODO
</h2>
<ul><li> better windows compatibility
</li><li> tests on some USB power meters
</li><li> better pictures
</li><li> <a class="w" href="https://en.wikipedia.org/wiki/Standard_Commands_for_Programmable_Instruments" title="Wikipedia link: Standard Commands for Programmable Instruments" target="_blank">SCPI</a> emulation/gateway
</li><li> hardware mods
</li><ul><li> more robust MOSFET, reverse-protection diodes
</li><li> MOSFET gate protection with zener/transil
</li><li> isolated 5-12v converter for powering from standard 5v usb, galvanically isolated from the rest
</li><li> maybe galv isolation of the USB, like RD60xx have; unlike that one, a pair of lousy optocouplers will do here as 9k6 is slow
</li></ul></ul><!-- feedback -->
<!-- /feedback -->
</body>
</html>