# Part 2: LoRaWAN on Helium ###### tags: `TA Stuff RP2` `Raspberry Pi Pico` In this tutorial, we'll be focusing on connecting your device to **LoRaWAN** (**Lo**ng **Ra**nge **W**ide **A**rea **N**etwork). You can watch to the following video from The Things Academy about LoRaWAN and the complete playlist is [**(here)**](https://youtube.com/playlist?list=PLM8eOeiKY7JWeGAJfpsJmVXqlanzJfJ_X). ### The Things Academy YouTube {%youtube TonUXQeMctY %} As always, we'll continuously update this walkthrough. **Is there anything missing or unclear, or have you experienced some issue? Please add a comment.** You do this by highlighting the text and then you can write a comment on the highlighted part. You need to log in/create an account on hackMD first. ## LoRaWAN Coverage Map Before being able to use Helium and sending LoRa packages you should check if you have coverage in your area. You can check the coverage map [**here**](https://world.helium.com/en/iot/coverage) and if you are close to a gateway around then you can send message to Helium. :::warning Some gateways are indoor gateway and there may be a lots of obstacles between your device and that gateway so it is possible you see gateway close to your place but signal is weak and you can not send messages. ::: ## Required Hardware (Raspberry Pi Pico W and M5Stack LoRaWAN Unit) We use the Raspberry Pi Pico W and the M5Stack LoRaWAN Unit to connect to Helium. You can see an image of the M5Stack ASR6501 [here](#Connect-the-antenna). Before purchasing an M5Stack module, check your area frequency band [**here**](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country/) and based on that you can choose between the [**915MHz (here)**](https://shop.m5stack.com/collections/all-products/products/lorawan-unit-915mhz-asr6501-with-antenna), the [**868MHz (here)**](https://shop.m5stack.com/collections/all-products/products/lorawan-unit-868mhz-asr6501-with-antenna), or the [**470MHz (here)**](https://shop.m5stack.com/collections/all-products/products/lorawan-unit-470mhz-asr6501-with-antenna) version of M5Stack ASR6501. If you live in **North America or Australia** you should use the **915 MHz** band and connect the antenna accordingly. If you live in **Europe** you can choose either **433 MHz** band or the **868 MHz** band. Altough both are license-free, we recommend going with the **868 MHz** since it has less interference. **❗ Remember, you can always ask a TA if you are not sure**. ## Getting started ### Connect the antenna :::danger **⚠️ Important** Make sure the LoRa antenna is connected properly **before** running any LoRa code on your device. Not doing so might break your device. ::: ![](https://hackmd.io/_uploads/BkppJ7zw3.jpg =500x) ### Connecting M5Stack to Raspberry Pi Pico W <!--![](https://hackmd.io/_uploads/SkosYEfD3.jpg)--> </br> ![M5_Stack_bb](https://hackmd.io/_uploads/ryNpow1rA.png) ### LoRa --- #### LoRa OTAA LoRa has two main methods of authentication. One is **ABP** (**A**uthentication **B**y **P**ersonalisation), and the other is **OTAA** (**O**ver-**T**he-**A**ir-**A**ctivation). We will mostly be going through the **OTAA** method of connecting to LoRaWAN since it is the easier and the simpler of the two. There are three different types of keys/identifiers that you need to provide in OTAA method: **app_eui**, **app_key** and **dev_eui** The **APP_EUI** is what identifies the application you will be creating on whichever platform you choose in the next step. The **APP_KEY** is the encryption key that will be used to encrypt all the data you will be sending to the gateway. This is a private key that should be kept secure. Otherwise others will be able to send data to your application. Lastly, the **DEV_EUI** is a unique key that identifies your end device. Usually, the MAC of the **Raspberry Pi Pico W** is used if nothing is provided by the network you are using. :::info The following text shows how and where to get/generate these three values. ::: ## Helium-IoT Console Registration and Creating a Device :::warning When you register in [Helium-IoT Console](https://console.helium-iot.xyz/), it gives you only `300 Data Credits`. This means you can send **300** free **24 bytes messages** to their network and after that you must purchase more **Data Credits**. Every `100,000 data credits` is `5 US$`, which is the smallest amount you can purchase data credits for. So, please first try the Helium-IoT Console with the free data credits and if you could connect successfully and if you are interesting in using LoRaWAN further, you could buy more data credits. ::: ### Step 1: Register an account on the Helium-IoT Console + 1. To create a Helium-IoT Console account, click [**here**](https://console.helium-iot.xyz/front/login) and follow the instructions. ![00](https://hackmd.io/_uploads/rJWXy_QBC.png) </br> ### Step 2: Add a Device in Helium-IoT Console + 1. To add a device we first need to go to the `Device profiles` tab — found on the left side of the website. Then click on the `Add device profile` button like following image. ![01](https://hackmd.io/_uploads/H1jYJuQrC.jpg) </br> + 2. Name your device profile and select the correct region, LoRaWAN version and ADR algorithm as shown in the image below, and then click the `Submit` button: ![02](https://hackmd.io/_uploads/ryqQxd7BC.jpg) + 3. Now you are ready to create an application, in which you will be able to add your devices. ![03](https://hackmd.io/_uploads/rJs3g_mH0.jpg) + 4. Give your application a name and description (optional) as shown below: ![04](https://hackmd.io/_uploads/HymXZd7rC.jpg) + 5. Click on your new application in the application list, and add a new device to the application: ![05](https://hackmd.io/_uploads/SklDZuXrA.jpg) + 6. Name your new device, generate both the `Device EUI` and `Join EUI` keys (you will need these later) and select the `Device profile` you created earlier. ![06](https://hackmd.io/_uploads/SkSpbdQB0.jpg) + 7. Click on your new device in the list, and go to the `OTAA keys` and generate a new `Application key` (you will need this later) as shown below: ![07](https://hackmd.io/_uploads/B1mrXdmBA.jpg) :::success Now you are ready to use the generated keys and connect to the Helium network. ::: ### 4. Connect to Helium using your device --- Now, you connect to Helium using the `AppKey` you generated earlier. :::danger **⚠️ Important ⚠️** Make sure the LoRa antenna is connected properly before running any LoRa code on your device. Not doing so might break your device. You can find how to properly connect the antenna [here](#Connect-the-antenna). ::: + 1. Download the LoRaWAN library file from our [GitHub repository](https://github.com/iot-lnu/pico-w/tree/main/network-examples/N4_LoRaWAN_Connection) and add it to the root folder of the project. This is what your project structure should look like: ![](https://hackmd.io/_uploads/r1Ig-hXP3.png) + 2. Look for this snippet in the beginning of your `main.py`: ```python= APP_EUI = "0000000000001234" # Substitute Your APP_EUI (Join EUI) here DEV_EUI = "70B3D57ED005E758" # Substitute Your DEV_EUI here APP_KEY = "31CC62B0256EA3311EEFDCB9ED2CEC3B" # Substitute Your APP_KEY here ``` + 3. Now, replace the following with the corresponding keys you generated in the Helium-IoT Console: + `APP_EUI` (also known as `Join EUI`) + `DEV_EUI` (also knows as `Device EUI`) + `APP_KEY` (also knows as `Application key`) <br> + 4. Try to run `main.py` and now in the console, you should see something like: ![08](https://hackmd.io/_uploads/SkDAO_mrA.jpg) If you see the `Join success!` message, then congratulations! You have now successfully connected to the Helium network and are ready to start sending messages! :::warning If your device tries to join for more than a few minutes, then it is an indication of poor coverage in your area. Perhaps you should consider other networks, like [TTN](https://hackmd.io/GpSu99mWS7-52tMD2OpP7g). ::: ### 5. Send messages with Helium --- Before we start sending data, we need to encode our data using the `struct` library and `hex()` function. In the following code snippet, we will be encoding and sending data using LoRaWAN and MicroPython. To encode the data, we'll be using the `struct` library and `hex()` function. ```python=23 # Example temperature (in Celsius) and humidity (%) values with a negative temperature temperature, humidity = -14.2, 42.5 # Convert the float values to integers by multiplying them by a factor (example: 10) temp_int = int(temperature * 10) humidity_int = int(humidity * 10) # https://docs.micropython.org/en/latest/library/struct.html # >: Indicates big-endian byte order. Big-endian means the most significant byte is stored first. # h: Represents a short integer (2 bytes). # H: Represents an unsigned short integer (2 bytes). payload = struct.pack(">hH", temp_int, humidity_int) payload = payload.hex() while True: lora.sendMsg(payload) print("Sent message:", payload) response = lora.receiveMsg() if (response != ""): print("Received: ", end=": ") print(response) time.sleep(30) ``` In the code snippet above: 1. We first pack two integers (-14.2 and 42.5) with `struct.pack()`. The `">hh"` format string indicates that we are packing two big-endian 2-byte short integers. 2. The packed binary payload is then converted to a hexadecimal string using `hex()`. 3. In the main loop, we send the encoded payload using `lora.sendMsg()`. 4. We also attempt to receive a response from the LoRa device using `lora.receiveMsg()`. 5. If a response is received, it is printed to the console. 6. The loop then sleeps for 30 seconds before sending the message again. By running the code snippet above (in VSCode or Thonny), you should get an output similar to the one below: ![](https://hackmd.io/_uploads/BkH_W3EP2.png) Under `Events` in your `Applications` tab in the Helium-IoT Console, you should see something similar to the image below: ![09](https://hackmd.io/_uploads/SyzecOXr0.jpg) :::success You can get the complete code examples for both the `LoRaWAN.py` library and `main.py` from our [**GitHub repo here**](https://github.com/iot-lnu/pico-w/tree/main/network-examples/N4_LoRaWAN_Connection). ::: ### 6. Encoding and Decoding Messages :::info The following part is not mandatory to follow but is **recommended**. The encoding and decoding will be necessary in Part 3, when working with data visualization. ::: In Example 1, we handle negative temperatures by using the ">h" format specifier in the `struct.pack()` function. The ">" means "big-endian format," and the "h" specifies a "signed short integer" which occupies 2 bytes or 16 bits. With this format, we can handle temperatures in the range of -3276.8°C to 3276.7°C (after dividing by the factor of 10). Here's how the code works for a negative temperature: ```python= import struct import binascii # Example temperature (in Celsius) and humidity (%) values with a negative temperature temperature, humidity = -14.2, 42.5 # Convert the float values to integers by multiplying them by a factor (example: 10) temp_int = int(temperature * 10) humidity_int = int(humidity * 10) payload = struct.pack(">hH", temp_int, humidity_int) payload = payload.hex() ``` Now, if you have a negative temperature, like -14.2°C, it is converted to -142 as a signed short integer. The struct.pack() method takes care of the negative value correctly, and it is encoded in the payload as a signed integer. When you decode the payload on the receiving end, you'll get the exact temperature value (-14.2°C) by dividing it by the same factor (10) used during encoding. In Helium (and most of the IoT platforms), it is necessary to decode the previously encoded payload from the end device. To add a decoder that expects a temperature value (2 bytes) and a humidity value (2 bytes), copy the following Javascript code and paste it under `Payload formatters` in the end-device page in TTS. ```javascript= function decodeUplink(input) { var bytes = input.bytes; var decoded = {}; // Check that the byte array is long enough to contain our expected values if (bytes.length < 4) { return { errors: ["Payload length is too short"] }; } // Create a DataView from the bytes var buffer = new ArrayBuffer(bytes.length); var dataView = new DataView(buffer); // Set each byte in the DataView bytes.forEach((byte, index) => dataView.setUint8(index, byte)); // Read the signed short (2 bytes) from the start decoded.temperature = (dataView.getInt16(0, false)) / 10; // false for big-endian // Read the unsigned short (2 bytes) from offset 2 decoded.humidity = (dataView.getUint16(2, false)) / 10; // false for big-endian return { data: { temp: decoded } }; } ``` Paste this code in the `Codec` tab, after selecting the right `Payload codec`, which should be `JavaScript functions`, like below: <!--![](https://hackmd.io/_uploads/H1qaHq4Ph.png)--> ![10](https://hackmd.io/_uploads/r1-RouXB0.jpg) Now if you go back to `Events` in the `Applications` tab in the Helium-IoT Console, you should see the decoded temperature and humidity, and not only their hexadecimal representations. ![11](https://hackmd.io/_uploads/Bk-v3OmBR.jpg) :::success If you made it this far, **good job**! Now grab some coffee before selecting the next box from the roadmap. :::