I connected an Arduino MKR WAN 1310 to The Things Network. And enabled both send and receive. This post is my log of the activity. A few weeks ago, I bought a LoRaWan gateway. In this post, it helps to get and end-to-end trace. I have full view. I can see the Arduino Thing's behaviour on TTN and in the IDE serial monitor. And I can see the gateway logs both on TTN and on the gateway itself. 360° view. |
The Example setup
An Arduino MKR WAN 1310 connects to TTN. It reports the status of its onboard LED (uplink). From the TTN, the status of that LED can be changed (downlink).
Activities
- retrieve Thing's ID
- register the Thing on TTN
- develop firmware and
- program Arduino
- test join,
- test uplink data exchange and
- test downlink data exchange
assumptions:
- if you want to play along: you have a TTN account, and know how to navigate the console. Else, get started.
- there's a TTN gateway in range. If not, check Low-Cost LoRaWAN Gateways!.
- Arduino MKR WAN 1310 and antenna. Or an other device that works with the MKRWAN lib.
Set-up of The Thing on TTN
A bit of preparation work first. Before you can register a Thing, you need to have an application set up in TTN console.
Click on create, and keep the window open. We 'll register the Thing on the application screen in a bit.
... and you need the device ID of your MKR 1310. Arduino's LoRaLib has a sketch for that.
Load the sketch to the MKR, open serial output and copy the EUI from the log. You'll need it. It 'll be the value to enter in the DevEUI field a bit later in the process.
At this point, you're ready to register your thing. In the TTN console, your application screen should be open. Click the Register end device button.
There's a preset for the 1310. Let's use it. The controls in a red rectangle are regional. Check the appropriate one for your location.
The JoinEUI with all 00 will allow to join the Thing directly at first connection. TTN also provides a JoinEUI that can (should!) be used with proper provisioning. Maybe subject for an additional blog.
After confirming, provide your DevEUI. This is the one that you retrieved earlier. Do not click the Generate button.
Generate the AppKey (click the correct Generate button behind the AppKey control. Not the one behind the DevEUI control).
Register End Device. Done.
Leave the console window open. You 'll need AppEUI and AppKey in your Arduino sketch.
Arduino MKR WAN 1310 firmware
There used to be a LED example on create.arduino , but it's no longer there. And I couldn't locate a copy. I made my own, starting from the MKRWAN Lora Send And Receive example.
That Send and Receive example joins TTN (or the network where you registered your Thing). Then it listens on the serial console for a text input. When you type a string, that sketch sends it to the network . And retrieves any pending download messages.
My adaption removes the serial console part. It checks the state changes of the on-board LED, and sends that to the network.
At that time, it may also receive a downlink message from the network. It checks the payload. If it's a LED state command, it will set the on-board LED to that state. If the state is different than the current LED state, it will result in a new message to the network. In essence, I created a low speed semi-Blinky.
special cases:
- the sketch will always send the initial LED status upon boot.
- if the LED state didn't change the state for a while (20 minutes in my code), it will send the status anyway. This will take care that we also retrieve downlink messages (I don't poll for them).
How can the LED change state? In my sketch, this can only happen by sending a downlink message. Exercise for the reader: you could extend my code, and add a button to toggle the LED state.
Code
The easiest way to start is by opening the MKRWAN LoRaSendAndReceive sketch. Immediately Save As LoRa_LED_ON_OFF. This takes care that you have an .ino and arduino_secrets.h file. And the MKRWAN lib is included. Ready to start. Before you adapt the code, have a look at it. If you understand what it does, it 'll be easier to understand my sketck.
Here's the adapted sketch, ready for LED action:
/* Lora_LED_ON_OFF: The Things Network testsketch that integrates with their payload formatters and tutorials Altrnative for the no longer available LoRa LED/ON off basic sketch: Please refer to https://create.arduino.cc/editor/FT-CONTENT/043f42fb-2b04-4cfb-a277-b1a3dd5366c2/preview Jan Cumps 15-03-2024 With code from: Lora Send And Receive This sketch demonstrates how to send and receive data with the MKR WAN 1300/1310 LoRa module. This example code is in the public domain. */ #include <MKRWAN.h> LoRaModem modem; // Uncomment if using the Murata chip as a module // LoRaModem modem(Serial1); #include "arduino_secrets.h" // Please enter your sensitive data in the Secret tab or arduino_secrets.h String appEui = SECRET_APP_EUI; String appKey = SECRET_APP_KEY; void setup() { // put your setup code here, to run once: pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, 0); Serial.begin(115200); while (!Serial); // change this to your regional band (eg. US915, AS923, ...) if (!modem.begin(EU868)) { Serial.println("Failed to start module"); while (1) {} }; Serial.print("Your module version is: "); Serial.println(modem.version()); Serial.print("Your device EUI is: "); Serial.println(modem.deviceEUI()); int connected = modem.joinOTAA(appEui, appKey); if (!connected) { Serial.println("Something went wrong; are you indoor? Move near a window and retry"); while (1) {} } // Set poll interval to 60 secs. modem.minPollInterval(60); // NOTE: independent of this setting, the modem will // not allow sending more than one message every 2 minutes, // this is enforced by firmware and can not be changed. } // #define WAITBEFOREAUTOSEND (6 * 60 * 2) // every 2 hours #define WAITBEFOREAUTOSEND (6 * 10 * 2) // every 20 minutes void loop() { static int previousLedState = 0; // enfore a communication every so many minutes, to check for downlinks static int loopcounter = 0; if (loopcounter % (WAITBEFOREAUTOSEND) == 0) { loopcounter = 0; } int err; char state; if ((digitalRead(LED_BUILTIN) != previousLedState) || (loopcounter == 0) ) { previousLedState = digitalRead(LED_BUILTIN); state = previousLedState ? 0x01 : 0x00; modem.beginPacket(); modem.print(state); err = modem.endPacket(true); if (err > 0) { Serial.println("Message sent correctly!"); } else { Serial.println("Error sending message :("); Serial.println("(you may send a limited amount of messages per minute, depending on the signal strength"); Serial.println("it may vary from 1 message every couple of seconds to 1 message every minute)"); } } loopcounter ++; delay(10000); if (!modem.available()) { // Serial.println("No downlink message received at this time."); return; } char rcv[64]; int i = 0; while (modem.available()) { rcv[i++] = (char)modem.read(); } Serial.print("Received: "); switch (rcv[0]) { case 0x00: Serial.print("led off"); digitalWrite(LED_BUILTIN, 0); break; case 0x01: Serial.print("led on"); digitalWrite(LED_BUILTIN, 1); break; default: Serial.print("unexpected payload"); Serial.print(rcv[0] + 32); break; } Serial.println(); }
In the header file, you'll have to replace the placeholders with the AppEUI and AppKey that you find back on the End Device console window. The one you left open a few steps ago. Do not share the IDs. (and don't accidently check them into github.)
Save all. Connect an antenna to your Arduino and plug it in. It will show up at the title bar of the IDE.
Press the Upload button. After successful build and upload, open the serial monitor, 115200 baud. Enjoy! (hopefully )
Test
The Things Stack Sandbox Fair Use Policy applies, which limits the uplink airtime to 30 seconds per day (24 hours) per node and the downlink messages to 10 messages per day (24 hours) per node. |
The serial monitor of the Arduino IDE will show if you have joined TTN. If not, the usual cause is that:
- there is no gateway within reach,
- I made a mistake in this post, or
- you made a mistake wile doing the activities
uplink
If the console says Message sent correctly, you made it! You can use the TTN monitor to see the data. It 'll show real time in the Overview tab. You get more details (including drill-through) in the Live data tab.
click to enlarge. You 'll see that the payload is formatted. In reality it's just one byte. Exercise for the reader: check your device's Payload formatters tab.
Detail:
downlink:
You can send a LED command to the Thing from the console too. Navigate to the Messaging -> Downlink tab.
It's not a simulation. This generates a real message four your Thing. 01 is LED on. 00 is LED off. The next time your Thing uplinks, it will receive this downlink message and set the on-board LED accordingly. If this changes the LED state, the sketch will immediately send an uplink with the new state. If you generate a downlink while the device is not connected, it will receive it upon first connection.
You can see that on the log below. I had submitted a downlink with payload 01(LED on). At 12:25, I powered on the 1310.
The device joins, and immediately sends a first uplink with the initial state (off).
At that time, it also receives the pending downlink with the LED on payload. The sketch switches on the LED.
The sketch notices that the LED state changed from off to on, and uplinks that data. The next 20 minutes, nothing will happen.
During that time, I generated a downlink with payload 00 (LED off). As soon as the sketch does its next uplink, at 14:45 (my 20 minutes wait expired), it receives the new downlink message.
The LED gets switched off. Again the firmware detects a state change and uplinks the new state.
You should be able to find back these activities in the log capture above.
Gateway view
Because I run my own gateway, I can see what happens in between The Thing and The Things Network. This post is long enough as it is. I 'll post a follow up with the gateway's view. But here is a preview with rough comments.
Raspberry Pi gateway log (filtered):
- line 1: join
- line 2: initial send
- line 3: send change, because LED was changed due to receive a downlink that was earlier submitted by me and ready waiting on TTN
- line 1: send after 20 minutes.
- line 2: send change, because LED was changed due to receive a downlink that was submitted on TTN by me
TTN console gateway log of the 11:45 traffic. Click to enlarge
Thanks for reading !
follow up: If you keep on reading: this is the end-state I'm working towards.
- Arduino MKR WAN 1310 via The Things Network to AWS IoT MQTT
- Arduino MKR WAN 1310 integration with The Things Network MQTT
- Arduino MKR WAN 1310 integration with Node-RED via The Things Network
sketch source code on GitHub.