Skip to main content

Python driver for the ISDT MP305 (MP305A/MP305B) smart bench power supply over USB-HID

Project description

pymp305

A pure-Python driver for the ISDT MP305 smart bench power supplies (MP305A and MP305B) over USB-HID (sync) and Bluetooth (async) — the same protocol the official WebLink web app and PolyLink phone app use. Reverse-engineered from WebLink's public source-maps; the full protocol is documented in ../PROTOCOL.md. (The recovered upstream JS is ISDT's copyright and is kept locally under reversing/, which is git-ignored and not published.)

Status: not yet validated against real hardware. Framing, decoding, units, and firmware-decrypt are covered by golden-vector tests (pytest, all passing), but nothing here has talked to a device — open() emits a one-time UserWarning to that effect, and OTA flashing is gated behind an explicit allow_untested_ota=True. See Bring-up below.

Install

pip install pymp305          # USB-HID (pulls in hidapi)
pip install pymp305[ble]     # + Bluetooth transport (bleak)

From source (development): pip install -e . from this directory.

A Dracula-themed PyQt6 desktop GUI (live charts + simulator) lives in ../gui.

On Linux you'll need permission to access the hidraw node. Either run as root for a quick test, or add a udev rule (recommended):

# /etc/udev/rules.d/99-pymp305.rules
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28e9", MODE="0660", TAG+="uaccess"

then sudo udevadm control --reload && sudo udevadm trigger and replug.

Quick start

from pymp305 import MP305

with MP305.open() as psu:
    print(psu.hardware_info())            # name, hw/boot/app versions

    psu.set_output(voltage=5.0, current=1.0, on=True)   # takes remote control + enables output

    st = psu.read_state()
    print(f"{st.voltage:.2f} V  {st.current:.3f} A  {st.power:.2f} W  {st.temperature} C")

    psu.output_off()
    psu.release_remote()                  # hand control back to the front panel

See examples/basic.py for a live-streaming example.

API surface

Method Does
MP305.list_devices() enumerate VID 0x28E9 HID interfaces
MP305.open(path=None) open (auto-picks usage_page 0x01 / usage 0x04)
hardware_info() 0xE00xE1 device id, firmware versions
read_state(realtime=True) 0xBD/0xC20xC3 live V/I/W/Wh/temp/output (State)
read_system_settings() 0xC40xC5 (SystemSettings)
set_output(voltage, current, on, model=0) take control + apply, returns fresh State
output_on() / output_off() toggle output
release_remote() remoteCon=0 — return control to the panel
control(ControlCommand) low-level 0xC8
set_system_settings(SystemSetCommand) 0xC6
set_language(i) 0xA2
read_charge_state() / read_charge_settings() 0xEC0xED / 0xEA0xEB (ChargeState / ChargeInfo)
charge(ChargeCommand) 0xEE start/stop a battery charge
read_pdo(id) / pdo_connect(PDOConnect) / write_pdo(...) 0xD00xD1 read / 0xE80xE9 select / 0xD20xD3 define a PD profile
read_program_list() / read_program_steps(id, n) 0xD40xD5 / 0xD80xD9
read_program_state() / program_connect(ProgramConnect) 0xDE0xDF / 0xE20xE3 run a sequence
write_program(id, steps) / program_change(...) 0xDA0xDB write steps / 0xD60xD7 create/rename/delete slot
read_emarker() USB-C cable e-marker info (speed/format labelled)
flash(Firmware, allow_untested_ota=True) experimental OTA over HID (see warnings)
reboot() / enter_bootloader() danger zone
send(cmd, payload) / request(cmd, expect, payload) / read_frame() raw access for any other command

Units are converted for you: voltage/set_voltage in V, current/set_current in A, power in W, energy in Wh, temperature in °C, working_time in s.

Transports

  • MP305 — synchronous, USB-HID (this table).
  • MP305BLE — the same API but async over Bluetooth (bleak); methods are coroutines and connection is await MP305BLE.open(). Adds flash_ble(IntelHexFirmware, allow_untested_ota=True) (experimental BLE OTA over fee0/fee1). See examples/ble.py.

Firmware (pymp305.ota)

  • Firmware.parse(bytes) — decrypt + verify an official .bin (key is in the header).
  • IntelHexFirmware.parse(...) — the BLE FEE1 firmware format.
  • tools/fetch_firmware.py downloads + decrypts official images into git-ignored reversing/.
  • OTA writing is experimental and untested on hardware — see the repo banner.

Experimental / undisclosed commands

Reverse-engineered from the firmware (handled by the device but never sent by the official app). Untested on hardware — see notes in reversing/FINDINGS-commands.md.

  • get_language() — read the UI language index (cmd 0xA00xA1), the read counterpart of set_language(). Read-only; the safe first probe.
  • soft_reset(confirm=True) — magic-gated (0xFE AA 55) soft re-init of the regulator/ USB-PD state to defaults + control-task restart. Static analysis shows no flash/NVM access (can't brick), but it resets the live output, so it's gated behind confirm=True.

Bring-up checklist (first run with hardware)

  1. python -c "from pymp305 import MP305; print(MP305.list_devices())" — confirm the device shows up under VID 0x28E9 and note its usage_page/usage.
  2. psu.hardware_info() — if the de-stuffed name/version look right, framing is correct.
  3. If reads time out: the device may not use a fixed 64-byte report. Try MP305(dev, report_size=N) with other sizes, or pass an explicit interface path.
  4. read_state() polls with the realtime command (0xBD) like the app; if that yields nothing, try read_state(realtime=False) (0xC2).

Tests

pytest                 # runs all suites (framing, charge/PD/program, OTA, experimental)

All run without hardware — they validate framing/checksum/stuffing, unit decoding, the firmware decryptor, and the command builders against golden vectors.

BLE transport

Implemented via MP305BLE (async, bleak) — see Transports above and examples/ble.py. Over BLE the same command set is used but frames drop the length/0xAA/checksum wrapper ([0x12, cmd, …payload]): commands go to GATT characteristic af01, responses arrive as notifications (parsed at index 2, reusing responses.py), and an af02 binding handshake starts the session; fee0/fee1 carry BLE OTA.

MP305 has Bluetooth, but its BLE-module firmware isn't published in the OTA feed and this transport is unverified on hardware — USB-HID is the primary path.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymp305-0.4.8.tar.gz (35.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymp305-0.4.8-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

Details for the file pymp305-0.4.8.tar.gz.

File metadata

  • Download URL: pymp305-0.4.8.tar.gz
  • Upload date:
  • Size: 35.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymp305-0.4.8.tar.gz
Algorithm Hash digest
SHA256 70b67bbec1c4567438d68cac121d285d31dcaccb4b9269e9acd3e39f06831f06
MD5 b27b4cb55d6ff8882fc8a21015f2bada
BLAKE2b-256 e287d624a8693a8c502252012f3778b9876029232b0007ea9d4b5c428460da55

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymp305-0.4.8.tar.gz:

Publisher: publish.yml on nemanjan00/pymp305

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pymp305-0.4.8-py3-none-any.whl.

File metadata

  • Download URL: pymp305-0.4.8-py3-none-any.whl
  • Upload date:
  • Size: 29.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymp305-0.4.8-py3-none-any.whl
Algorithm Hash digest
SHA256 43f0908f3bad3e3d7c6edafa2c092ae21ecfb5bb7f236bf55bd0bdacbe71c62c
MD5 d0936f538661c2bed09dec0713a14f82
BLAKE2b-256 f03e295d2bfb5ddb530ee63151dfb065c16fdb6c78c866ea000ecddf9dba6e11

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymp305-0.4.8-py3-none-any.whl:

Publisher: publish.yml on nemanjan00/pymp305

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page