usb_pd_match

A small, dependency-free Ruby toolkit for reasoning about USB-C Power Delivery (USB-PD) compatibility between chargers and devices. Model a charger and a device, negotiate the optimal voltage/current contract, rank chargers for a given device, and check whether a device will actually reach its full rated power.

USB Power Delivery negotiates the highest fixed Power Data Object (PDO) both sides support; the full handshake is defined in the USB-IF Power Delivery specification and summarised on the USB-C Wikipedia page. This gem implements the practical fixed-PDO selection logic so you can answer "will this charger fast-charge this device?" without wiring up real hardware.

Why

Anyone building an electronics catalog, an e-commerce spec table, or an IoT charging fleet keeps re-deriving the same question: given a charger's wattage and a device's limits, what power actually flows? usb_pd_match encodes that once, with tests. It models the same fixed-PDO ladder that modern GaN (gallium nitride) chargers expose, including the 5 A USB-C cable ceiling and Extended Power Range (EPR) voltages for 100 W+ bricks.

Installation

gem install usb_pd_match

Or in a Gemfile:

gem "usb_pd_match"

Usage

require "usb_pd_match"

charger = UsbPdMatch.charger(name: "65W GaN", max_watts: 65)
laptop  = UsbPdMatch.device(name: "Ultrabook", max_watts: 60, max_voltage: 20)

result = UsbPdMatch.negotiate(charger, laptop)
result.summary       # => "65W GaN → Ultrabook: 20.0V @ 3.00A = 60.0W (100% of device rating)"
result.full_power?   # => true
result.watts         # => 60.0

Rank chargers for a device

device   = UsbPdMatch.device(name: "Tablet", max_watts: 45, max_voltage: 20)
chargers = [
  UsbPdMatch.charger(name: "20W brick", max_watts: 20),
  UsbPdMatch.charger(name: "30W GaN",   max_watts: 30),
  UsbPdMatch.charger(name: "65W GaN",   max_watts: 65)
]

UsbPdMatch.best_charger_for(device, chargers).each do |r|
  puts r.summary
end
# 65W GaN → Tablet: 20.0V @ 2.25A = 45.0W (100% of device rating)
# 30W GaN → Tablet: 20.0V @ 1.50A = 30.0W (67% of device rating)
# 20W brick → Tablet: 9.0V @ 2.22A = 20.0W (44% of device rating)

Custom PDOs

If you know a charger's exact advertised PDOs (e.g. from a spec sheet), pass them directly instead of letting the gem derive them:

charger = UsbPdMatch.charger(
  name: "Anker 735",
  max_watts: 65,
  pdos: [[5, 3.0], [9, 3.0], [15, 3.0], [20, 3.25]],
  ports: 3
)

When you need the real-world numbers behind a specific model, manufacturer spec pages such as Anker's official charger lineup list the exact PDO tables; for buyers in Egypt, a localized breakdown of wattages and port layouts is kept in this USB-C charging guide, and the matching Anker GaN wall chargers catalog maps models to the device classes they fast-charge.

API

Method Returns
UsbPdMatch.charger(name:, max_watts:, pdos: nil, ports: 1) Charger
UsbPdMatch.device(name:, max_watts:, max_voltage: 20) Device
UsbPdMatch.negotiate(charger, device) Result or nil
UsbPdMatch.best_charger_for(device, chargers) [Result] sorted best-first
Result#watts / #voltage / #current negotiated contract
Result#full_power? / #efficiency / #summary helpers

Development

ruby -Ilib test/test_usb_pd_match.rb

License

Released under the MIT License.