Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MicroPython API


MicroPython lets you prototype and build your applications quickly without having to dive into any low level programming. With a few lines of Python, you can draw to the display, access the camera, and offload processing to the FPGA. Of course you get all the other benefits of Python too. Best of all, it’s completely wireless, and you can access the Python REPL fully over Bluetooth.

The MicroPython firmware for Monocle is a customized firmware which is largely based on the upstream MicroPython project. Thanks to the large MicroPython community, we’re always updating to new features as they come out on the upstream project.

A subset of the standard MicroPython libraries are currently supported, with more periodically being added. Additionally, some extra modules are included which let you easily interact with the Monocle hardware. Be sure to check out the MicroPython docs site, as well as the docs here to familiarize yourself with all the features.


Getting start

Brilliant AR Studio for VSCode

Accessing MicroPython on Monocle using the web REPL interface

Get started by trying out the VSCode extension on PC or MacOS. Once installed:

  • Initialize a new project using the command Ctrl-Shift-P (Cmd-Shift-P on MacOS) → Brilliant AR Studio: Initialize new project folder.
  • Then connect to Monocle by brining it close and running the command Ctrl-Shift-PBrilliant AR Studio: Connect.
  • Copy paste the example below into main.py and save the file.

      import touch
      import display
    
      def change_text(button):
          new_text = display.Text(f"Button {button} touched!", 0, 0, display.WHITE)
          display.show(new_text)
    
      touch.callback(touch.BOTH, change_text)
    
      initial_text = display.Text("Tap a touch button", 0, 0, display.WHITE)
      display.show(initial_text)
    
  • After a few moments, you should be able to touch each of the touch pads on Monocle, and see the display update.

WebREPL Console

Monocle also supports bare scripting from a custom app. The Web Bluetooth REPL is a good starting point for debugging and using as a template for building your own web apps. Try it from Google Chrome on your PC, Mac, Android, or a Web Bluetooth compatible web browser on your iOS device such as Bluefy.

Check out the full instructions and the source code here.

Accessing MicroPython on Monocle using the web REPL interface


Library reference

MicroPython for Monocle is always being updated so be sure to check back frequently. The ❌ icon signifies a feature which is not implemented yet, but is planned.

  1. builtins
  2. device – Monocle specific
  3. display – Monocle specific
  4. camera – Monocle specific
  5. microphone – Monocle specific
  6. touch – Monocle specific
  7. led – Monocle specific
  8. fpga – Monocle specific
  9. bluetooth - Monocle specific
  10. time – Monocle specific
  11. update - Monocle specific
  12. gc
  13. math
  14. micropython
  15. uarray
  16. uasyncio
  17. ubinascii
  18. ucollections
  19. uerrno
  20. uhashlib
  21. uio
  22. ujson
  23. uos
  24. urandom
  25. ure
  26. uselect
  27. ustruct
  28. usys

builtins

Standard MicroPython built in functions are supported.

Example

import builtins
help(builtins) # Lists all of the built-in MicroPython functions

device – Monocle specific

The device class contains general information about the Monocle’s hardware and firmware.

MembersDescription
NAME constantConstant which holds 'monocle' as a string.
mac_address() functionReturns the 48-bit MAC address as a 17 character string in the format 'xx:xx:xx:xx:xx:xx', where each xx is a byte in lowercase hex format.
VERSION constantConstant containing the firmware version as a 12 character string. E.g. 'v22.342.1252'.
GIT_TAG constantConstant containing the build git tag as a 9 character string.
GIT_REPO constantConstant containing the project git repo as a string.
battery_level() functionReturns the battery level percentage as an integer.
reset() functionResets the device.
reset_cause() functionReturns the reason for the previous reset or startup state. These can be either:
- 'POWERED_ON' if the device was powered on normally
- 'SOFTWARE_RESET' if device.reset() was called
- 'CRASHED' if the device had crashed.
prevent_sleep(enable) functionEnables or disables sleeping of the device when put back into the charging case. Sleeping is enabled by default. If no argument is given. The currently set value is returned. WARNING: Running monocle for prolonged periods may result in display burn in, as well as reduced lifetime of components.
force_sleep() functionPuts the device to sleep. All hardware components are shut down, and Bluetooth is disconnected. Upon touching either of the touch pads, the device will wake up, and reset.
Storage(start, length) classThe Storage class is used internally for initializing and accessing the file system. This class shouldn’t be accessed, unless you want to reformat the internal storage. To learn more about how MicroPython handles user files, have a look at the documentation here and here.

Example

import device
device.VERSION # Prints the device firmware version
device.battery_level() # Returns the current battery level as a percentage

display – Monocle specific

The display module allows for drawing to the micro OLED display.

MembersDescription
Text(string, x, y, color, justify=TOP_LEFT) classCreates a text object at the coordinate x, y which can be passed to display.show(). string can be any string, and color should be an RGB hex value with the format 0xRRGGBB. If the justify parameter is given, the text will be justified accordingly from the x, y coordinate.
Rectangle(x1, y1, x2, y2, color) classCreates a rectangle object which can be passed to display.show(). x1, y1 and x2, y2 define each corner of the rectangle. color should be an RGB hex value with the format 0xRRGGBB.
Fill(color) classCreates a colored box object which fills the entire screen, and can be passed to display.show(). color should be an RGB hex value with the format 0xRRGGBB.
Line(x1, y1, x2, y2, color, thickness=1) classCreates a line object from x1, y1 to x2, y2 which can be passed to display.show(). color should be an RGB hex value with the format 0xRRGGBB, and thickness can optionally be provided to override the default line thickness in pixels.
VLine(x, y, height, color, thickness=1) classCreates a vertical line object from position x, y with a length of height which can be passed to display.show(). color should be an RGB hex value with the format 0xRRGGBB, and thickness can optionally be provided to override the default line thickness in pixels.
HLine(x, y, width, color, thickness=1) classCreates an horizontal line object from position x, y with a length of width which can be passed to display.show(). color should be an RGB hex value with the format 0xRRGGBB, and thickness can optionally be provided to override the default line thickness in pixels.
Polygon([x1, y1, ... xn, yn], color) classCreates a polygon object which can be passed to display.show(). The first parameter should be a list of coordinates, and color should be an RGB hex value with the format 0xRRGGBB. Polygons are always closed shapes, therefore if the last coordinate does not close the shape, it will be closed automatically.
Polyline([x1,y1,...xn,yn],color,thickness=1) classSimilar to the Polygon object, Polyline creates a shape based on a list of coordinates. Unlike Polygon, Polyline does not need to be a closed shape. color should be an RGB hex value with the format 0xRRGGBB, and thickness can optionally be provided to override the default line thickness in pixels.
show(object_1, ... object_n) functionPrints to the display. The passed arguments can be any number of Text, Line, Rectangle, Polygon, or Polyline objects, or any number of lists containing such objects. Objects are layered front to back, i.e. object_1 is shown on top of object_n.
move(x, y) functionmove() can be called as a class method on any printable object to translate its position. x and y will move the object relative to its current position.
move([objects], x, y) functionAdditionally, move() can be called as a standard function to move a list of objects together. This is useful for grouping printable objects together and moving them as layers.
color(color) functioncolor() can be called as a class method on any printable object to change its color. color should be an RGB hex value with the format 0xRRGGBB.
color([objects], color) functionAdditionally, color() can be called as a standard function to change the color on a whole list of objects. color should be an RGB hex value with the format 0xRRGGBB.
brightness(level) functionSets the display’s brightness. level can be 0 (dimmest), 1, 2, 3, or 4 (brightest). Level 3 is the default.
clear() functionClears the display.
CLEAR constantEqual to 0x000000.
RED constantEqual to 0xad2323.
GREEN constantEqual to 0x1d6914.
BLUE constantEqual to 0x2a4bd7.
CYAN constantEqual to 0x29d0d0.
MAGENTA constantEqual to 0x8126c0.
YELLOW constantEqual to 0xffee33.
WHITE constantEqual to 0xffffff.
GRAY1 constantEqual to 0x1c1c1c.
GRAY2 constantEqual to 0x383838.
GRAY3 constantEqual to 0x555555.
GRAY4 constantEqual to 0x717171.
GRAY5 constantEqual to 0x8d8d8d.
GRAY6 constantEqual to 0xaaaaaa.
GRAY7 constantEqual to 0xc6c6c6.
GRAY8 constantEqual to 0xe2e2e2.
TOP_LEFT constantJustifies a text object on its x, y coordinate to the top left.
MIDDLE_LEFT constantJustifies a text object on its x, y coordinate to the middle left
BOTTOM_LEFT constantJustifies a text object on its x, y coordinate to the bottom left
TOP_CENTER constantJustifies a text object on its x, y coordinate to the top center
BOTTOM_CENTER constantJustifies a text object on its x, y coordinate to the middle center
TOP_RIGHT constantJustifies a text object on its x, y coordinate to the bottom center
MIDDLE_CENTER constantJustifies a text object on its x, y coordinate to the top right
MIDDLE_RIGHT constantJustifies a text object on its x, y coordinate to the middle right
BOTTOM_RIGHT constantJustifies a text object on its x, y coordinate to the bottom right
WIDTH constantThe display width in pixels. Equal to 640.
HEIGHT constantThe display height in pixels. Equal to 400.

This shows, for a given coordinate (x,y) used as reference, where the text will be placed:

Illustration of the `justify=...` parameter

import display

# Place some text in the middle of the screen with a line underneath
text = display.Text('Hello world', 320, 200, display.WHITE, justify=display.MIDDLE_CENTER)
line = display.Line(175, 230, 465, 230, display.WHITE)
display.show(text, line)

# Group the line and the text together to change the color of both at the same time
group = [text, line]
display.color(group, display.GREEN)
display.show(group)

# Move the line above the text, and print everything again
line.move(0, -75)
display.show(group)

# Create a white polygon with a red outline and print everything again
poly = display.Polygon([0, 0, 639, 399, 0, 399], display.WHITE)
outline = display.Polyline([0, 0, 639, 399, 0, 399, 0, 0], display.RED)
display.show(text, line, outline, poly)

camera – Monocle specific

The camera module allows for capturing images and transferring them to another device over Bluetooth.

MembersDescription
capture() functionCaptures an image and returns it to a device over Bluetooth. See downloading media to understand how media transfers are done.
overlay(enable) functionEnables or disables an overlay of what the camera is currently seeing onto the display.
output(x,y,format) function ❌Set the output resolution and format. x and y represent the output resolution in pixels. format can be either RGB, 'YUV' or 'JPEG'. The default output settings are camera.output(640, 400, 'YUV').
zoom(multiplier) functionSets the zoom level of the camera. Multiplier can be any floating point number between 1 and 8.
RGBconstantString constant which represents a RGB565 output format.
YUVconstantString constant which represents a YUV422 output format.
JPEGconstantString constant which represents a jpeg output format.

Example

import camera
camera.overlay(True) # Turns on mirroring from the camera to the display
camera.overlay(False) # Turns off mirroring from the camera to the display

microphone – Monocle specific

The microphone module allows for capturing audio and streaming it to another device over Bluetooth.

MembersDescription
stream() function ❌Streams audio from the microphone to a device over Bluetooth. See downloading media to understand how media transfers are performed.

touch – Monocle specific

The touch module allows for reacting to touch events from the capacitive touch pads on Monocle.

MembersDescription
callback(pad,callback) functionAttaches a callback handler to one or both of the touch pads. If pad is given as touch.BOTH, a single callback will be used to capture both touch events. Otherwise touch.A or touch.B can be used to assign separate callback functions if desired. callback should be a predefined function taking one argument. This argument will equal the pad which triggered the callback. To unassign a callback, issue touch.callback() with None in the callback argument. To view the currently assigned callback, issue touch.callback() without the callback argument.
state(pad) functionReturns the current touch state of the touch pads. If pad is not specified, either 'A', 'B', 'BOTH' or None will be returned depending on which pads are currently touched. If pad is specified, then True or False will be returned for the touch state of that pad.
A constantString constant which represents Pad A.
B constantString constant which represents Pad B.
BOTH constantString constant which represents both pads.

Example

import touch

# Define the touch callback function which is triggered upon a touch event
def fn(arg):
    if arg == touch.A:
        print("button A pressed!")
    if arg == touch.B:
        print("button B pressed!")

touch.callback(touch.BOTH, fn) # Attaches the callback to the both buttons
touch.callback(touch.A, fn) # Attaches the callback to an individual button

led – Monocle specific

The LED module contains functions to control the red and green LED on the front of Monocle.

MembersDescription
on(color) functionIlluminates an led. color can be either led.RED or led.GREEN.
off(color) function Turns off an led. color can be either led.RED or led.GREEN.
RED constantString constant which represents the red led.
GREEN constantString constant which represents the green led.

Example

import led
led.on(led.GREEN) # Turns on the green LED
led.on('GREEN') # Also turns on the green LED
led.off(led.GREEN) # Turns off the green LED
led.on(led.RED) # Turns on the red LED
led.off(led.RED) # Turns off the red LED

fpga – Monocle specific

The FPGA module allows for communicating with the FPGA over the internal SPI bus.

MembersDescription
read(addr, n) functionReads n number of bytes from the 16-bit address addr, and returns a bytes object.
write(addr,bytes[]) functionWrites all bytes from a given bytes object bytes[] to the 16-bit address addr.

Example

import fpga
fpga.read(0x1234, 5) # Reads 5 bytes from some FPGA register (0x1234 in this case)
fpga.write(0x1234, b'\x01\x02\x03') # Writes three bytes (1, 2, 3) to the FPGA register 0x1234
fpga.write(0x1234, b'hello fpga') # Writes the byte string 'hello fpga' to the FPGA register
fpga.write(0x1234, b'') # Doesn't write anything specific, but acts as a command or trigger

bluetooth - Monocle specific

The bluetooth module can be used to transfer byte data between Monocle and the host Bluetooth device. Bytes can contain any arbitrary data, and avoids having to pollute the REPL interface with printing data out as strings. The raw data service is used for all communications under the bluetooth module.

MembersDescription
send(bytes[]) functionSends data from a bytes object bytes[] over Bluetooth using the raw data service. The length of bytes[] must be equal to or less than the value returned by the bluetooth.max_length() function.
receive_callback(callback) functionAssigns a callback to receive data over the raw data service. callback must be a predefined function taking one argument. The value of the argument will be a bytes object bytes[] containing the received data. To unbind the callback, issue this function with callback set as None. If callback isn’t given when issuing this function, the currently set callback will be returned if it is set.
connected() functionReturns True if the raw data service is connected, otherwise returns False.
max_length() functionReturns the maximum data size the Bluetooth host allows for single transfers.

Example

import bluetooth
bluetooth.connected() # Returns True if the Bluetooth is connected. Always true when using the REPL, but useful for saved scripts
len = bluetooth.max_length() # Returns the maximum payload size we can send in one go

str = "hello world"
bluetooth.send(str[:len]) # Sends the string 'hello world' to the host. Limited by the maximum payload size

# Define a callback function which is triggered upon reception of Bluetooth data from the host
def fn(bytes):
    print(bytes)

bluetooth.receive_callback(fn) # Attaches the above function to the receive callback

time – Monocle specific

The time module allows for getting/setting the time and date as well as adding delays into your programs.

MembersDescription
time(secs) functionSets or gets the current system time in seconds. If secs is not provided, the current time is returned, otherwise the time is set according to the value of secs. secs should be referenced from midnight on the 1st of January 1970.
now(epoch) functionReturns a dictionary containing a human readable date and time. If no argument is provided, the current system time is used. If epoch is provided, that value will be used to generate the dictionary. The epoch should be referenced from midnight on the 1st of January 1970.
zone(offset) functionSets or gets the time zone offset from GMT as a string. If offset is provided, the timezone is set to the new value. offset must be provided as a string, eg “8:00”, or “-06:30”.
mktime(dict) functionThe inverse of now(). Converts a dictionary provided into an epoch timestamp. The returned epoch value will be referenced from midnight on the 1st of January 1970.
sleep(secs) functionSleep for a given number of seconds.
sleep_ms(msecs) functionSleep for a given number of milliseconds.
ticks_ms() functionReturns a timestamp in milliseconds since power on.
ticks_add(ticks, delta) functionOffsets a timestamp value by a given number. Can be positive or negative.
ticks_diff(ticks1,ticks2) functionReturns the difference between two timestamps. i.e. ticks1 - ticks2, but takes into consideration if the numbers wrap around.

Example

import utime
time.sleep(1.5) # Sleeps for 1.5 seconds
time.sleep_ms(100) # Sleeps for 500ms
time.time(1681236168) # Sets the device system time using UTC timestamp
time.time() # Returns the current time (as a UTC timestamp), based on the system time
time.now() # Returns the current time as a human readable dictionary

update - Monocle specific

The update module allows for firmware upgrades of the MicroPython firmware, as well as the FPGA application over bluetooth. This library use used automatically by the Brilliant REPL for firmware updates. You generally shouldn’t need to call these manually, unless you’re implementing your own update process.

MembersDescription
micropython() functionPuts the device into over-the-air device firmware update mode. The device will stay in DFU mode for 5 minutes or until an update is finished being performed. The device will then restart with an updated MicroPython firmware.
Fpga classFpga contains three low level functions which are used to update the FPGA. Fpga.erase() erases the existing application, Fpga.write(bytes[]) sequentially writes in the new application, and Fpga.read(address, length) can be used to read back and verify the application. For details on how the FPGA application is updated, check out the FPGA application updates section.

Example

import update
update.micropython() # Reboots the device into update mode for updating the MicroPython firmware

gc

Standard MicroPython garbage collection is supported.

Example

import gc

# Shows the current memory usage as a percentage
mem_used = gc.mem_alloc() / (gc.mem_alloc() + gc.mem_free())
print('{:d}%'.format(round(mem_used * 100)))

# Manually runs the garbage collector
gc.collect()

math

Standard MicroPython math functions are supported.

micropython

Standard MicroPython internals are supported.

uarray

Standard MicroPython arrays are supported.

uasyncio

Standard MicroPython asynchronous scheduling is supported.

ubinascii

Standard MicroPython binary/ASCII conversions are supported.

ucollections

Standard MicroPython collection and container types are supported.

uerrno

Standard MicroPython system error codes are supported.

uhashlib

Standard MicroPython hashing algorithms are supported.

uio

Standard MicroPython IO streams are supported.

ujson

Standard MicroPython JSON handling is supported.

uos

Standard MicroPython operating system services for file handling are supported.

urandom

Standard MicroPython random number generation is supported.

ure

Standard MicroPython regular expressions are supported.

uselect

Standard MicroPython stream event waiting is supported.

ustruct

Standard MicroPython struct primitives are supported.

usys

Standard MicroPython system specific functions are supported.


Under the hood

This section describes how data is transferred to and from Monocle over Bluetooth.

For testing everything Bluetooth related, try our the nRF Connect App, for desktop, Android, or iOS.

Communication

All MicroPython communication, i.e. the REPL interface, is accessed via a single Bluetooth Service containing two Characteristics.

  • Serial service UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
  • Serial RX characteristic UUID: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
  • Serial TX characteristic UUID: 6e400003-b5a3-f393-e0a9-e50e24dcca9e

The RX characteristic is write only, and transports serial string data from the central BLE device to Monocle. The TX characteristic is notification only and delivers messages back from Monocle, to the central BLE device.

Each characteristic transports string data of any length up to the negotiated MTU size - 3 bytes. Longer strings must be chopped up and will be automatically rejoined on the receiving side by Monocle. Likewise if Monocle wishes to send longer responses than can fit into a single MTU payload, the data will arrive sequentially, and can be concatenated by the central Bluetooth app. The diagram below describes how communication operates between Monocle and a central device.

Sequence diagram of the Monocle serial data service

A secondary Bluetooth Service, again containing two Characteristics, is used to transport raw data such as image, audio and firmware update data. The mechanism for the raw data service is similar to the serial data service, aside from the fact that null or 0 characters may also be included within the payload.

  • Raw data service UUID: e5700001-7bac-429a-b4ce-57ff900f479d
  • Raw data RX Characteristic UUID: e5700002-7bac-429a-b4ce-57ff900f479d
  • Raw data TX Characteristic UUID: e5700003-7bac-429a-b4ce-57ff900f479d

Raw data transfer may often be bigger than a single MTU payload. Similarly to the serial data, it may need to be broken up into pieces. To help reconstruct the packets sent or received by Monocle, a flag is present at the start of each payload to determine if it’s either a starting payload, middle payload, end payload, or a small single buffer payload. The exact mechanisms for different types of data transfer are outlined below.

Downloading media

Media files such as audio and images may be downloaded from the Monocle using the raw data service mentioned in the Communication section. Files may also be sent asynchronously by Monocle when they are ready.

Due to the small payload size of Bluetooth packets, the file may be spit into many chunks and need to be recombined by the receiving central device. A flag at the start of each payload indicates if it is the START, MIDDLE or END of the file. A very small file may also be transferred using the SMALL flag.

The first payload includes metadata about the file such as the filename (with a relevant file extension) and the file size. The sequence diagram below describes how a file is broken into several parts and the data can be recombined to construct the full file:

Sequence diagram of the Monocle raw data service

Firmware updates

Within the Web REPL, firmware updates should show up automatically, and you’ll be prompted to update. If it doesn’t work. You can follow these steps:

  1. Make sure you’re using a Bluetooth enabled web browser such as Google Chrome on desktop, Android Chrome, or Bluefy on iOS.
  2. Navigate to the repl at repl.brilliant.xyz
  3. Take monocle out of the case. It should turn on.
  4. Press any key in the repl to connect.
  5. Select monocle from the Bluetooth menu that appears.
  6. An update notification should appear at the bottom. Click it.

    If it doesn’t show up, you can force an update using the commands:

     import update;update.micropython()
    
  7. Monocle will disconnect, and you’ll see a message to reconnect again.
  8. Press any key to reconnect and select DFUTarg from the Bluetooth menu.
  9. The update should start, and you’ll see the progress.
  10. If anything goes wrong, simply try again.

Under the hood, the update .zip file is obtained from the releases page of the monocle-micropython repository. After that Monocle is rebooted into device firmware update (DFU) mode where the Nordic DFU service handles the transfer of the file data. To read how the DFU mechanism works, you can check the Nordic documentation here.

For testing everything Bluetooth related, try our the nRF Connect App, for desktop, Android, or iOS.

FPGA application updates

FPGA application updates are automatically updated when using the Brilliant WebREPL.

For simplicity, the WebREPL encodes the application binary file to base-64 format, and simply sends the data over the raw REPL. The entire process is shown below.

import device
import update
import ubinascii

# Erases the entire application
update.Fpga.erase()

# Send exactly 444430 bytes. Each write appends to the already written data
# There's no limitation on how many bytes you can send, but it should be
# tuned to match the host MTU length for a faster upload speed
update.Fpga.write(ubinascii.a2b_base64(b'TWFueSBoYW5kcyBtYWt...lIGxpZ2h0IHdvcmsu'))
...
update.Fpga.write(ubinascii.a2b_base64(b'yBtYWtTWFueSBoYW5kc...cmslIGxpZIHd2h0vu'))

# Write the special "done" flag at the end of the file
update.Fpga.write(b'done')

device.reset()