Skip to main content

Tests PyPI Python Version

nrf-ota

Flash firmware to Nordic nRF5x devices over BLE from Python. Implements the Nordic Legacy DFU protocol (nRF5 SDK ≤ 15.x) and works on Linux, macOS, and Windows.

Installation

pip install nrf-ota

CLI

Run using uvx:

uvx nrf-ota firmware.zip                                  # interactive device picker
uvx nrf-ota https://example.com/firmware.zip              # download then flash
uvx nrf-ota firmware.zip --device OD216205                # select by name
uvx nrf-ota firmware.zip --device FC:06:1C:C8:DE:47       # select by address

Accepts a local ZIP path or an HTTP(S) URL. Scans for nearby BLE devices, lets you pick one, and flashes the firmware. If the device is running application firmware the bootloader is triggered automatically.

Library

import asyncio
from nrf_ota import perform_dfu, scan_for_devices

async def main():
    devices = await scan_for_devices(timeout=5.0)

    # local file
    await perform_dfu("firmware.zip", devices[0], on_progress=lambda pct: print(f"\r{pct:.0f}%", end=""))

    # or a URL — downloads and flashes in one call
    await perform_dfu("https://example.com/firmware.zip", devices[0])

asyncio.run(main())

API

perform_dfu(zip_path, device, *, on_progress=None, on_log=None, packets_per_notification=...)

Performs a full OTA update, triggers the bootloader if needed, waits for the device to reboot into DFU mode, transfers the firmware, and activates it.

Parameter Type Description
zip_path str | DFUZipInfo Local path, HTTP(S) URL, or pre-parsed DFUZipInfo
device BLEDevice | str Device from scan_for_devices, or a raw Bluetooth address
on_progress Callable[[float], None] Called with percentage (0–100) as firmware is sent
on_log Callable[[str], None] Called with status messages
packets_per_notification int Packets sent per receipt notification. Default: 8 on macOS, 10 elsewhere.

Raises DFUError on failure, DeviceNotFoundError if the bootloader can't be found after reboot.

DFUZipInfo

Named tuple returned by parse_dfu_zip. Can be passed directly to perform_dfu to skip re-parsing:

from nrf_ota import perform_dfu, parse_dfu_zip

info = parse_dfu_zip("firmware.zip")
print(f"{info.bin_file}  {len(info.firmware):,} bytes")
await perform_dfu(info, device)

scan_for_devices(timeout=5.0) -> list[BLEDevice]

Scans for nearby named BLE devices and returns a list of bleak.BLEDevice objects.

Exceptions

Exception Description
DFUError Base exception for all DFU failures
DeviceNotFoundError Bootloader not found after reboot

Platform notes

Works on Linux, macOS, and Windows via bleak. On macOS, the default packets_per_notification is lowered to 8 (from 10) to stay within CoreBluetooth's write-without-response flow control limits.

Development

git clone https://github.com/OpenDisplay-org/nrf-ota.git
cd nrf-ota
uv sync --all-extras

uv run pytest tests/ -v
uv run ruff check .
uv run mypy src/nrf_ota

Metadata

Release files for nrf-ota 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nrf-ota 0.4.0
File Size Uploaded
nrf_ota-0.4.0.tar.gz 85.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nrf-ota 0.4.0
File Interpreter ABI Platform
nrf_ota-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 108.2 kB

Release files / nrf_ota-0.4.0.tar.gz

Download URL nrf_ota-0.4.0.tar.gz
Size 85.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4e645a1db9df600020ec4127e0dbfde79b684b431f7ccd71dce270f5a4f3f6a9
BLAKE2b-256 checksum
How to use checksums
986625b62e03883c589f13fe3c3793929e08178202f3d2d8e581a22c66e5afff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Release files / nrf_ota-0.4.0-py3-none-any.whl

Download URL nrf_ota-0.4.0-py3-none-any.whl
Size 23.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
073613c7a1d58b2bf7866b13d6ccf2c435128f7e585dbc18d7d44f9939cd4972
BLAKE2b-256 checksum
How to use checksums
c7e4ae471c72f2b3dc8e219002478bf90434e6f4e8ebb23d0e4513b1f7fbff99
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page