lpf2

Talk to LEGO Powered Up motors, sensors, lights and hubs.

The ports on your hub (hub.ports.A …) are port objects: use them to see what’s plugged in and to drive motors. lpf2 also lets you connect to other LEGO hubs over Bluetooth (hub) or make your hub pretend to be a LEGO hub (hub_emulation). Useful lists of numbers live in sub-modules like color and device_type.

Submodules

Classes

battery

Advanced: battery level calculation for custom battery setups.

device_descriptor

Advanced: describes a pretend device — its modes and version numbers.

hub

Connect to another LEGO hub (Powered Up, Control+, BOOST…) over Bluetooth.

hub_emulation

Make your hub pretend to be a LEGO hub, so LEGO apps can connect to it.

mode

Advanced: describes one "mode" of a device — one kind of value it can report or accept.

motor_setting

Advanced: the tuning values used for each kind of LEGO motor.

port

A port where a LEGO motor, sensor or light can be plugged in.

version

A version number made of Major.Minor.Bugfix.Build.

Package Contents

class lpf2.battery[source]

Advanced: battery level calculation for custom battery setups.

For the hub’s own battery use hub.battery instead. Here you can set what voltage counts as full (default 9000 mV) and empty (default 6000 mV); the percentage is worked out between those two. Use it as lpf2.battery.getPercent() — no need to create one.

static getCurrentVoltage() → int[source]

Get the last-known current battery voltage in mV.

static getMaxVoltage() → int[source]

Get the full-charge voltage in mV.

static getMinVoltage() → int[source]

Get the cut-off (0%) voltage in mV.

static getPercent() → int[source]

How full the battery is, 0..100 %, based on the current voltage.

static readBatteryVoltage() → int[source]

Measure the battery now (see setupAdcDivider()) and return millivolts, or 0 if not set up.

static setCurrentVoltage(mv: int) → None[source]

Manually update the current battery voltage (mV).

Use this if you have your own voltage source (not the built-in ADC divider).

static setMaxVoltage(mv: int) → None[source]

Set the full-charge voltage in mV.

static setMinVoltage(mv: int) → None[source]

Set the cut-off (0%) voltage in mV.

static setPercentFunc(fn: Callable[[int, int, int], int] | None) → None[source]

Use your own function to turn a voltage into a percentage.

fn(mV, vmin, vmax) must return 0..100. Pass None to go back to the default (a straight line between empty and full).

static setupAdcDivider(adc_channel: int, adc_unit: int, r_top_ohms: float, r_bottom_ohms: float, vref_mv: int = 3300, samples: int = 8) → bool[source]

Advanced: measure a battery through a voltage divider on an analog pin.

adc_channel / adc_unit pick the ESP32 analog input; r_top_ohms / r_bottom_ohms are the two resistors (battery → middle → ground). Returns True if it worked.

class lpf2.device_descriptor[source]

Advanced: describes a pretend device — its modes and version numbers.

Used together with lpf2.virtual.device.

fwVersion: version[source]

Firmware version reported by the device.

hwVersion: version[source]

Hardware version reported by the device.

modes: list[mode][source]

List of mode descriptors, indexed by mode number.

class lpf2.hub[source]

Connect to another LEGO hub (Powered Up, Control+, BOOST…) over Bluetooth.

Call init() to start searching, wait until isConnected() and infoReady() are True, then use getPort() to control its motors and sensors — just like your own ports.

connectHub() → bool[source]

Try to connect to the hub that was found. Returns True if it worked.

getAllInfoStr() → str[source]

Everything known about the other hub and its ports, as text.

getBatteryType() → int[source]

What kind of batteries the other hub uses (see lpf2.battery_type).

getHubAddress() → str[source]

The other hub’s Bluetooth address.

getHubPropStr(prop_id: int) → str[source]

One fact about the other hub as text, e.g. its firmware version (see lpf2.hub_property).

getHubType() → int[source]

What kind of hub it is (see lpf2.hub_type).

getName() → str[source]

The other hub’s name.

getPort(port_num: int) → port | None[source]

One of the other hub’s ports, or None if it doesn’t exist.

Port numbers depend on the hub type — see lpf2.port_num, e.g. lpf2.port_num.poweredup.A. The port works like hub.ports.A.

infoReady() → bool[source]

True once the other hub has told us all about itself and its ports. Wait for this before using getPort().

init(addr_or_scan: str | int | None = None, scan_duration: int = 10) → None[source]

Start searching for a LEGO hub to connect to.

addr_or_scan can be a hub’s Bluetooth address (text like "aa:bb:cc:dd:ee:ff") to connect to that exact hub, a number of seconds to search for, or left out to search for scan_duration seconds.

isConnected() → bool[source]

True while connected to the other hub.

isConnecting() → bool[source]

True while trying to connect.

isScanning() → bool[source]

True while searching for hubs.

setName(name: str) → None[source]

Rename the other hub. It remembers the new name.

setPortMode(port_num: int, mode: int, delta: int, notify: bool = True) → int[source]

Advanced: choose which value a port on the other hub reports. Returns 0 if it worked.

setPortModeCombo(port_num: int, combo_idx: int, nibble_pairs: Sequence[int], deltas_per_mode: Sequence[int]) → int[source]

Advanced: have a port on the other hub report several values at once.

Each byte in nibble_pairs is mode * 16 + value number; deltas_per_mode lists the minimum change for each, in the same order.

shutDownHub() → None[source]

Turn the other hub off.

update() → None[source]

Advanced: process Bluetooth news right now. Not needed — the hub does this in the background.

class lpf2.hub_emulation[source]

Make your hub pretend to be a LEGO hub, so LEGO apps can connect to it.

Set it up first (name, battery…), choose which ports the app may use with attachPort(), then call start().

attachPort(port_num: int, p: port) → None[source]

Let the app use port p as port number port_num (0 = A, 1 = B, …).

Keep p in a variable for as long as the emulation runs.

getName() → str[source]

The hub name shown in the app.

setAlert(alert: int, on: bool) → None[source]

Turn a warning such as “low battery” on or off in the app (see lpf2.alerts).

setBatteryLevel(level: int) → None[source]

The battery level (0..100 %) shown to the app.

setBatteryType(type: int) → None[source]

The battery type shown to the app (see lpf2.battery_type).

setButtonState(state: int) → None[source]

Tell the app the hub’s button was pressed or released (see lpf2.button_state).

setFirmwareVersion(v: version) → None[source]

The firmware version shown to the app.

setHardwareVersion(v: version) → None[source]

The hardware version shown to the app.

setName(name: str) → None[source]

The hub name shown in the app.

setUseBuiltInDevices(use: bool) → None[source]

Also show the hub’s built-in light and motion sensor to the app (True) or only your attached ports (False).

Call this before start().

start() → None[source]

Become visible over Bluetooth so apps can connect.

stop() → None[source]

Stop pretending: disconnect and become invisible.

class lpf2.mode[source]

Advanced: describes one “mode” of a device — one kind of value it can report or accept.

For example a color sensor has a mode for color, one for reflected light, and so on. Holds the mode’s name and value ranges.

PCTmax: float[source]

Percent-scale maximum.

PCTmin: float[source]

Percent-scale minimum.

SImax: float[source]

SI-scale maximum.

SImin: float[source]

SI-scale minimum.

dataSets: int[source]

Number of datasets per sample.

decimals: int[source]

Decimals shown for display.

figures: int[source]

Total display figures (integer + decimals).

flags: int[source]

Capability/flags bitmask.

format: int[source]

Sample element format (0=int8, 1=int16, 2=int32, 3=float).

inMapping: int[source]

Input-mapping bitmask (see LWP spec).

max: float[source]

Raw value maximum.

min: float[source]

Raw value minimum.

motorBias: int[source]

Motor bias, per LWP.

name: str[source]

Mode name (from the device).

outMapping: int[source]

Output-mapping bitmask (see LWP spec).

rawData: bytes[source]

Latest raw payload for this mode.

class lpf2.motor_setting[source]

Advanced: the tuning values used for each kind of LEGO motor.

medium_linear: _motor_settings[source]

Medium linear motor.

technic_large_angular: _motor_settings[source]

Technic Large Angular motor.

technic_large_angular_grey: _motor_settings[source]

Technic Large Angular motor (grey Control+ variant).

technic_large_linear: _motor_settings[source]

Technic Large linear motor.

technic_medium_angular: _motor_settings[source]

Technic Medium Angular motor.

technic_medium_angular_grey: _motor_settings[source]

Technic Medium Angular motor (grey Control+ variant).

technic_xlarge_linear: _motor_settings[source]

Technic XL linear motor.

class lpf2.port[source]

A port where a LEGO motor, sensor or light can be plugged in.

hub.ports.A and friends are ports. Ask isDeviceConnected() whether something is plugged in, get it with device(), or drive a motor directly with startPower(), startSpeed() and friends. The hub keeps every port up to date in the background, so you just read the values.

Speeds and powers go from -100 to 100: the sign picks the direction.

device() → devices.basic_motor | devices.encoder_motor | devices.color_sensor | devices.distance_sensor | devices.port_expander | devices.hub_led | devices.accelerometer | devices.gyroscope | None[source]

The motor, sensor or light plugged into this port, or None if nothing is plugged in.

What you get depends on the device — for example an encoder_motor or a color_sensor — each with its own handy functions.

disable(disable: bool = True) → None[source]

Switch the port off (or back on with disable(False)).

While switched off the hub stops talking to the device and frees the port’s pins, so you can use them for something else — for example an LED strip (see the NeoPixel example).

enable() → None[source]

Switch a port back on after disable().

getCapabilities() → int[source]

Capability bitmask (bit 0x04 = combinable, if the device has combos).

getDeviceType() → int[source]

A number saying what kind of device is plugged in — compare it with lpf2.device_type.

getInfoStr() → str[source]

Everything the port knows about its device, as text. Handy to print while exploring.

getInputModes() → int[source]

Bitmask of modes that produce values.

getMode(num: int) → mode | None[source]

mode descriptor for mode num or None.

getModeCombo(combo: int) → int[source]

Mode-combo bitmask at index combo. Bit N = mode N.

getModeComboCount() → int[source]

Number of active mode-combo entries.

getModeCount() → int[source]

Total number of modes exposed by the device.

getOutputModes() → int[source]

Bitmask of modes that accept values.

getValue(mode: int, dataSet: int) → float[source]

Read a value from the device: value number dataSet (starting at 0) of mode.

Use this for devices that have no special class in lpf2.devices; otherwise their own functions are easier.

getValueStr(mode: int) → str[source]

The value(s) of mode as readable text.

getViewCount() → int[source]

Number of modes the device would show in the LEGO app.

gotoAbsPosition(absPos: int, speed: int = 100, maxPower: int = 100, endState: int = 0, useProfile: int = 0) → None[source]

Turn the motor to position absPos degrees, then stop.

Position 0 is where it was at start-up or where you last called presetEncoder(). speed is 0..100. endState says what the motor does afterwards: 0 = let it spin freely (coast), 127 = brake, 126 = hold its position.

init() → None[source]

Advanced: one-time setup hook. Does nothing by default.

isDeviceConnected() → bool[source]

True if something is plugged into this port.

isDisabled() → bool[source]

True while the port is switched off with disable().

presetEncoder(pos: int) → None[source]

Stop the motor and say “this position is now pos degrees” (usually 0).

rawToSpeed(raw: int) → int[source]

Advanced: convert a device byte (0..255) back to a -100..100 speed.

setAccTime(time: int, profile: int) → None[source]

How long (milliseconds) the motor takes to speed up, stored in slot profile (0..15).

Use it with the useProfile option of the speed functions.

setDecTime(time: int, profile: int) → None[source]

How long (milliseconds) the motor takes to slow down, stored in slot profile (0..15).

setMode(mode: int, delta: float = 1.0) → int[source]

Advanced: choose which kind of value the device should report (its “mode”).

delta is how much the value must change before an update is sent (0 = always). Returns 0 if it worked. The device classes in lpf2.devices pick modes for you.

setModeCombo(idx: int, deltas: Sequence[float] = ()) → int[source]

Advanced: have the device report several modes at once.

idx picks one of the device’s built-in combinations; deltas gives the minimum change for each mode in it. Returns 0 if it worked.

setRgbColor(r: int, g: int, b: int) → None[source]

Set a light to any color by mixing red, green and blue, each 0..255.

setRgbColorIdx(idx: int) → None[source]

Set a light to one of the colors in lpf2.color, e.g. color.RED.

speedToRaw(speed: int) → int[source]

Advanced: convert a -100..100 speed to the byte (0..255) the device uses.

startPower(pw: int) → None[source]

Run a motor at a power from -100 to 100.

Positive turns one way, negative the other, 0 stops. Works with every motor, even simple ones without a rotation sensor.

startSpeed(speed: int = 100, maxPower: int = 100, useProfile: int = 0) → None[source]

Run the motor at a steady speed from -100 to 100 until told otherwise.

Unlike startPower() the motor works harder uphill to keep its speed (needs a motor with a rotation sensor). maxPower (0..100) limits how hard it may push. useProfile picks the speed-up/slow-down times set with setAccTime() / setDecTime() (0x21 = speed up with slot 1, slow down with slot 2).

startSpeedForDegrees(degrees: int, speed: int = 100, maxPower: int = 100, endState: int = 0, useProfile: int = 0) → None[source]

Turn the motor by degrees (360 = one full turn), then stop.

Give a positive number of degrees; make speed negative to turn the other way. endState says what the motor does afterwards: 0 = let it spin freely (coast), 127 = brake, 126 = hold its position.

startSpeedForTime(time: int, speed: int = 100, maxPower: int = 100, endState: int = 0, useProfile: int = 0) → None[source]

Run the motor at speed for time milliseconds, then stop.

endState says what the motor does afterwards: 0 = let it spin freely (coast), 127 = brake, 126 = hold its position.

update() → None[source]

Advanced: check the port for news right now.

You don’t need this — the hub already does it for every port many times per second.

writeData(mode: int, buf: bytes) → int[source]

Advanced: send raw bytes to the device for mode. Returns 0 if it worked.

class lpf2.version[source]

A version number made of Major.Minor.Bugfix.Build.

Bugfix: int[source]

Bugfix version.

Build: int[source]

Build number.

Major: int[source]

Major version.

Minor: int[source]

Minor version.