Writing code With Mu

Adafruit recommends the Mu editor to type your code into and interact with your project. You can find out how to install Mu on mac, PC, and Linux in this guide page on the Adafruit Learning System.

The advantage to using Mu is it has an editor and added features like direct save to the board's REPL interactive command line and print output. Mu can even plot values for you.

The Code

The code below will use the adafruit_tinylora library which provides high-level access to your radio transceiver's features. 

The code for sending data using a Si7021 sensor to a Things Network Gateway is shown below:

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""Using TinyLoRa with a Si7021 Sensor.
import time

import adafruit_si7021
import board
import busio
import digitalio

from adafruit_tinylora.adafruit_tinylora import TTN, TinyLoRa

try:  # typing
    from typing import Annotated, TypeAlias

    bytearray4: TypeAlias = Annotated[bytearray, 4]
    bytearray16: TypeAlias = Annotated[bytearray, 16]
except ImportError:

# Board LED
led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT

# Create library object using our bus i2c port for si7021
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_si7021.SI7021(i2c)

# Create library object using our bus SPI port for radio
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# RFM9x Breakout Pinouts
cs = digitalio.DigitalInOut(board.D5)
irq = digitalio.DigitalInOut(board.D6)
rst = digitalio.DigitalInOut(board.D4)

# Feather M0 RFM9x Pinouts
# cs = digitalio.DigitalInOut(board.RFM9X_CS)
# irq = digitalio.DigitalInOut(board.RFM9X_D0)
# rst = digitalio.DigitalInOut(board.RFM9X_RST)

# TTN Device Address, 4 Bytes, MSB
devaddr: bytearray4 = bytearray([0x00, 0x00, 0x00, 0x00])

# TTN Network Key, 16 Bytes, MSB
nwkey: bytearray16 = bytearray(

# TTN Application Key, 16 Bytess, MSB
app: bytearray16 = bytearray(

ttn_config = TTN(devaddr, nwkey, app, country="US")

lora = TinyLoRa(spi, cs, irq, rst, ttn_config)

# Data Packet to send to TTN
data: bytearray4 = bytearray(4)

while True:
    temp_val = sensor.temperature
    humid_val = sensor.relative_humidity
    print("Temperature: %0.2f C" % temp_val)
    print("relative humidity: %0.1f %%" % humid_val)

    # Encode float as int
    temp_val = int(temp_val * 100)
    humid_val = int(humid_val * 100)

    # Encode payload as bytes
    data[0] = (temp_val >> 8) & 0xFF
    data[1] = temp_val & 0xFF
    data[2] = (humid_val >> 8) & 0xFF
    data[3] = humid_val & 0xFF

    # Send data packet
    print("Sending packet...")
    lora.send_data(data, len(data), lora.frame_counter)
    print("Packet Sent!")
    led.value = True
    lora.frame_counter += 1
    led.value = False

Using Mu (or a text editor), copy this code and save it to your computer, naming it code.py.

Note: The code is configured to use a RFM9x breakout by default. If you are using a Feather M0 RFM9x, delete the following lines:

# RFM9x Breakout Pinouts

cs = digitalio.DigitalInOut(board.D5)

irq = digitalio.DigitalInOut(board.D6)

rst = digitalio.DigitalInOut(board.D4)

Then, uncomment (remove the #) the following lines to enable the RFM9x's builtin D0 and CS pins

Feather M0 RFM9x Pinouts

irq = digitalio.DigitalInOut(board.RFM9X_D0)

cs = digitalio.DigitalInOut(board.RFM9X_CS)

rst = digitalio.DigitalInOut(board.RFM9X_RST)

Installing Code on CircuitPython

Navigate to where you saved your code.py file. Copy (by dragging the file and dropping it) the file to the CIRCUITPY drive.  

While the code will appear to run, it is not yet set up for your Application or Device. We'll do that next.

Setting up the code for The Things Network

While we can send data to The Things Network, and our gateway might notice it, it isn't registered to a device yet. To register your device with The Things Network using ABP, you'll need to set three unique identifiers in the code.py file: the Network Session Key, the Device Address, and the Application Session Key.

Navigate to the Device Overview page for your Feather device.


Make sure the Activation Method is set to ABP

Before adding the unique identifiers to our sketch, we'll need to first expand them by clicking the <> icon.

These are your keys. We're going to enter them into our code.py, but we need to be careful - the keys on the Things Network console use parentheses or curly braces { } instead of brackets [ ]

First, copy the Device Address from the TTN console to the devaddr variable in the code. 

Then, remove the braces { } from the device address.

A device address copied from The Things Network console would look like: { 0x26, 0x02, 0x1F, 0x07 }. In the code.py, it'd look like: devaddr = bytearray([0x26, 0x02, 0x1F, 0x07]).

Then, copy the Network Session Key from the TTN console to the NwkSkey variable in the code. Make sure to modify the code to remove the parentheses/curly braces { }. 

Finally, copy the Application Session Key from the TTN console to the AppSkey variable in the code. Make sure to modify the code to remove the parentheses/curly braces { }. 

That's all for now - we're ready to run our code! 

Running the Code using Mu Editor

Upon saving (ctrl/cmd +s) your code, the board will refresh. 

But where is the output? The serial monitor is hidden by default in Mu Editor.

In the Mu Editor, click the Serial button on the top icon-bar to bring up the Serial REPL.

You should see the temperature and humidity values printed to the console. The packet's status (sending, or timed out and unable to send) should appear shortly after. The LED on your Feather should also blink the onboard LED when it successfully sends a packet to The Things Network.

If you see Packet Sent!, rejoice - your packet has sent to the Things Network. But, while it's been sent, we want to check and make sure it's been received. 

If you're using a Raspberry Pi: The Pi does not have an onboard LED located at pin D13, so it will not blink when the packet is sent. In the code, comment out every line which uses the LED, like the following:

led = digitalio.DigitalInOut(board.D13) to # led = digitalio.DigitalInOut(board.D13)

Checking Data on The Things Network Console

We want to make sure the data has been received on the other end. To do this, we'll navigate to the The Things Network Console and select the application. From the menu on the right hand side of the page, Click Data.

If everything worked correctly, you'll see the payload from your device streaming into the page, in real time. 


Neat, right? But while we received a payload, we still don't understand what it means. It's been sent to The Things Network and decoded on the client (Gateway) side, so it's not an AES-encrypted payload anymore. It's just not read-able by humans.


Decoding the Payload

If you're sending packets in strange formats or encodings (like we are!), The Things Network Console has a programmable data decoder to decode the packets, and assign useful labels to the data.

Copy and paste the decoder script below into the decoder's integrated text editor and click save

Then, click the data tab. Next to the raw payload data, you should see the decoded data for humidity and temperature.

// TinyLoRa - Si7021 Decoder
function Decoder(bytes, port) {
  var decoded = {};

  // Decode bytes to int
  var celciusInt = (bytes[0] << 8) | bytes[1];
  var humidInt = (bytes[2] << 8) | bytes[3];
  // Decode int to float
  decoded.celcius = celciusInt / 100;
  decoded.humid = humidInt / 100;

  return decoded;

This guide was first published on Dec 06, 2018. It was last updated on Apr 22, 2024.

This page (Using TinyLoRa) was last updated on Apr 22, 2024.

Text editor powered by tinymce.