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.0.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.0-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pymp305-0.4.0.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.0.tar.gz
Algorithm Hash digest
SHA256 74759694ae38956e6bc35b4f936e98892b26a33bf6b9a9daff0f53fbc03f9fe7
MD5 96dbd13c45069434dcff72a265b1d755
BLAKE2b-256 998480b177fb8ec304ffe51aef8534a37b5ab321a31cca736c48b232eed8ef28

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymp305-0.4.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: pymp305-0.4.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a8bb47693dc146494635ae67f1cba2d44460d93fcfc7c888bfa40379b83b4e70
MD5 c4daaec511444dd71b37ff96c68987c8
BLAKE2b-256 cd971a60a608316c2fd8d4861a7c915aa7eb95be5185df38946864046561882a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymp305-0.4.0-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