Now that we've set up our Things Network application and device, we're going to move on to installing TinyLoRa onto our Raspberry Pi. To do this, enter the following into your terminal to install the library system-wide:
sudo pip3 install adafruit-circuitpython-tinylora
Code
Unlike sending data to another device, we're going to be sending data from our device (the Pi) to a gateway (check the gateway map to find one near you).
While we don't have any sensors hooked up to our radio, we'll send the Raspberry Pi's CPU utilization to The Things Network.
Below is an example of using TinyLoRa to send data to The Things Network. Save this as radio_lorawan.py on your Raspberry Pi.
# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT """ Example for using the RFM9x Radio with Raspberry Pi and LoRaWAN Learn Guide: https://learn.adafruit.com/lora-and-lorawan-for-raspberry-pi Author: Brent Rubell for Adafruit Industries """ import threading import time import subprocess import busio from digitalio import DigitalInOut, Direction, Pull import board # Import thte SSD1306 module. import adafruit_ssd1306 # Import Adafruit TinyLoRa from adafruit_tinylora.adafruit_tinylora import TTN, TinyLoRa # Button A btnA = DigitalInOut(board.D5) btnA.direction = Direction.INPUT btnA.pull = Pull.UP # Button B btnB = DigitalInOut(board.D6) btnB.direction = Direction.INPUT btnB.pull = Pull.UP # Button C btnC = DigitalInOut(board.D12) btnC.direction = Direction.INPUT btnC.pull = Pull.UP # Create the I2C interface. i2c = busio.I2C(board.SCL, board.SDA) # 128x32 OLED Display reset_pin = DigitalInOut(board.D4) display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, reset=reset_pin) # Clear the display. display.fill(0) display.show() width = display.width height = display.height # TinyLoRa Configuration spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) cs = DigitalInOut(board.CE1) irq = DigitalInOut(board.D22) rst = DigitalInOut(board.D25) # TTN Device Address, 4 Bytes, MSB devaddr = bytearray([0x00, 0x00, 0x00, 0x00]) # TTN Network Key, 16 Bytes, MSB nwkey = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) # TTN Application Key, 16 Bytess, MSB app = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) # Initialize ThingsNetwork configuration ttn_config = TTN(devaddr, nwkey, app, country='US') # Initialize lora object lora = TinyLoRa(spi, cs, irq, rst, ttn_config) # 2b array to store sensor data data_pkt = bytearray(2) # time to delay periodic packet sends (in seconds) data_pkt_delay = 5.0 def send_pi_data_periodic(): threading.Timer(data_pkt_delay, send_pi_data_periodic).start() print("Sending periodic data...") send_pi_data(CPU) print('CPU:', CPU) def send_pi_data(data): # Encode float as int data = int(data * 100) # Encode payload as bytes data_pkt[0] = (data >> 8) & 0xff data_pkt[1] = data & 0xff # Send data packet lora.send_data(data_pkt, len(data_pkt), lora.frame_counter) lora.frame_counter += 1 display.fill(0) display.text('Sent Data to TTN!', 15, 15, 1) print('Data sent!') display.show() time.sleep(0.5) while True: packet = None # draw a box to clear the image display.fill(0) display.text('RasPi LoRaWAN', 35, 0, 1) # read the raspberry pi cpu load cmd = "top -bn1 | grep load | awk '{printf \"%.1f\", $(NF-2)}'" CPU = subprocess.check_output(cmd, shell = True ) CPU = float(CPU) if not btnA.value: # Send Packet send_pi_data(CPU) if not btnB.value: # Display CPU Load display.fill(0) display.text('CPU Load %', 45, 0, 1) display.text(str(CPU), 60, 15, 1) display.show() time.sleep(0.1) if not btnC.value: display.fill(0) display.text('* Periodic Mode *', 15, 0, 1) display.show() time.sleep(0.5) send_pi_data_periodic() display.show() time.sleep(.1)
You'll also want to download the font file, font5x8.bin
, and copy it into the same directory as the script:
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 radio_lorawan.py: the Network Session Key
, the Device Address
, and the Application Session Key
.
Navigate to the Device Overview page for your Raspberry Pi device.
Make sure the Activation Method is set to ABP.
Before adding the unique identifiers to our code, we'll need to first expand them by clicking the <> icon.
These are your keys. We're going to enter them into our code, 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, it'd look like: devaddr = bytearray([0x26, 0x02, 0x1F, 0x07])
.
Then, copy the Network Session Key from the TTN console to the nwkey
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 app
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!
Pressing Button C will periodically send a packet to the things network. You can modify this value (in seconds) by changing the data_pkt_delay
variable in the code.
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 readable 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.
// TinyLoRa - Raspberry Pi CPU Load Decoder function Decoder(bytes, port) { var decoded = {}; // Decode bytes to int var CPU_Load = (bytes[0] << 8) | bytes[1]; // Decode int to float decoded.CPU_Load = CPU_Load / 100; return decoded; }
Then, click the data tab. Next to the raw payload data, you should see the decoded data for the CPU load.