An easy, SerialPort or Xterm.js based, MicroPython REPL for micro controllers
npm install micro-replSocial Media Photo by Luca J on Unsplash
An easy, SerialPort based, MicroPython REPL for micro controllers.
* Live Serial Demo
Live PyScript Demo which uses MicroPython* on the browser to communicate with the boards 🤯
It is very likely that your MicroPython based board works too but these have been manually, and personally, tested during the development of this module:
* Spike Prime
* Raspberry Pi Pico and Pico W
* Adafruit PyPortal - CircuitPython
* Arduino Nano ESP32
I used dfu-util -a 0 -d 0x2341:0x0070 -D ./ARDUINO_NANO_ESP32-X.app-bin to install MicroPython on it: app-bin download
- - -
The currently maintained and developed export is micro-repl/serial (previously known as board) which supports the following features:
board name showed as soon as connected and associated to the board* instance
fully interactive REPL* mode out of the box
* tab completion works out of the box too
every Control+X* combination just works
stopping running code via Control+C* also works
* uploading data (text or binary files) works too
* pasting code also works
* paste mode never overflows the writes (big files copy pasted with ease)
safe (after prompt) reboot on Control-D when not inside a paste mode* session
* ondata(buffer:Uint8Array) passes along, while interacting, every single char the user is asking for
AutoFit and WebLinks* plugins available out of the box
* all imports are dynamic so it's size is still minimal before its usage
eval method, if awaited and the end of the code has a reference or an expression, will return that value, if any, beside evaluating code without showing it on REPL* shell. If the extra options reference hidden value is false, it also shows the evaluated code while streaming it to the board.
paste method to pass along code in "paste mode*" with ease, where raw: true is also available
The micro-repl/board alias still exists but it's now micro-repl/serial instead, to eventually allow micro-repl/bt and others within the same ease of use.
The easiest way to use micro-repl/serial is via CDN:
``html`
Documented via JSDoc TS, these are all explicit TS details around this module's API.
#### options
These are all optional fields that can be passed when creating a new Serial.
`ts`
type MicroREPLOptions = {
// default: 115200
baudRate?: number | undefined;
// default: 'buffer'
dataType?: 'buffer' | 'string';
// default: console.error
onerror?: ((error: Error) => void) | undefined;
// default: () => void - notifies when the board is connected
onconnect?: (() => void) | undefined;
// default: () => void - notifies when the board is disconnected/lost
ondisconnect?: (() => void) | undefined;
// default: () => void - receives all data from the terminal
ondata?: ((buffer: Uint8Array) => void) | undefined;
// allow terminal easy-theme setup - if values are "infer"
// these are retrieved via computed style / CSS values
// for background (or background-color) and color (as foreground)
// default: { background: "#191A19", foreground: "#F5F2E7" }
theme?: {
background: string;
foreground: string;
} | undefined;
}
#### serial board
A serial board can be created via new Serial(options) or just direct Serial(options) ( which is more Pythonic ) and its returned reference is always an instanceof Serial.
`tstrue
type MicroREPLSerialBoard = {
// when connected, false otherwisebaudRate
readonly connected: boolean;
// the passed optiontarget
readonly baudRate: number;
// the connected board name
readonly name: string;
// the Terminal reference once connected
readonly terminal: xterm.Terminal;
// ⚠️ must be done on user action !!!
// connects the board and show the REPL in the specified target
// can be either a DOM Element or an element ID or a CSS selector.code
connect: (target: Element | string) => Promise
// disconnect the board and invoke ondisconnect
disconnect: () => Promise
// soft-reset the board and put it back into REPL mode
reset: () => Promise
// write any string directly to the board
write: (code: string) => Promise
// eval any code (no output while processing)
// if the end of the is a reference, it triesfalse
// to json serialize it and parse it back as result.
// if the options.hidden is it shows the inputFile
// while evaluating code.
eval: (code: string, options?: { hidden:boolean }) => Promise
// enter paste mode, write all code, then exit from paste mode
paste: (code: string, options?: { hidden:boolean, raw:boolean }) => Promise
// upload content as text or and save it as path name`
upload: (path: string, content: string | File, on_progress?: (current:number, total:number) => void) => Promise
}
Please note that board.write(code) requires \r\n at the end if you want your code to be executed.
Please also note this is not the same as board.terminal.write(...) because the terminal depends on writes on the board, not vice-versa.
- - -
WARNING
Please note this module is experimental. The current exports might change if actually the board reference is the best option this module offers (and I am definitively leading toward this conclusion).
- - -
If you are on Linux and you can't see your Prime you can try to force-enable it by writing the following content into /etc/udev/rules.d/50-myusb.rules:
``
KERNEL=="ttyACM[0-9]*",MODE="0666"
After a reboot, this instruction should enable it and you should see it selectable.
This project has been inspired by pyrepl-js but because I think React and TypeScript, plus the rest of the logic, was a bit too much for a basic core REPL, I've decided to create a minimal JS standard module able to do pretty much the same in way less code to maintain. Feel free to use that project if you want a more rich UI around the connection, events instead of just promises to deal with unbuffered data as sent by the controller, and everything else in there which I didn't need to create those live demoes.
#### micro-repl TS signature
deprecated
Once a repl has been successfully initialized, it offers this API:
`ts`
// The default export TS signature
({ baudRate, onceClosed, }?: {
baudRate: number; // default: 115200
onceClosed(error: Error | null): void;
}) => Promise<{
readonly active: boolean;
readonly result: Promise
readonly output: Promise
write: (code: string) => Promise<...>;
close: () => Promise<...>;
}>
#### Signature description
repl.active as boolean - it's true when the REPL* is active and running, false otherwise.Promise
* repl.result as - it contains the last line produced by the last executed code.Promise
* repl.output as - it awaits for the last executed code to execute and returns whatever that code produced, including the written code itself. Please note this throws an error if the active state is not true.(code:string) => Promise
repl.write(code) as - it writes code to the boards' REPL* and it fulfills after all code has been sent. Please note this throws an error if the active state is not true.() => Promise
* repl.close() as - it detaches all streams and gracefully clean up the repl state right before disconnecting it.
`js
// check the board status
repl.active; // true
// write code into the REPL
await repl.write('print("Hello MicroPython")');
// wait/check the produced REPL outcome
await repl.output;
/**
* >>> print("Hello MicroPython")
* Hello MicroPython
*/
// check the result (last printed line of the REPL)
await repl.result; // "Hello MicroPython"
// disconnect the board
await repl.close();
// check the board status again
repl.active; // false
``