Close
0%
0%

PSU-EXT

Open hardware and firmware that sit inline with a bench power supply, adding live measurement, protection, and SCPI control.

Similar projects worth following
PSU-EXT started as a way to give an existing bench power supply capabilities it didn't ship with. The current build is an inline hardware module (ESP32-S3, isolated measurement front end) paired with a browser dashboard — live telemetry, protection controls, an SCPI console, and a scripting IDE for automation. Every part of it, hardware through software, is open source.



Overview

PSU-EXT sits inline between a bench power supply and whatever it's powering. It measures voltage, current, and power, switches the output on and off through a relay, and speaks SCPI — the command language bench instruments use — over both USB and Wi-Fi/TCP.

A browser dashboard sits on top: live telemetry widgets, OVP/OCP protection controls, a raw SCPI console, and a JavaScript scripting IDE for running sandboxed automation sequences against the device. Hardware, firmware, and the dashboard's backend and frontend are all in the open.

It started from a plain annoyance: our own bench PSU already did the one thing it needed to do — supply power — but everything around that was manual. Watching the display meant standing at the bench. Logging meant writing numbers down. Scripting anything wasn't really on the table. PSU-EXT is what we built to sit inline and take care of that part.

Spec at a glance:

Operating range0–25 V, 0–2.5 A
Board size100 × 50 mm (3.94 × 1.97 in)
Control connectionUSB-C (power and data)
ControllerEspressif ESP32-S3
Measurement front endADS1115 ADC + INA240 current-sense amplifier
IsolationIsolated I²C bus + isolated DC-DC (measurement domain)

Current Status — Crowd Supply Pre-Launch

PSU-EXT is a working prototype today. The board, firmware, and dashboard already work together end to end: you can measure, control, calibrate, and script against a real unit right now.

Our Crowd Supply pre-launch page is live: crowdsupply.com/maxeelabs/psu-ext. Please subscribe if you're interested in the project.

In the meantime:


The Journey We've Been Through

PSU-EXT didn't show up finished. Getting it to this point took a real string of steps — here's what that looked like, behind the scenes:

✔  March 2026 — The idea lands, resonates, and won't let go: what if our own bench PSU didn't have to be replaced to get remote control and telemetry?
✔  March 2026 — Start of hardware development: first board work begins.
✔  April 2026 — First prototype on breadboard
✔  April 2026 — Start of software development: live telemetry widgets in the browser, first version.
✔  May 2026 — First PCB revision.
✔  June 2026 — Enclosure: PSU-EXT moves off the bare board and into its own case
✔  July 2026 — JavaScript IDE for scenarious autoamtion
✔  August 2026 — Hardware, firmware, and software all published in the open.
✔  August 2026 — Crowd Supply pre-launch page goes up: crowdsupply.com/maxeelabs/psu-ext. The campaign itself is still ahead.

→  August 2026 - And we're here while the journey continues... Stay tuned!


  • 1 × ESP32-S3-WROOM-1-N16R8 A high-performance wireless microcontroller module
  • 1 × RFM-0505S DC-DC Converter
  • 1 × INA240A2DR Current-sense amplifier
  • 1 × ISO1540DR A low-power, bidirectional digital isolator
  • 1 × AP22818BKCWT-7 Single-Channel High-Side Switch

View all 17 components

  • Adding Auto-ranging to the PSU-EXT Analog Front End

    Maxim Pavlov2 days ago 0 comments

    PSU-EXT sits between an existing bench power supply and its load. It measures voltage and current and controls the output path with a relay. This update follows the development of its voltage measurement front end, from fixed converter settings to automatic range selection and programmable acquisition speed.

    The existing design works with a fixed programmable gain amplifier (PGA) setting and a fixed analog-to-digital converter (ADC) rate. Its DC voltage accuracy is:

    • ±(0.1% of reading + 2 mV) from 1 V to 24 V
    • ±(0.5% of reading + 2 mV) below 1 V

    That gives us a useful starting point. The next step is to use more of the ADS1115's capabilities: select a measurement range automatically and let the acquisition speed suit the task. Following that idea through the firmware led to two additions to the analog circuit: voltage buffers and a negative-rail output bias.

    Making the Converter Settings Programmable

    The ADS1115 has several full-scale input ranges. A smaller range gives a smaller voltage step per ADC count, which is useful when measuring low voltages. Autoranging lets the firmware select a narrow range for a small signal and move to a wider range as the signal rises.

    The updated firmware uses three ranges: ±0.256 V, ±0.512 V, and ±2.048 V. These are voltages at the ADC input, after the voltage divider.

    The range selection code moves one range at a time. Separate thresholds for moving up and down provide hysteresis, so a reading near a boundary does not repeatedly switch ranges. This excerpt comes from components/measure_svc/measure_prov_ads1115.c:

    uint8_t index = current_index;
    if ((index + 1U < ADS1115_RANGE_COUNT) &&
        (adc_voltage_u4 >= ADS_RANGES[index].hysteresis_top_u4)) {
        ++index;
    } else if ((index > 0U) &&
        (adc_voltage_u4 <= ADS_RANGES[index].hysteresis_bottom_u4)) {
        --index;
    }
    *next_index = index;

    Each input keeps its own range index. The firmware can therefore choose a range independently for each measured signal.

    Acquisition speed is  now programmable too. The driver accepts the ADS1115 rates of 8, 16, 32, 64, 128, 250, 475, and 860 samples per second. For example, these cases encode two rates into the configuration register:

    case 128U:
        *bits = (uint16_t)0x04U << 5;
        return ESP_OK;
    case 250U:
        *bits = (uint16_t)0x05U << 5;
        return ESP_OK;

    These settings control the converter rate. The update rate for a complete set of measurements also depends on channel scanning and settling conversions.

    The new Standard Commands for Programmable Instruments (SCPI) command exposes this setting to users:

    CommandDescription
    MEASure:ADC:RATE <SPS>Set the ADC conversion rate in samples per second
    MEASure:ADC:RATE?Read the selected rate as an integer


    Following the Signal Back to the Divider

    During development of the programmable-rate mode, changing the ADC rate also changed the voltage reading for a steady input. The current channel, driven by an INA240 current-sense amplifier, stayed stable in the same experiments. That difference pointed us toward the circuit driving the ADC.

    Each voltage channel uses two 160 kΩ resistors above a 20 kΩ resistor. The nominal division ratio is 17:1. At a 30 V input, the divider produces about 1.765 V while drawing about 88 µA.

    Rsource = 320 kΩ || 20 kΩ ≈ 18.8 kΩ

    The ADS1115 uses a switched-capacitor input. Its input loading interacts with the resistance of the source driving it; The ADS1115 datasheet describes this behavior. The observed rate-dependent shift made source impedance a practical design consideration for the new operating modes.

    Adding a Buffer

    The revised design places a TSZ122 dual precision operational amplifier between the voltage dividers and the ADC. Each amplifier channel is a unity-gain follower. The divider sets the voltage ratio, and the buffer provides a low-impedance signal to the converter.

    Measured voltage
          |
        160 kΩ
          |
        160|
     +----> TSZ122 follower...
    Read more »

  • One SCPI Standard, One Bridge, USB and TCP Under the Hood

    Dzmitry Dydyshka09/06/2026 at 16:44 0 comments

    Prerequisite

    Getting a device connected and the PSU-EXT Dashboard open follows the Installation section of the psu-ext-software README



    Overview

    Our dashboard, backend, and firmware all speak SCPI, the standard ASCII command language for test-and-measurement instruments. Two transports and one WebSocket bridge carry that command language between browser and device — nothing here invents a protocol of its own.

    That choice matters in practice. One shared command language means every dashboard widget and script talks to PSU-EXT the same way, regardless of how it's connected. Exposing that language over two transports instead of one means a USB-tethered setup on a workbench and a Wi-Fi-only deployment across the room run on identical firmware, with nothing to swap out between them.

    One query, one bridge, two possible transports, one firmware dispatcher.

    One query, one bridge, two possible transports, one firmware dispatcher.

    The stack behind it

    Front-end ( psu-ext-software/psu-fe )

    • Framework: React 18.3.1 + React Router 6.30.1, built with Vite 6.0.5
    • Styling: Tailwind CSS 4.1.0 (via the @tailwindcss/vite plugin) 
    • Charting: uPlot 1.6.32 — the live telemetry chart widgets 
    • Icons: lucide-react 
    • Testing: Vitest 4.1.5 + Testing Library (React, jest-dom), jsdom

    Back-end ( psu-ext-software/psu-be )

    • Language/runtime: Java 25, Maven multi-module build (parent + BOM pattern)
    • Framework: Spring Boot (version pinned via the psu-be-bom/parent POMs; spring-boot-maven-plugin 4.0.6) 
    • Transport-specific: spring-integration-ip (backs "TcpScpiTransport.class") and jSerialComm (backs "UsbScpiTransport.class")
    • WebSocket: spring-boot-starter-websocket — backs "ScpiWebSocketHandler.class" 
    • Serialization: Jackson (jackson-databind, jackson-datatype-jsr310) - Testing: JUnit 5 + Mockito across all modules

    SCPI: the command language, not the wire

    SCPI (Standard Commands for Programmable Instruments) is an established, ASCII-text command-set standard for controlling test-and-measurement instruments. It's built on IEEE 488.2-1992, the message-exchange and common-command layer originally defined for GPIB (General Purpose Interface Bus) instruments under IEEE-488.1, and it grew up in the context of GPIB and VXIbus test gear. Its latest formal revision is commonly referenced as "SCPI-99."

    The format is hierarchical and colon-separated: a command like "MEAS:VOLT?" addresses a "MEASURE" subsystem's "VOLTAGE" node. Commands defined by IEEE 488.2 itself — the ones every SCPI instrument shares regardless of what it measures — are prefixed with an asterisk, such as "*IDN?", "*RST", and "*CLS'. A trailing question mark on the header is what distinguishes a query, which expects a reply, from a plain command, which doesn't.

    Crucially, the standard is transport-agnostic by design: it defines the command language, not the physical or electrical link it rides on.

    PSU-EXT's own SCPI commands

    Our command surface implements exactly one IEEE-488.2 common command: 

    *IDN?

    , which returns

    PSU-EXT,ESP32-S3,0001,0.1.0 

    and is handled before anything else, ahead of the per-family dispatch chain. Beyond that, everything is organized into eight command families:

    System (`SYST`)"SYST:ERR?" returns "0,"No error";
    "SYST:DATETIME" sets a runtime wall-clock mapping that isn't persisted across reboots
    Measure
    (
    `MEAS`)
    "MEAS:VOLT? CH1" and "MEAS:CURR? CH1' read output voltage and current; "MEAS:VOLT:DATA? CH1" returns a binary block of stored history records.
    Calibration
    (
    `CAL`)
    "CALibration:STARt VOLTage,CH0" opens a calibration transaction;
    "CALibration:COMMit" validates the staged points and writes them to non-volatile storage.
    Output
    (
    `OUTP`)
    "OUTP CH1,1" energizes the output relay (after clearing latched protection and checking the input-voltage condition);
    "OUTP? CH1" reads the relay state back.
    Protection
    (
    `OVP`/`OCP`)
    "OVP CH1,<value>" sets the over-voltage threshold;
    "RESET:PROTect CH1" clears a latched protection trip
    Timer
    (
    `TIMer`)
    "TIMer:ADD CH1,<id>,<seconds>,<0|1>" queues a delayed...
    Read more »

  • Step Motor Current and Power Profiling

    Maxim Pavlov09/02/2026 at 04:50 0 comments

    Driving a stepper motor is often one of the first practical electronics experiments. The 28BYJ-48 motor and its ULN2003 driver board are inexpensive, widely available, and simple to control from an Arduino. Paul Gallagher's 28BYJ-48 project in LittleArduinoProjects provides a useful introduction to the motor, the driver board, the coil sequence, and the required connections.

    This article examines the same circuit from a power perspective. We use PSU-EXT to measure its current and power consumption in different operating modes, including holding with one or two energized coils and running the motor at different step rates.

    Setup

    Figure 1. Basic 28BYJ-48 and ULN2003 wiring. Copyright © Paul Gallagher. Image from LittleArduinoProjects, used under the MIT License

    The Arduino ground is connected to the ULN2003 module ground, as shown in Figure 1. The Arduino and PSU-EXT are each powered over USB. The motor receives 5 V from the bench power supply through PSU-EXT.

    A Rigol DM858E digital multimeter is connected in series with the motor circuit. It provides an independent current measurement for comparison with the PSU-EXT reading. The complete current path is the bench power supply, PSU-EXT, ULN2003 driver, 28BYJ-48 motor, DM858E current input, PSU-EXT return, and bench power supply return.

    Arduino Control Sketch

    The Arduino sketch drives the motor with an eight-state half-step sequence and accepts newline-terminated commands over a 9600-baud serial connection. This lets us select a repeatable coil state or running speed while recording the electrical measurements.

    CommandFunction
    HELPLists the available commands.
    STATUSReports the current mode, coil pattern, direction, and speed.
    STOPDe-energizes all four driver inputs.
    HOLD ONE <1-4>Holds one of four positions with one coil energized.
    HOLD TWO <1-4>Holds one of four positions with two adjacent coils energized.
    RUN LEFT <1-1200>Advances through the sequence at 1 to 1200 half-steps per second.
    RUN RIGHT <1-1200>Traverses the sequence in reverse at 1 to 1200 half-steps per second.

    The running range starts at one half-step per second because zero represents the stopped state and cannot be used to calculate a step interval. The upper limit of 1200 half-steps per second was selected as an experimental ceiling. A common 5 V 28BYJ-48 datasheet specifies a no-load starting frequency above 600 Hz and a no-load running frequency above 1000 Hz. Extending the test range to 1200 half-steps per second lets us examine the motor near and beyond that documented region. It is not a guaranteed operating speed, and the sketch applies the requested speed without an acceleration ramp. The observed shaft direction depends on the motor wiring and the side from which it is viewed.

    Testing Hold Modes: One or Two Coils

    The sketch provides one-coil and two-coil hold modes. Each mode has four selectable electrical positions. These numbers identify positions in the drive sequence, not absolute positions of the geared output shaft.

    CommandIN1IN2IN3IN4Energized coils
    HOLD ONE 110001
    HOLD ONE 201001
    HOLD ONE 300101
    HOLD ONE 400011
    HOLD TWO 111002
    HOLD TWO 201102
    HOLD TWO 300112
    HOLD TWO 410012

    One-coil hold provides the lower-power reference. Two-coil hold energizes two windings at the same time and should draw more current while providing greater holding torque. Measuring all four positions also shows any differences between the individual windings and driver channels.

    HOLD ONE 1

    The 

    HOLD ONE 1 

    command keeps the first ULN2003 input active and energizes one motor winding continuously. The motor remains stationary while the energized winding produces holding torque.

    Figure 2. PSU-EXT current measurement during HOLD ONE 1. The recorded minimum is 0.1696 A, the maximum is 0.1721 A, and the average is 0.1706 A.

    The full recorded span is 2.5 mA, or about 1.45% of the maximum. The sustained current level falls by less than this because the minimum and maximum include...

    Read more »

  • A Tour of the PSU-EXT Dashboard

    Dzmitry Dydyshka08/30/2026 at 17:09 0 comments

    Prerequisite

    Getting a device connected and the PSU-EXT Dashboard open follows the Installation section of the psu-ext-software README


    The Tour

    From there, here's where the dashboard itself stands today: a three-column grid built from a catalog of six widget types: 

    • Single Value (displays a live SCPI reading);
    • Single Toggle (switches something on or off using SCPI commands);
    • Protection Control (watches a threshold and flags whether it's tripped);
    • External Triggers (hardware input pins to SCPI actions);
    • Timer Queue (runs a queue of timed relay actions);
    • Chart (plots SCPI query over time)

    PSU-EXT Dashboard WIth All Types of Widgets


    Getting the Grid Ready to Look Around

    A toolbar "Edit"/"Done" (1) button unlocks dragging, deleting, and adding widgets. The Add widget catalog (2) lists eight entries mapped to the six widget types (three of those eight are the chart's fixed sizes). "Reset" (3) restores the default layout

    Whatever layout you build persists locally in the browser.

    PSU-EXT Dashboard First Visit

    One fact applies to every widget type before we tour them individually: each widget picks its own target device independently, so a single dashboard isn't locked to one PSU-EXT unit. You can mix cards pointed at different connected devices on the same grid.

    Single Value and Single Toggle: The Two Simplest Widgets

    Single Value and Single Toggle are the two simplest widgets on the grid, both sized 1x1.

    Single Value is a read-only display of one cached SCPI query result: a number plus a unit label, for example "5.1431 / V".

    Single Value Widget

    Single Value Widget

    Single Value Widget Settings

    Single Value Widget Settings

    Single Toggle is a button that turns something ON or OFF — enabling a channel's output, say — and shows which state it's currently in: it checks a SCPI status query to know whether the thing it controls is ON or OFF right now, and clicking it sends one SCPI command for ON and a different one for OFF.

    Single Toggle Widget

    Single Toggle Widget

    Single Toggle Widget Settings

    Single Toggle Widget Settings


    Protection Control

    Protection Control is a 1x1 widget for one threshold — a voltage or current limit, set in an editable field with a Save button next to it. The PSU-EXT decides when that threshold's been crossed; the widget polls the device's reported trip state and shows it as a Tripped/Clear badge.

    Each widget instance is single-purpose: it's tied to one protection key and one SCPI query/set-command pair. Watching OVP (over-voltage protection) and OCP (over-current protection) on the same channel takes two separate widget instances on the grid, not one widget with two thresholds.
    Protection Control Widget

    Protection Control Widget

    Protection Control Widget Settings

    Protection Control Widget Settings


    External Triggers: Reading Hardware Inputs Into SCPI Actions

    External Triggers is a 1x2 widget that reads two physical trigger inputs  placed on PSU-EXT device — T1 on IO5 and T2 on IO4 — into SCPI actions. Each input has a LOW state slot and a HIGH state slot, four slots total, and each slot picks an action from a configurable list (defaults include Output On/Off/Toggle and Timer Start/Pause/Toggle) or None.

    On the board itself, T1 and T2 are broken out at connector J4: a 4-pin (2x2), 2.54 mm-pitch header, silkscreened "T1" and "T2," so the two inputs are easy to find by eye.
    External Trigger Widget

    External Trigger Widget

    External Trigger Widget

    External Trigger Widget Settings


    Timer Queue: An Ordered List of Timed Actions

    Timer Queue is a 2x2 widget that lets you queue up to ten timed relay actions in sequence, so you can cycle an output on and off over a schedule without writing a script. The code caps it at:

    MAX_TIMERS = 10 

    The widget's config is hardcoded to CH1, so every timer in the queue acts on CH1's output relay — the same relay that Single Toggle's "CH1 Output" example switches. Each timer carries an ID of up to three characters, a duration in seconds, and a relay-after setting of ON or OFF: once that timer's duration counts down, CH1's output relay switches to whichever of those two states the timer was set to.

    A timer...
    Read more »

  • How We Got Here

    Dzmitry Dydyshka08/25/2026 at 19:58 0 comments


    Pro"log"ue

    We keep coming back to the same starting point: a bench PSU that already does its one job well. It supplies voltage, it supplies current, and it's been sitting on the bench doing exactly that for years. The problem was never the PSU — it's everything around it. Watching it means standing there. Logging it means writing numbers down by hand, or propping a phone up to film the display. Automating it usually means buying a whole new instrument and retiring the one that already works.

    We didn't want to go that route, so this project started small and has been growing outward from that one decision since.

    Extend, don't replace.

    A programmable PSU solves remote control by replacing the instrument you already own — that's the default answer, and it means the supply you already know, already trust, already paid for, goes in a drawer. We want the opposite: keep the PSU right where it is, and extend it in place instead of swapping it out. That's the constraint everything else here has to work around.

    And it shouldn't be locked down.

    Fine — but if we're keeping the PSU, we're not going to hand anyone a closed box either. A lot of "programmable" gear ships with closed firmware and a fixed feature set: whatever the vendor decided you get is what you get. That's not extension, that's a different flavor of lock-in. So the hardware, the firmware, and the software all stay open.

    So it should speak SCPI.

    Open is good, but open and mute doesn't help anyone driving a test bench. It needs to speak SCPI — the command language real instruments use for remote control. Give it SCPI over USB, then. Done?

    Not quite. We add TCP too!

    Most SCPI-capable gear is USB-only, or LAN-only — pick a lane and stay in it. We didn't see a reason to pick one. The same commands work whether you're plugged into a laptop on the bench or reaching the module over Wi-Fi from across the room.

    Control isn't enough — make it automatable.

    SCPI commands get you remote control, but remote control by hand is still someone standing at a keyboard instead of standing at a bench — that's relocation, not automation. On top of the commands, there's a scripting IDE and reusable dashboard widgets: something that runs a sequence and shows you the result, instead of waiting for you to type the next line.

    And don't stop at this one PSU.

    Once those widgets exist, why should they only know about this one instrument? They don't — they adapt to other SCPI-capable gear too. 

    Somewhere along the way, the project stopped being about one bench PSU at all, and that's still where the scope keeps expanding.


    What PSU-EXT Is: One Module, Firmware, and a Dashboard

    Concretely, here's where that thinking has landed so far. PSU-EXT sits inline between a bench power supply and a load, measures voltage, current, and power, and controls the output path with a relay. That's the current physical shape the five points above have taken.

    "PSU-EXT" isn't just that board, though — it's three pieces that work together, each its own repo:

    - Hardware — the module itself
    - Firmware  — runs on the module
    Software  — the companion stack that talks to the firmware over USB or the network

    Separate repos, one product, moving in parallel.

    Here's what it's built on right now:

    Operating range0–25 V, 0–2.5 A
    Board size100 × 50 mm (3.94 × 1.97 in)
    Control connectionUSB-C (power and data)
    ControllerEspressif ESP32-S3
    Measurement front endADS1115 ADC + INA240 current-sense amplifier
    IsolationIsolated I²C bus + isolated DC-DC (measurement domain)
    PSU-EXT Board

    PSU-EXT Board

    And here's what runs it today:

    Capability

    What it provides

    Firmware & softwareOpen hardware, firmware, and software — not closed or vendor-locked
    Control transportsSCPI over both USB CDC and Wi-Fi/TCP
    AutomationBuilt-in scripting IDE and reusable dashboard widgets
    Instrument scopeWidgets adapt to other SCPI-capable gear too, not locked to this one instrument
    PSU-EXT Dashboard
    PSU-EXT Dashboard

    What...

    Read more »

View all 5 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates