Skip to main content

Live Wiring commands from Python to your microcontroller

Project description

liveduino

A live Python REPL for your board: type a command, watch the hardware react instantly.

Python uv Platform Arduino License


tests quality security firmware publish coverage


The Arduino API you already know, now live, from Python. Call pinMode, digitalWrite, analogRead and watch the board react right away: no compile, no upload, no flashing. Just Python talking to real hardware in real time.

It feels like a REPL for your circuit: type a line, the LED blinks; read a pin, the live value comes back. The Arduino edit-compile-upload loop is gone.

Connect any board, any way. USB, serial, Bluetooth, Wi-Fi or Ethernet: same code, same API, just point it at the wire you have. Prototype over USB on your desk, then drive the exact same board over Wi-Fi from across the room without changing a single line.

Not MicroPython. Not a sketch compiler. Not yet another pin-object API. If you know Arduino, you already know liveduino. There is nothing new to learn.

The spiritual successor to Frameduino, rebuilt from scratch for Python 3.13.


Table of Contents


About

Arduino's superpower is its API (pinMode, digitalWrite, analogRead): clean, famous, and loved by millions. Its workflow, though, is stuck in batch: write a sketch, compile it, upload it, wait, repeat. Every tiny change costs you a full round trip, and you never get to talk to the hardware while it runs.

liveduino keeps the API and kills the loop. Your code runs on the host and drives the board live over a wire protocol (StandardFirmata), so every command hits the hardware the instant you call it. Same function names. Same semantics. Zero new concepts. Now interactive, scriptable, and powered by Python 3.13.

Prototype faster, debug interactively, automate test rigs, drive sensors and actuators from your data pipeline, all without leaving Python. This realtime, line-by-line control is the original Frameduino vision, rebuilt from scratch for Python 3.13 and a growing catalog of boards.

How it works in one line: liveduino runs your Python on the computer and speaks to firmware already flashed on your board. It does not run Python on the chip or compile sketches, and that is exactly why it is instant.

(back to top)

Features

Zero learning curve If you know Arduino, you are already done. Same names, same semantics, in Python
Instant feedback Every digitalWrite / analogRead fires on the board now: no compile, no upload, no wait
Real device coverage Digital I/O, analog input, PWM, servo, and I2C (sensors, displays, ...) — all over the bundled StandardFirmata, no extra firmware
No dependency bloat Native StandardFirmata 2.x, written in-house. No third-party Firmata library to drag along
No Arduino IDE Flashes StandardFirmata itself in pure Python over the bootloader; no IDE, no avrdude, no toolchain
Connect any way One API over USB serial, Wi-Fi/Ethernet (TCP), or Bluetooth RFCOMM; just swap the driver
Batteries-included catalog Auto-discovered profiles for UNO, Nano, Mini, Pro Mini, Fio, and more; add a board by dropping a file
Typed and safe Literal types (PinMode, DigitalValue, BitOrder) with pins, modes, and values validated before they hit the wire
Rock-solid 100% unit-test coverage with mocks, plus real-hardware integration tests

(back to top)

Liveduino vs. the alternatives

Others make you learn a new API or a new language. liveduino bets on the one you already know.

liveduino pyFirmata / Telemetrix MicroPython
API style Arduino/Wiring (pinMode, digitalWrite) Library-specific Python on device
I2C / serial API Arduino Wire / Serial1 Library-specific Native Python
Code runs on Host Python Host Python Microcontroller
Firmware Stock StandardFirmata Firmata / a custom sketch MicroPython
Flashing Built in, pure Python (no Arduino IDE) Arduino IDE / avrdude esptool / external tool
Transports USB, Wi-Fi/Ethernet, Bluetooth (swap the driver) Serial (mostly) On-device
Learning curve for Arduino users Zero New API New language

What only liveduino does:

  • The Arduino API all the way down. Not just pinMode/digitalWrite: board.wire is Arduino's Wire, board.serial(1) is Serial1 (same begin/write/available/ read/end), plus servoWrite, analogRead, timing. A sketch ports almost line for line.
  • Runs on the StandardFirmata that's already everywhere. No custom firmware to build or maintain (Telemetrix needs its own); if the board already has StandardFirmata, liveduino just talks to it — and flashes it for you in pure Python if it doesn't.
  • The board self-describes. capabilities() reads each pin's real modes from the firmware and uses them over the hardcoded catalog.
  • One API over any wire. Swap USB, Wi-Fi/Ethernet, or Bluetooth by changing a single line, never your code.

(back to top)

Quick start

Prerequisites

Python 3.13+ is all you need to use liveduino (uv is only for developing it). Connect an Arduino UNO (or compatible) via USB and note its serial port (liveduino-cli ports lists them). No Arduino IDE, no avrdude, no toolchain — liveduino flashes the firmware for you next.

Install

pip install liveduino
# or
uv add liveduino

Requires Python 3.13+.

Flash the firmware

liveduino ships a prebuilt StandardFirmata image for each board and flashes it over the serial bootloader itself, in pure Python (it speaks STK500v1 and auto-resets the board via DTR/RTS). No Arduino IDE, no avrdude, no .hex file, no toolchain. One command and the board is ready:

liveduino-cli flash arduino:uno --port /dev/ttyACM0   # flash bundled StandardFirmata

That is the whole setup. The bundled image works offline, and flashing targets the ATmega328 family (UNO, Nano, Mini, Pro Mini, ...) today. Variants, custom .hex, and every option: docs/CLI.md.

Already flashed StandardFirmata yourself (e.g. from the Arduino IDE)? Skip this step, liveduino talks to whatever StandardFirmata build is already on the board.

Blink from Python

From zero to a blinking LED in a handful of lines, and it runs the moment you hit enter.

from liveduino import ArduinoUno, OUTPUT, HIGH, LOW

board = ArduinoUno().connect("/dev/ttyACM0")  # or COM3 on Windows
board.pinMode(13, OUTPUT)

while True:
    board.digitalWrite(13, HIGH)
    board.delay(1000)
    board.digitalWrite(13, LOW)
    board.delay(1000)

Read a pin

from liveduino import A0

val = board.analogRead(A0)  # same as analogRead(0); returns 0-1023
board.close()

More on analog pins and the full method table: docs/API.md.

(back to top)

How it works

Host Python (Board API, FirmataProtocol, Driver: serial/TCP/Bluetooth) talks to the Microcontroller (StandardFirmata, GPIO/ADC/PWM) and back

You call a plain Python method (board.pinMode(13, OUTPUT)); the board validates the pin, the protocol (what is spoken: Firmata) encodes it, and the driver (where it connects: serial, TCP, Bluetooth) ships the bytes. The two layers are decoupled, so a board works over any channel by swapping the driver, never your code.

Deep dive: docs/ARCHITECTURE.md.

(back to top)

Tech stack

Python 3.13+, stdlib-only (pyserial for serial; stdlib sockets for TCP/Bluetooth). Board subclasses expose camelCase Arduino methods over a native FirmataProtocol (StandardFirmata 2.x — no third-party Firmata library). Quality gate: pytest at 100% coverage, ruff, flake8, pylint, mypy, pyright, bandit.

(back to top)

Arduino API

Public board methods use camelCase to match Arduino/Wiring exactly: pinMode, digitalWrite, digitalRead, analogRead, analogWrite, servoWrite, plus host-side timing (delay, millis, ...). Device functions that StandardFirmata cannot perform (tone, pulseIn, shiftOut/shiftIn) exist for fidelity but raise UnsupportedOperationError.

What works over StandardFirmata today:

Capability Methods Firmware
Digital I/O pinMode, digitalWrite, digitalRead ✅ built in
Analog input analogRead ✅ built in
PWM output analogWrite ✅ built in
Servo servoWrite, servoConfig ✅ built in (Servo lib)
I2C board.wire (Arduino Wire) ✅ built in (Wire lib)
Discovery info, capabilities, pinState, status ✅ built in (Firmata queries)
Streaming & serial samplingInterval, readString, serial, continuous I2C ✅ built in
Host-side timing delay, delayMicroseconds, millis, micros ✅ host only
Tone / pulse / shift tone, noTone, pulseIn, shiftOut, shiftIn ⚠️ raise UnsupportedOperationError

Servo and I2C are the real Arduino names too. I2C is Arduino's Wire — alias it and a sketch ports verbatim:

board.servoWrite(9, 90)             # servo on pin 9

Wire = board.wire                   # in place of: #include <Wire.h>
Wire.begin()
Wire.requestFrom(0x68, 6, 0x3B)     # read 6 bytes from register 0x3B (MPU-6050)
while Wire.available():
    value = Wire.read()

Discovery — ask the board about itself instead of trusting the catalog:

board.info()          # firmware + board identity
board.status()        # live state of every pin
board.capabilities()  # per-pin modes read from the firmware (cached), else the catalog

Full method table, servo/I2C/discovery/serial details, and helpers: docs/API.md.

(back to top)

Supported boards

Arduino UNO is fully supported (StandardFirmata over USB serial). Nano, Mini, Pro Mini, Fio, Duemilanove/Diecimila, Ethernet, BT, LilyPad, and UNO Mini are supported; Mega, Leonardo, Micro, and Pinguino are planned. Board profiles are auto-discovered, so adding one is just dropping a file.

from liveduino import connect

board = connect("arduino:uno", "/dev/ttyACM0")

Full board table and how to add a board: docs/BOARDS.md.

(back to top)

Connections

One API, every wire. The board talks over a pluggable driver, so the same code runs over USB, Wi-Fi/Ethernet, or Bluetooth — you swap one line, never your code:

board = ArduinoUno().connect("/dev/ttyACM0")                          # USB serial (default)
board = ArduinoUno().connect(driver=TcpDriver("192.168.1.50", 3030))  # Wi-Fi / Ethernet
board = ArduinoUno().connect(driver=BluetoothDriver("AA:BB:CC:DD:EE:FF"))  # Bluetooth RFCOMM

Every driver and the protocol override: docs/CONNECTIONS.md.

(back to top)

Command-line interface

Installing liveduino adds the liveduino-cli console command, pure Python with no extra toolchain:

liveduino-cli flash arduino:uno --port /dev/ttyACM0   # flash bundled StandardFirmata (STK500v1)
liveduino-cli boards                                  # list catalog boards
liveduino-cli ports                                   # list serial ports

Full reference: docs/CLI.md.

(back to top)

Development

Requires Python 3.13 and uv.

uv python pin 3.13
uv sync --all-groups
make install-dev        # installs dev deps + pre-commit hooks
make check              # lint + type-check + 100% coverage gate

Every make target, the coverage gate, and how to run hardware integration tests: docs/DEVELOPMENT.md.

(back to top)

Legacy

Frameduino 0.x (Python 2, Pinguino-only) lives in the original Frameduino repository.

(back to top)

Documentation

Document Audience Contents
This README Everyone Motivation, quick start, overview
docs/API.md Users Full Arduino method table and analog pin model
docs/BOARDS.md Users Supported boards and how to add one
docs/CONNECTIONS.md Users Drivers (serial, TCP, Bluetooth) and protocol override
docs/CLI.md Users liveduino-cli command: flash firmware, list boards and ports
docs/DEVELOPMENT.md Contributors Setup, make targets, and tests
docs/ARCHITECTURE.md Contributors Layers, data flow, drivers, analog pins, testing
firmware/arduino/README.md Users StandardFirmata setup and serial settings
AGENTS.md AI agents Coding standards and guardrails

(back to top)

License

Distributed under the MIT License.

(back to top)

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

liveduino-0.2.1.tar.gz (291.7 kB view details)

Uploaded Source

Built Distribution

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

liveduino-0.2.1-py3-none-any.whl (220.7 kB view details)

Uploaded Python 3

File details

Details for the file liveduino-0.2.1.tar.gz.

File metadata

  • Download URL: liveduino-0.2.1.tar.gz
  • Upload date:
  • Size: 291.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for liveduino-0.2.1.tar.gz
Algorithm Hash digest
SHA256 8d7c87ba6974a66aa171efe74d117f8712f7754c99a7919790948b06d5dba332
MD5 d5d1d1f5a416782772547ea2d1b9c203
BLAKE2b-256 cb64d9fb1a000b68e318d9cba78c8cf6306dbe3e371bd170afb2291bbac23c58

See more details on using hashes here.

File details

Details for the file liveduino-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: liveduino-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 220.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for liveduino-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4f58d854237212890879b182b8f8d955cc46070b295e0adb31e2d71239507212
MD5 8185818b84fc43f38e5456baf5ae19ac
BLAKE2b-256 d9de4b7aecf955f1236bcb107a8e51ef6f4037cb8dfaee6e5ef3cf8d6c25a870

See more details on using hashes here.

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