I wanted a programmable bench power supply that my Linux box could drive like any other service. A script sets 12 V, waits for the board to boot, logs the current every second and cuts the output if something shorts. The shopping part turned out to be the easy bit. The hard part is that “programmable” means four different things across the brands people actually buy, from SCPI over the network to Modbus over a USB serial chip to a protocol that only looks like SCPI.
So I picked the four supplies that come up in every maker and homelab thread: Siglent SPD3303X-E, Rigol DP832A, Riden RD6018 and Korad KA3005P. For each one I worked out how it talks to Linux, which Python library or CLI drives it, and what breaks first. I ran the control side in October 2026 on an Ubuntu 26.04.1 LTS VM called box2, with mbpoll, lxi-tools, PyVISA, the riden library and koradctl talking to simulators I built from each vendor’s documented protocol, and every output below comes from that box.
The four I’d buy, by how you’ll script them
Pick by the interface you want to script against first and by watts second, because a supply with the right protocol but no network port ends up tethered to one machine by a USB cable:
- Best overall: Siglent SPD3303X-E (around $460): two 32 V / 3.2 A channels plus a fixed third, LAN and USBTMC
- Best for precise logging: Rigol DP832A (around $620): 0.1 mV readback, LAN and RS232 standard, sigrok support
- Best for high current on a budget: Riden RD6018W kit (around $245): 60 V / 18 A over Modbus RTU, you assemble it
- Cheapest that scripts at all: Korad KA3005P (around $155): one 30 V / 5 A channel over USB serial
Prices are what Amazon listed on 29 October 2026, so check the live price before you buy. If you only power one dev board at a time and never leave the bench, the Korad is enough. If the supply sits in a rack and a CI job flips it, spend the extra on one with a network port, because a USB cable ties it to a single host.
How I tested without owning all four
I don’t have four bench supplies on my desk, and I am not going to pretend I measured ripple on any of them. So what could I test properly? The Linux half, meaning the packages, the libraries, the device permissions and the exact bytes each protocol expects. For that I wrote three small simulators on box2 and pointed the real client tools at them. The Riden one is a Modbus RTU slave holding the RD60xx register map from the ShayBox/Riden project, the Korad one speaks the terminator-less serial protocol documented on the sigrok Korad page, and the SCPI one answers the SPD3303X command set on TCP 5025.
That split matters when you read the rest of this page, because a simulator can only be as right as the documentation it was built from. It cannot tell you that a real unit drops a command when two arrive in the same millisecond, so this is what each claim rests on:
- Tested on box2: package names, install commands, library APIs, udev rules, Modbus framing
- Taken from datasheets: voltage, current, resolution, ripple, interfaces
- Not tested: accuracy, noise, fan behaviour, firmware bugs on real units
Every spec in the table and the pick sections traces to the maker’s datasheet or to the Amazon listing for that exact ASIN. Where a fact came from a community project instead of the vendor, I say so in the sentence.
Comparing the programmable bench power supplies
The protocol column decides how much code you’ll write, so read it before the watts column. SCPI supplies work with generic tools like PyVISA and lxi-tools, which means one script can drive both the Siglent and the Rigol with only the command strings changed. The Riden and Korad each need their own library, and that library is usually one person’s side project.
| Model | Outputs | Set resolution | Interfaces | Remote protocol | Linux tool | Price band |
|---|---|---|---|---|---|---|
| Siglent SPD3303X-E | 2 x 32 V / 3.2 A, plus 2.5/3.3/5 V at 3.2 A, 220 W | 10 mV / 10 mA | USB (USBTMC), LAN | SCPI over VXI-11 | PyVISA, lxi-tools | about $460 |
| Rigol DP832A | 2 x 30 V / 3 A, plus 5 V / 3 A, 195 W | 1 mV / 1 mA (readback 0.1 mV / 0.1 mA) | USB, LAN, RS232 | SCPI, LXI | PyVISA, lxi-tools, sigrok | about $620 |
| Riden RD6018W kit | 1 x 60 V / 18 A, 1080 W | registers scaled by 100 (0.01 V / 0.01 A) | USB serial (CH340), WiFi module | Modbus RTU, 115200 8N1 | riden library, mbpoll | about $245 |
| Korad KA3005P | 1 x 30 V / 5 A, 150 W | 10 mV / 1 mA | USB serial, RS232 | Korad ASCII, 9600 8N1 | koradctl, sigrok | about $155 |
The Riden resolution row is the register scaling the riden library uses for the RD6018, not a vendor accuracy figure, and I could not reach Riden’s own site to confirm one. Treat it as the step size you can command, not a promise about what the output really does.
1. Siglent SPD3303X-E: best overall for LAN scripting
This is the one I’d put on a homelab bench that gets driven from a server in another room. It has two isolated 32 V / 3.2 A channels that can run in series or parallel, a third output switchable between 2.5, 3.3 and 5 V, and both a USB device port and Ethernet on the back.

Siglent’s quick start documents USBTMC on the USB port and VXI-11 on the LAN port, which is exactly what PyVISA and lxi-tools expect, so there’s no vendor driver to hunt for. The community Python libraries for this model also talk raw TCP on port 5025, and that’s what my simulator answered. Siglent documents 5025 for its SPD1000X series, but I couldn’t find it in an SPD3000X document, so I’d use VXI-11 (TCPIP::10.0.1.50::INSTR) first and fall back to the socket if your firmware answers there.
Who it’s for: anyone powering two boards at once, or a board plus a fan, from scripts on another machine. Ripple is rated at 1 mVrms or less in constant voltage mode on the SPD3000X datasheet, which is plenty for microcontroller and SBC work.
Skip it if you need millivolt steps. The X-E sets and reads in 10 mV / 10 mA steps. The non-E SPD3303X (around $630) does 1 mV / 1 mA with the same outputs, so if you’re characterising LDO dropout you want that one. It’s also an 8 kg box, so it isn’t going in a backpack.
Amazon listed the SPD3303X-E at around $460 at the time of writing. Siglent’s own store showed a restock date in December, so stock can swing between sellers, and it’s worth checking the live price and availability before you plan a bench around it.
2. Rigol DP832A: best for logging small currents
The DP832A is the supply I’d pick when the script’s job is measuring, not just switching. Rigol’s datasheet gives it 1 mV / 1 mA programming resolution and 0.1 mV / 0.1 mA readback, so a sleep-current test on a battery board actually shows the difference between 1.2 mA and 1.3 mA.
Do not confuse it with the plain DP832, which is cheaper on Amazon and easy to grab by mistake. Rigol’s datasheet lists LAN and RS232 as an option on the DP832, so the base unit only gives you USB, and it programs in 10 mV steps. The A model ships with LAN, RS232 and digital I/O enabled. The DP800 programming guide documents commands like :APPLy CH1,5,1 and :MEASure:ALL? CH1, which returns voltage, current and power in one reply, so a logging loop needs one query per sample instead of three.
It is also the only pick here that sigrok supports through its generic scpi-pps driver, per the sigrok DP832 page. On USB it shows up as 1ab1:0e11, which is the ID I used in the udev rule further down.
Pass on it if you want more than 30 V or your bench is small. Rigol’s DP800 datasheet lists the DP832 at 10.5 kg and 418 mm deep, deeper than the Siglent, and the A model has the same front panel and outputs, so plan for a similar box. It’s also the priciest pick at around $620 on Amazon (the listing showed limited stock on 29 October), so check the live price and stock first.
3. Riden RD6018W kit: best for high current over Modbus
Nothing else here gets close to 60 V and 18 A for the money, and that’s why the Riden shows up on so many benches that charge batteries or run motors. The catch is that the RD6018 is a buck converter module, not a finished supply. It needs a DC input above the voltage you want out, which is why I’d buy the kit with the case and a 68 V, 1200 W switching supply rather than the bare module.

On Linux it’s the most scriptable supply here once you accept Modbus. The USB port is a CH340 serial bridge (1a86:7523), the kernel’s ch341 driver binds it as /dev/ttyUSB0, and every setting is a holding register you can read with mbpoll. The defaults are 115200 baud and slave address 1, both changeable in the menu, per the sigrok Riden page.
Look elsewhere if you’d rather not wire mains yourself. The kit arrives unassembled, the EEVblog build thread reports the bundled PSU fan runs constantly, and the ShayBox README warns that newer stock firmware may break Modbus, which is why many owners flash the community UniSoft firmware. The WiFi module also talks to Riden’s phone app, not to Linux, so ignore it for scripting. Around $245 for the kit on Amazon, with only a few left on 29 October; check the live price.
4. Korad KA3005P: cheapest supply that scripts at all
The KA3005P is a single 30 V / 5 A supply with USB and RS232 on the back, and at around $155 it’s the cheapest way I’d trust to get a supply under script control. Korad’s KA-series page lists 10 mV / 1 mA resolution and a temperature-controlled fan.

The thing most Amazon reviews skip is that it is not SCPI. Apart from *IDN?, the commands are Korad’s own, sent at 9600 baud with no line terminator, and set commands get no reply at all. The sigrok wiki documents the set you’ll use most:
VSET1:12.00andISET1:0.5to set voltage and currentVOUT1?andIOUT1?to read what the output is doingOUT1andOUT0to switch the outputSTATUS?for one status byte, only partly reliable
PyVISA’s SCPI habits don’t fit that, so use a library that knows the dialect. The same wiki page documents a firmware bug where ISET1? returns a stray sixth byte, and the front panel locks while a PC holds the port, so you can’t nudge the knob while a script is connected.
The wrong buy if you need two rails or network control, because it has neither. Rebadged versions (Tenma, Velleman) exist, and sigrok notes some Velleman units speak a different protocol, so buy the Korad-branded one. The KD3005P (around $145) is a slightly cheaper sibling.
On Amazon the KA3005P was around $155 at the time of writing, with limited stock. Search results also turned up lookalike 30 V / 5 A listings from unknown brands at higher prices, so check that the brand on the listing reads Korad as well as checking the live price.
Setting up the Linux side once
All four supplies need the same small toolbox, so I installed it once on box2. The Ubuntu packages cover the CLI tools and the Python libraries go in a virtual environment, because the riden library isn’t on PyPI and has to come from GitHub:
sudo apt install python3-venv git mbpoll lxi-tools sigrok-cli
Then create the environment and pull the libraries into it. Keeping them in ~/psu rather than the system Python means an Ubuntu upgrade can’t break your bench scripts, and you can copy the folder name into a systemd unit later.
python3 -m venv ~/psu
~/psu/bin/pip install pyvisa pyvisa-py pyserial koradctl git+https://github.com/shaybox/riden.git
Pip’s last line listed what it pulled in. The riden library brings modbus_tk with it, so you don’t need a separate Modbus package, and koradctl needs nothing beyond pyserial because the Korad protocol is plain ASCII.
Successfully installed Riden-1.2.0 click-8.5.0 koradctl-0.8 modbus_tk-1.1.5 pyserial-3.5 pyvisa-1.16.2 pyvisa-py-0.8.1 typing_extensions-4.16.0
My first pyvisa-info run showed a gap that would have bitten me on a real Siglent or Rigol plugged in over USB. PyVISA-py had TCPIP and serial ready, but not USB:
USB INSTR:
Please install PyUSB to use this resource type.
No module named 'usb'
Installing the usb extra fixes it. I added psutil in the same step because the report also said VXI-11 discovery was only partial without it.
~/psu/bin/pip install "pyvisa-py[usb]" psutil
After that, pyvisa-info reported USB through libusb, which is the line you want to see before plugging in a USBTMC instrument.
USB INSTR: Available via PyUSB (1.3.1). Backend: libusb1
USB RAW: Available via PyUSB (1.3.1). Backend: libusb1
The same apt package names exist in the Ubuntu 24.04 archive at older versions. I did not rerun the lab there, so if a flag below doesn’t exist on 24.04, check the tool’s --help first.
Giving your user access without sudo
A script that needs root to open a serial port is a script that ends up running everything as root. Two udev rules and two group memberships fix that: the Riden’s CH340 lands in dialout, and the Rigol’s USBTMC node lands in plugdev. Create the rules file:
sudo vim /etc/udev/rules.d/70-bench-psu.rules
Add these two rules. The first also gives the Riden a stable /dev/riden name, so your scripts stop caring whether it enumerated as ttyUSB0 or ttyUSB1:
# Riden RD60xx: CH340 USB-serial bridge (matches every CH340 adapter on the box)
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="riden", GROUP="dialout", MODE="0660"
# Rigol DP800 through the kernel usbtmc driver
SUBSYSTEM=="usbmisc", KERNEL=="usbtmc*", ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0e11", GROUP="plugdev", MODE="0660"
Notice the comment on the first rule. The CH340 ID is shared by half the cheap Arduino clones and USB serial adapters out there, including some console cables, so if you have more than one CH340 plugged in, add a KERNELS match on the USB port path to pin the symlink to the Riden. Matching on ATTRS{serial} usually won’t help, because most CH340 chips report no serial number. Check the syntax before reloading:
sudo udevadm verify /etc/udev/rules.d/70-bench-psu.rules
A clean file reports one success and no failures. A typo in a match key shows up here instead of silently doing nothing at the next plug-in.
1 udev rules files have been checked.
Success: 1
Fail: 0
Reload the rules and add yourself to both groups, then log out and back in so the new groups apply to your session:
sudo udevadm control --reload
sudo usermod -aG dialout,plugdev $USER
You do not need a rule for a supply you only reach over LAN. The Siglent and Rigol on Ethernet need nothing but a route and, if you run a firewall between VLANs, TCP 111 plus the VXI-11 port the instrument hands out, or TCP 5025 for raw sockets. I’d still give the supply a DHCP reservation, because every script hardcodes its address and a lease change looks exactly like a dead instrument.
Talking SCPI to the Siglent and Rigol
For the two SCPI supplies, PyVISA with the pure-Python backend is all you need. This is the exact script I ran against the SPD3303X simulator; on real hardware you only change the resource string to TCPIP::10.0.1.50::INSTR for VXI-11 or keep the ::5025::SOCKET form:
vim ~/scpi_demo.py
Paste the script. It identifies the supply, sets channel 1 to 5 V with a 0.8 A limit, switches it on, reads three measurements and switches it off again.
import time
import pyvisa
rm = pyvisa.ResourceManager("@py")
psu = rm.open_resource("TCPIP::127.0.0.1::5025::SOCKET",
read_termination="\n", write_termination="\n", timeout=2000)
print(psu.query("*IDN?"))
psu.write("CH1:VOLTage 5.0")
psu.write("CH1:CURRent 0.8")
psu.write("OUTPut CH1,ON")
time.sleep(0.1)
for q in ("MEASure:VOLTage? CH1", "MEASure:CURRent? CH1", "MEASure:POWEr? CH1"):
print(f"{q:22} -> {psu.query(q)}")
psu.write("OUTPut CH1,OFF")
psu.close()
The time.sleep(0.1) after enabling the output is not decoration. Siglent’s own SPD programming tips recommend a 10 to 100 ms pause between commands, warn that a write-then-read query with no delay may cause problems, and require a bare \n terminator. On a real SPD I’d add the same pause before each query() too. Run it from the venv:
~/psu/bin/python ~/scpi_demo.py
The simulator identifies itself in the Siglent format and the three measurements come back as plain decimal strings, which is what makes SCPI pleasant to log:
Siglent Technologies,SPD3303X-E,SIM0000000001,1.01.01.02.07R2,V3.0
MEASure:VOLTage? CH1 -> 5.000
MEASure:CURRent? CH1 -> 0.500
MEASure:POWEr? CH1 -> 2.500
For a one-off query, lxi-tools is quicker than Python. These two runs point at the simulator on 127.0.0.1, so swap in your supply’s address (for example 10.0.1.50) when you try them. My first try failed, and the reason will save you time on real hardware.
lxi scpi -a 127.0.0.1 -t 2 "*IDN?"
Without -r, lxi speaks VXI-11, which starts at the portmapper on TCP 111. My simulator only listens on 5025, so the connection never opened:
Error: Unable to connect to LXI device
Adding -r switches lxi to raw TCP, whose default port is 5025, so it needs no -p here.
lxi scpi -a 127.0.0.1 -r "*IDN?"
That returned the identity string straight away. On a real instrument the same error points the other way: if VXI-11 fails but -r works, the firmware has only the socket enabled, and if both fail, check the instrument’s LAN settings before blaming Linux.

The screenshot also has the Korad run from the next section, which is why it ends on koradctl’s warning. I kept the failed lxi call in it on purpose, because that error message is the one you’ll search for when a real supply doesn’t answer. If you see it, try -r before you start checking cables.
Getting the Korad to answer
koradctl wraps the terminator-less protocol and gives you a CLI that sets and reads back in one call. On box2 I pointed it at the simulator’s port, /dev/ttyKO-sim. On hardware the port is /dev/ttyACM0 or /dev/ttyUSB0 depending on the unit’s USB chip, which I couldn’t confirm from a source, so check dmesg after plugging it in and adjust the command below:
~/psu/bin/koradctl -p /dev/ttyACM0 -v 3.3 -i 0.25 -e on -m
Each request is read back from the supply, so a result that differs from the request is your first sign that a command got dropped. That check matters more on the Korad than anywhere else, because set commands return nothing, so the read-back is the only confirmation you’ll get:
WARNING: this power supply is not fully tested
Voltage: request: 3.30, result: 3.30
Current: request: 0.250, result: 0.250
Enable: request: On , result: On
Output: 3.30 v, 0.250 A, 0.82 W
The warning appears because koradctl’s author tested on a Tenma 72-2540, and any other identity string triggers it. My first simulator also taught me something about the protocol: koradctl fires its set and query commands back to back with no separator, and my first version, which split commands on a short pause, read VSET1:3.30 and the query after it as one garbled command and returned 0.00 V. I don’t know how much spacing a real Korad needs between commands, but that failure is exactly what you’d see if the supply misread merged writes, so always trust the read-back over the request. For a long monitoring run, pair -M with -o, so stopping it with Ctrl+C also switches the output off.
Driving the Riden over Modbus
The Riden is the easiest of the four to script from Linux, because Modbus needs no vendor software at all. mbpoll reads raw holding registers, which is the fastest way to check the cable, baud rate and slave address before you write any Python. These are the registers worth knowing first, from the ShayBox and Baldanos register tables:
- 0: model ID (60180 to 60189 is an RD6018)
- 8 and 9: voltage setpoint and current limit
- 10 and 11: measured output voltage and current
- 14: input voltage
- 17 and 18: CV/CC state and output switch
Read eleven registers starting at 8. The command uses /dev/riden from the udev rule above (use /dev/ttyUSB0 without it); on box2 I ran it against the simulator’s /dev/ttyRD-sim:
mbpoll -m rtu -a 1 -b 115200 -P none -t 4 -0 -r 8 -c 11 -1 /dev/riden
I’d already written 5.00 V and 0.50 A into registers 8 and 9 and switched register 18 on, so the values are hundredths: 500 is 5.00 V and 6420 is a 64.20 V input:
-- Polling slave 1...
[8]: 500
[9]: 50
[10]: 500
[11]: 50
[12]: 0
[13]: 250
[14]: 6420
[15]: 0
[16]: 0
[17]: 0
[18]: 1
Two flags trip people up here. -0 makes mbpoll count registers from zero the way the Riden documentation does (without it, -r 8 reads register 7), and -P none matters because mbpoll defaults to even parity while the Riden uses 8N1. Writing works the same way, so mbpoll -m rtu -a 1 -b 115200 -P none -t 4 -0 -r 18 /dev/riden 0 is a one-line emergency off switch for a shell script.
For anything longer, the riden library does the scaling for you and picks the right multipliers from the model ID. This is the script I ran:
vim ~/rd_demo.py
It reads the identity, sets 12 V with a 2 A limit, switches on, polls, then switches off. Change the port to /dev/riden when you run it against the real module.
from riden import Riden
r = Riden(port="/dev/ttyRD-sim", baudrate=115200, address=1)
print(f"{r.type} id={r.id} fw={r.get_fw()} sn={r.get_sn()} input={r.get_v_in():.2f} V")
r.set_v_set(12.00)
r.set_i_set(2.00)
r.set_output(True)
r.update()
print(f"set {r.v_set:.2f} V / {r.i_set:.2f} A -> out {r.v_out:.2f} V {r.i_out:.2f} A {r.p_out:.2f} W ({r.get_cv_cc()})")
r.set_output(False)
print("output on:", r.is_output())
Run it with the venv’s Python, since the system interpreter doesn’t have the library.
~/psu/bin/python ~/rd_demo.py
The library decoded model ID 60181 as an RD6018 on its own, and the simulator’s 10 ohm dummy load drew 1.2 A at 12 V, so the supply stayed in constant voltage mode under the 2 A limit:
RD6018 id=60181 fw=128 sn=00012345 input=64.20 V
set 12.00 V / 2.00 A -> out 12.00 V 1.20 A 14.40 W (CV)
output on: False
Here is the same session as a screenshot, with the mbpoll read above it, so you can compare the raw register values with what the library turned them into:

One thing I expected to work didn’t. The sigrok wiki lists the Riden under a driver called rdtech-rd, but the sigrok-cli in Ubuntu 26.04 is built on an older libsigrok that predates it:
sigrok-cli -d rdtech-rd:conn=/dev/riden --scan
The packaged build simply does not know the name. Is the Riden missing, or just renamed? I listed the drivers to find out.
Driver rdtech-rd not found.
Missing, it turns out. Its driver list only had the older DPS-series driver, plus Korad and the generic SCPI one, so on Ubuntu the riden library is the practical route for an RD6018. If you want sigrok’s PulseView logging, you’d have to build libsigrok from git, which I did not do. The riden library covers the same registers anyway, so you lose the GUI, not the data.
Choosing a supply you’ll script for years
Datasheets bury the things that decide whether a supply is pleasant to automate. These are the questions I’d answer before buying any programmable bench power supply, including ones not on this list:
- LAN in the base model, or a paid option (the DP832 trap)
- Real SCPI, or a vendor dialect that only answers
*IDN? - Readback resolution fine enough for the current you’ll log
- A maintained library for its protocol, with a recent commit
- Whether firmware updates have broken remote control before
Power budget comes after those. If your bench feeds dev boards, 3 A per rail is plenty, and the triple-output Siglent or Rigol covers a Raspberry Pi, an ESP32 dev board and a fan at once. A 30 V, 5 A supply can’t spin a 48 V motor or charge a 14S pack, which is where the Riden earns its place, and a GPU-sized load belongs on an ATX supply sized like the ones in our multi-GPU PSU guide, not on a bench unit.
One more homelab detail: a bench supply on a timer script is an always-on mains device. If it shares a circuit with the rack, the advice in power station vs UPS for a homelab applies to it too, because a brownout mid-test leaves the DUT in whatever state the supply’s power-on setting chooses. Check that setting (the riden library exposes it as set_boot_pow) before you let a script run overnight.
What I still don’t know
Simulators prove the Linux side, not the hardware, so a few questions stayed open after the lab:
- Whether current SPD3303X-E firmware answers raw sockets on 5025
- Which USB chip the latest KA3005P revision ships with
- How fast each real unit accepts back-to-back commands
- Whether today’s Riden stock firmware still breaks Modbus
If you own one of these and run the scripts above against it, the read-back lines will tell you within a minute whether your firmware behaves. My bet for most homelabs is still the Siglent, because VXI-11 on Ethernet means any machine on the network can drive it with tools Ubuntu already packages, and if you’re setting up a fresh workstation for bench work, the Ubuntu 26.04 desktop checklist covers the rest of the box.
