CircuitPython Examples

Our combined knowledge and scripts for making the most of the #MakeZurich 2023 Badge

See also:

MakeZurich 2023 Badge
Make Zurich 2023 Share

Repo for the badge, hardware, software and examples.

Getting Started

All examples were tested around June 2023 with Pico W and CircuitPython 8.1.0


  • Raspberry Pi Pico W (W stands for Wi-Fi)
  • Seed Studio LoRa E5, Pin GP4 + GP5
  • 6 Neopixels on Pin GP22
  • 1 LED on Pin GP8
  • 1 Button on Pin GP6
  • 4 expansion ports (Grove)
  • 1 PicoW onboard LED, Pin LED

Installing CircuitPython

Mind: CircuitPython should already be installed on your badge. Therefore, this step is not needed.

  1. Download the uf2 file from
  2. While holding the white "BOOTSEL" button connect the pico W to your computer, it should mount as "RPI-RP2"
  3. Copy the circuitpython uf2 file onto it
  4. After it is done the pico W will mount as "CIRCUITPY"

Getting libraries

Lots of existing libraries are bundled in the zip, which you can copy paste to your PicoW lib folder.

  1. Download v8 from

To prevent mistakes I recommend to delete the folders lib/adafruitfeatherwing and lib/adafruitseesaw

CircuitPython Essentials

Adafruit has a great list of examples on CircuitPython Essentials. Many examples of this repository are taken from there.

IDE's and extensions that can make your life easier

VS code

VS code is an easy to use IDE that has a lot of extensions, including extensions for python and also circuit python that safes you some hasle with e.g. adding a specific library to your project (the extensions downloads the latest bundle and places the module you add directly in your lib folder).

See for more information and download of Visual Studio Code.

Circuit python extension

Get it from the marketplace directly inside VS code, more info can be found in the extension readme: - Name: CircuitPython - Id: joedevivo.vscode-circuitpython - Description: CircuitPython for Visual Studio Code - Version: 0.1.20 - Publisher: joedevivo - VS Marketplace Link:


Two ways of sending packages: * Confirmed delivery, you want to know if sending succeeded, send packages with confirmation (ACK). * Fire and forget, you hope some gateway will receive it. Send without confirmation (no ACK).

The inital join is only done once to get the session keys, device will store them and stay joined.

Setting up LoRa OTAA

  1. visit the things network EU console
  2. you may need to create an account first
  3. Create a new application with the name "makezurch-badge-2023-YOURNAME"
  4. On your pico run AT+ID to get the AppEui (also referenced as JoinEUI), DevEui, DevAddr
  5. Register end device
    • manual
    • frequency plan: Europe 863-870 MHz (SF9 for RX2 - recommended)
    • LoRaWAN version: LoRaWAN Specification 1.0.3
    • under "Provisioning Information" for JoinEUI fill in the AppEui
    • also fill the DevEUI as obtained from the AT command
    • Click "Generate" to obtain an AppKey
  6. Configure LoRa with the value from Activation Information > AppKey
    1. AT+KEY=APPKEY,"AppKey"

Sending Packages

We use the UART port on pin GP4 and GP5 to send AT commands to the "Seed Studio LoRa E5". It uses LoRa Version 1.0.3.

If you want to play with the AT commands yourself see example 05-lora/

To set it up

# -> Use this info to configure your device in the thingsnetwork console
AT+DR=5 # 5 sets the datarate to SF7, which is recommended by thingsnetwork
AT+CH=NUM,0-2 # NOTE(yw): no idea what channel to choose

NOTE: you only need to set the APPKEY once and it is remembered.

You should see in the "Live data" section of your application on TheThingsNetwork console an entry of type "Forward uplink data message" with a Payload "48656C6C6F". You can convert this payload from hexadecimal to ASCII using e.g. this webpage and should see that it translates to the "Hello" message sent.

ABP vs OTAA Seed Studio LoRa E5 Documentation


Connecting to Serial

On macOS:

screen /dev/tty.usbmodemXXX 115200

CircuitPython vs Micropython

CircuitPython is a fork of MicroPython that includes a more extensive set of libraries and drivers out of the box, making it easier to get started with. It also has a higher level of abstraction, which can make it easier to write code quickly, and supports a growing number of boards and peripherals.

CircuitPython is heavly maintained by Adafruit, which provides many examples and libraries for all their libraries.

If you see any import machine the code is probably using micropython.


Grove Kit

Examples for the Grove Basic Kit can be found under 06-grove-starterkit. For more see their wiki with examples in micropython.

‼️ Help my kit is incomplete! ‼️ Check with the staff or see if you can swap it with other sensors for example provided by Sensirion

Sensirion Sensors

Sensirion sponsored sensors. Examples can be found under 12-sensirion

  • Grove SEN5X All in One wiki
  • Grove - CO2 & Temperature & Humidity Sensor (SCD30) wiki
  • Grove - CO2 & Temperature & Humidity Sensor(SCD41) wiki
  • Grove Temp&Humi Sensor (SHT40) wiki

AP9 box

The MakeZurich Badge fits into a standard AP9 box (80x80x35mm).




  • How do you receive packages? You need to send a package and in the response downlink data is included.
  • Are the lora configuration values channel, mode, class, appkey persisted? -> Yes
  • Can you read out the AT+KEY of a device? -> No, all KEYs are unreadable for security, the one who forgets his KEY need rewrite with a new key.
  • How to measure RSSI, is there a command? -> In the TTN console event details, you can inspect what the receiving gateways report (sometimes multiple gateways receive your packets).
  • What is a good RSSI? -> Higher than -120 (minimum you can have) and usually below -40 (right next to the gateway).
  • Why is OTAA better than ABP? link
  • What does the python package "supervisor" do? It is used to receive data over serial, while being plugged into USB.
  • Does every badge have an unique EUI? -> yes
  • How much is the difference for LoRa between a handcrafted binary payload vs serialising to JSON text payload?
  • What are AT commands? -> AT commands are used in modems and other hardware for querying or setting parameters more
  • Does CircuitPython support hardware interrupts? -> No, FAQ
This content is a preview from an external site.

Event finished

10.06.2023 16:00

docs (@yene)

Merge pull request #21 from makezurich/updatestolora_class

Update LoraModule.at_send to wait for an exit condition (@yene)

Merge pull request #20 from rac2030/badgetester

Uploaded badge tester (@yene)

update lora module's at_send to wait for an exit condition

Uploaded badge tester

Lora sending notes (@yene)

improving neopixel examples (@yene)

fixed: bug when sending text with space (@yene)

Grove OLED example (@yene)

Merge pull request #18 from derrickoswald/main

Typo (@yene)

Merge pull request #19 from morgulbrut/main

at_send fix from Yannick (@yene)

at_send fix from Yannick (@morgulbrut)

disabled right side buttons because in some badges not connected (@yene)

Merge pull request #1 from derrickoswald/derrickoswald-patch-1



removed unused matrix example (@yene)

improved lora sending and formatter example (@yene)

payload formatting example (@yene)

docs (@yene)

Merge pull request #17 from makezurich/ocd

blacken + rename Lora_module class to LoraModule (@yene)

lora setup code (@yene)

lora send with payload formatter example (@yene)

blacken + rename Lora_module class to LoraModule

misc improvements (@yene)

Merge pull request #16 from rac2030/minifan

Added a simple and a PWM example for controlling the mini fan (@yene)

Added a simple and a PWM example for controlling the mini fan

Merge pull request #14 from rac2030/cover

Added touch cover examples (@yene)

Merge pull request #15 from morgulbrut/main

mz_badge overhaul (@yene)

Merge pull request #13 from filippo82/06-grove-starterkit-lcd

Add working example for Grove LCD (@yene)

Add simon says game as requested by Thomas

Updated README (@morgulbrut)

Added pictures to readme for hardware modification needed

Merge branch 'main' into main (@morgulbrut)

Renamed Neopixel to LEDs, added new functions (@morgulbrut)

Added LEDs example (@morgulbrut)

Added .DS_store (@morgulbrut)

Renamed example (@morgulbrut)

Added simple touch color example from todays session

Add working example for Grove LCD

Merge pull request #12 from clelange/uplink_messages

Add example for retrieving uplink messages

Add example for retrieving uplink messages (@clelange)

gps example (@yene)

ntp example (@yene)

Event started

02.06.2023 09:00
Contributed 4 months ago by yannick_weiss for Make Zurich 2023

Creative Commons CC-BY logo The contents of this website, unless otherwise stated, are shared
under a Creative Commons Attribution 4.0 License.

Everyone at the event is required to agree with our Code of Conduct:

Be excellent to each other!

Make Zurich 2023