Infrastructure and payloads
This is the first in a series of posts about building an HTTP Integration for a The Things Network(TTN) application. I have assumed that readers are familiar with the configuration and operation of a TTN instance so I’m not going to cover that in detail.
I’m using a Seeeduino LoRaWAN device as a client so I configured the sample Over the Air Activation(OTAA) application to connect to my local RAK7246 Developer gateway.
#include <LoRaWan.h> unsigned char data[] = {0x53, 0x65, 0x65, 0x65, 0x64, 0x75, 0x69, 0x6E, 0x6F, 0x20, 0x4C, 0x6F, 0x52, 0x61, 0x57, 0x41, 0x4E}; char buffer[256]; void setup(void) { SerialUSB.begin(9600); while (!SerialUSB); lora.init(); memset(buffer, 0, 256); lora.getVersion(buffer, 256, 1); SerialUSB.print("Ver:"); SerialUSB.print(buffer); memset(buffer, 0, 256); lora.getId(buffer, 256, 1); SerialUSB.print(buffer); SerialUSB.print("ID:"); lora.setKey(NULL, NULL, "12345678901234567890123456789012"); lora.setId(NULL, "1234567890123456", "1234567890123456"); lora.setPort(10); lora.setDeciveMode(LWOTAA); lora.setDataRate(DR0, AS923); lora.setDutyCycle(false); lora.setJoinDutyCycle(false); lora.setPower(14); while (!lora.setOTAAJoin(JOIN, 10)) { SerialUSB.println(""); } SerialUSB.println( "Joined"); } void loop(void) { bool result = false; //result = lora.transferPacket("Hello World!", 10); result = lora.transferPacket(data, sizeof(data)); if (result) { short length; short rssi; memset(buffer, 0, 256); length = lora.receivePacket(buffer, 256, &rssi); if (length) { SerialUSB.print("Length is: "); SerialUSB.println(length); SerialUSB.print("RSSI is: "); SerialUSB.println(rssi); SerialUSB.print("Data is: "); for (unsigned char i = 0; i < length; i ++) { SerialUSB.print("0x"); SerialUSB.print(buffer[i], HEX); SerialUSB.print(" "); } SerialUSB.println(); } } delay( 10000); }
The SetKey and SetId parameters are not obvious and it would be much easier if there were two methods one for OTTA and the other for Activation by-Personalization(ABP).
I then built an Net Core 3.1 Web API application which had a single controller to receive messages from TTN.
[Route("[controller]")] [ApiController] public class Raw : ControllerBase { private static readonly ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); [HttpGet] public string Index() { return "move along nothing to see"; } [HttpPost] public void PostRaw([FromBody]JsonElement body) { string json = JsonSerializer.Serialize(body); log.Info(json); } }
I then configured my TTN application integration to send messages to my shinny new endpoint

My controller logged events to Azure application Insights so I could see if there were any errors and inspect message payloads. The TTN developers provide sample payloads to illustrate the message format but they were a bit chunky for my initial testing.

I could then inspect individual events and payloads

At this point I could download message payloads and save them locally.
{ "app_id": "rak811wisnodetest", "dev_id": "rak811wisnode1", "hardware_serial": "1234567890123456", "port": 1, "counter": 2, "confirmed": true, "payload_raw": "VGlueUNMUiBMb1JhV0FO", "metadata": { "time": "2020-08-26T00:50:36.182774822Z", "frequency": 924.2, "modulation": "LORA", "data_rate": "SF7BW125", "coding_rate": "4/5", "gateways": [ { "gtw_id": "eui-b827ebfffe6c279d", "timestamp": 1584148244, "time": "2020-08-26T00:50:35.012774Z", "channel": 5, "rssi": -63, "snr": 9.2, "rf_chain": 0, "latitude": -43.49889, "longitude": 172.60104, "altitude": 16 } ] }, "downlink_url": "https://integrations.thethingsnetwork.org/ttn-eu/api/v2/down/rak811wisnodetest/azure-webapi-endpoint?key=ttn-account-v2.12345678901234567_12345_1234567-dduo" }
These were useful because I could then use a tool like Telerik Fiddler to submit messages to my application when it was running locally in the Visual Studio 2019 debugger.
Pingback: The Things Network HTTP Integration Part2 | devMobile's blog