documentation

Stage 3: Connect to a Network Server

In the first stage, you built the LoRa® moisture-sensing broadcasting device and configured it to send a moisture reading every 30 seconds. In this section, you learn how to reconfigure the device to allow it to connect to a network server using the Semtech Network Server. Connecting a device to a network server allows the data within the messages to be forwarded to other services, for example, you can then display the data in a web-based application or IoT platform.

Configure the Semtech Network Server

Register with the Semtech Network Server and Configure your Gateway

Set up your gateway and configure the Semtech Network Server following these steps:

  1. Find your Gateway ID by following the instructions in the Find the Gateway ID section of the Semtech Network Server User Guide.

  2. Create an account on the Semtech Network Server following the instructions in the Create an Account with the Semtech Network Server section of the Semtech Network User Guide.

  3. Register your gateway and connect it to the Semtech Network Server following the instructions in the Register and Connect Your Gateway to the Semtech Network Server section of the Semtech Network User Guide.

Create an Application

An application represents a collection of devices on the network server. These devices may either be all the same type or a mixture of device types. The data from each device in the application will pass to any integrations you have registered with the application. In this tutorial your application will only contain your end device.

  1. Log in to the Semtech Network Server website if you haven’t already done so.

  2. Click Applications in the menu on the left.

    /uploads/documents/images/NS03A-01-Applications.png

    Applications Menu Item

  3. Click Add application.

    /uploads/documents/images/NS03A-02-Add-application.png

    Add application Button

  4. Complete the form:

    • Name:

      Enter a name for your application, e.g., Test Application

    • Description:

      Give the application a description, e.g., Application for hands-on lab

  5. Click Submit. The application appears in the list of Applications.

You have now created an application.

Create a Device Profile

A device profile defines a device’s capabilities and boot parameters. It is a reusable profile, created once for each device type and firmware version that you add to the network server. Whether you create 1 or 100 devices of the same type with the same firmware, you only need one device profile. The device profile must be added before you can add your device to the Semtech Network Server. Follow these steps to create one:

  1. Log in to the Semtech Network Server website if you haven’t already done so.

  2. Click Device profiles in the menu on the left.

  3. Click Add device profile.

  4. Complete the fields in the open General tab as follows:

    • Name:

      Enter a profile name to represent the device model and firmware version, e.g. My Test Device 1.0. Spaces are allowed.

    • Description:

      Optionally enter a free text description of your device type, e.g. Testing device for learning.

    • Region:

      Select the frequency plan for your device’s region, as listed in the Semtech Network Server website’s Regional Support table.

    • MAC version:

      Select LoRaWAN 1.0.3.

      Note

      This is the version of the LoRaWAN® specification implemented by the firmware on your end device.

    • Regional parameters revision:

      Select A.

      Note

      The Regional parameters revision refers to the version of the Regional Parameters document that the firmware on your end device supports.

    • ADR algorithm:

      Select Default ADR algorithm (LoRa only).

    • Flush queue on activate:

      Leave this set to the default.

      Note

      Downlinks can be queued to be sent to a device using the device page. Until messages have been sent, they remain in a queue. If you set Flush queue on activate to on, this queue will be emptied if a device rejoins the network, and the messages will never be sent to the device. If you set Flush queue on activate to off, this queue will remain and the messages will be sent to the device.

    • Expected uplink interval (secs):

      Set this to 30.

      Note

      This setting is used so that the network server can decide whether a device is active or inactive on the dashboard. The device will still work if this setting does not match the actual uplink interval.

    • Device-status request frequency (req/day):

      Leave this set to the default of 1.

      Note

      This value indicates the number of times per day you would like the network server to send the End Device Status MAC Command (DevStatusReq) to the end device, following receipt of an uplink. This MAC command will cause the end device to respond with its battery level and radio status.

      Unless the end device sends a Class A uplink the same number of times per day, it will not receive this number of DeviceStatusReq MAC commands. This is the maximum number of requests for the Device Status that the network server will send per day.

  5. Click on the Join (OTAA/ABP) tab and verify that the switch next to Device supports OTAA is turned on.

  6. Click Submit to save. The device profile appears in the Device profiles list.

Add Your Device

  1. Click Applications in the menu on the left.

  2. Click on the link to the application you just created.

    /uploads/documents/images/NS05-choose-application.png

    Link to Application

  3. Click the Add device button.

  4. Complete the fields in the open Device tab as follows:

    • Name:

      Enter a name to represent this device, e.g. Test Device. Spaces are allowed.

    • Description:

      Enter an optional description.

    • Device EUI (EUI64):

      1. Click the generate button (Generate EUI Icon) to generate a random device EUI.

        Note

        When creating a device in production, use the DevEUI supplied by the radio module manufacturer or obtain a valid, globally unique DevEUI that you own. Learn more about selecting a DevEUI.

      2. Click the MSB button shown below, and choose LSB from the list of options to change the display order of the device EUI to Least Significant Bit (LSB).

        /uploads/documents/images/NS05B-MSB.png

        MSB Button in the Device EUI Form Field

      3. Click the copy button (Copy AppKey Icon), then select the option HEX array. Paste this somewhere you can find it later. This value is referred to later as DEV_EUI.

      Note

      The Arduino code requires the Dev EUI to be inserted in the LSB format as a HEX array.

    • Device profile:

      Select the profile you created earlier, e.g., My Test Device 1.0.

    • Device is disabled:

      Leave this switched off.

    • Disable frame-counter validation:

      Leave this switched off.

  5. Click the Submit button to save the device.

  6. The OTAA keys tab is selected. Complete the following steps to set the Application Key field:

    1. Click the generate button (Generate EUI Icon) to generate a random Application Key.

      Note

      When creating a device in production, read section 2.5.3, Root Keys (page 9) of TR007 Developing LoRaWAN Devices V1.0.0 to learn how to securely generate and store the Application Key.

    2. Click the copy button (Copy AppKey Icon), then select the option HEX array to copy the Application Key in the format required by the Arduino code.

    3. Copy this Application Key somewhere safe. You will need to paste this into your code later. This value is referred to later as APP_KEY.

  7. Click Submit to update the key.

Set up the Arduino IDE for LoRaWAN®

In this section we show you how to; install the open-source library MCCI LoRaWAN LMIC (LoRaWAN-MAC-in-C) that will allow you to send and receive data using LoRa, edit a config file (unless you are based in the U.S.), and select your board.

  1. Open the Arduino IDE.
  2. At the Arduino IDE menu bar, select Sketch > Include Library > Manage Libraries. to open the Library Manager.
  3. Search for MCCI LoRaWAN LMIC and locate the MCCI LoRaWAN LMIC library by Terry Moore. At the time of this writing, the latest version is 4.1.1. Click Install.

    Arduino IDE Library Manager showing the library to install [TODO: Update image with red box around name of correct library to install]

    Warning

    Take care to avoid installing the library named MCCI Arduino LoRaWAN Library, this is a different library and will not work with this tutorial.

  4. Click Close to exit the Library Manager.
  5. At the Arduino IDE menu bar, select Tools > Board > Arduino Uno (or whichever board you are using for this tutorial) to ensure that the correct board is selected.
  6. The LMIC library contains a flag to toggle between region frequencies. You next need to make sure the correct frequency is selected for your region. If your region is US915, you do not need to perform these remaining steps, since that is the default region.
    1. At the Arduino IDE menu bar on Windows and Linux select File > Preferences, on macOS select Arduino > Preferences. The Preferences window opens at the Settings tab.

    2. Locate the Sketchbook location field; we refer to this below as SKETCHBOOK_LOCATION.

      Arduino IDE settings screen showing Sketchbook location

    3. Open your favourite code editor, or install and open Visual Studio Code.

    4. Open the file at SKETCHBOOK_LOCATION/libraries/MCCI_LoRaWAN_LMIC_library/project_config/lmic_project_config.h on macOS and Linux, or SKETCHBOOK_LOCATION\libraries\MCCI_LoRaWAN_LMIC_library\project_config\lmic_project_config.h on Windows. This file contains the settings for the LMIC library.

    5. Edit lmic_project_config.h to comment the #define CFG_us915 1 line, and uncomment the frequency for your country/region.

      For example, to use the EU868 frequency, comment-out the line #define CFG_us915 1 and uncomment the line #define CFG_eu868 1 as follows:

      // project-specific definitions

      #define CFG_eu868 1

      //#define CFG_us915 1

      //#define CFG_au915 1

      //#define CFG_as923 1

      // #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP /* for as923-JP */

      //#define CFG_kr920 1

      //#define CFG_in866 1

  7. Save the lmic_project_config.h file and then close it.

Configure Your LoRa® Device

In this section we show you how to update the LoRa device you created in Stage 1 to use the LoRaWAN standard to broadcast the soil moisture readings over the network.

  1. At the Arduino IDE menu, select File > New.
  2. Delete all the boilerplate code that appears in the sketch.
  3. Copy the code below into the sketch. This code, and the code that follows, references the TTN-OTAA sample provided with the LMIC library, which is found here.

    #include lmic.h

    #include hal/hal.h

    #include SPI.h

    #define SensorPin A0

    int sensorValue = -1;

    // Pin mapping: set your pin numbers here. These are for the Dragino shield.

    const lmic_pinmap lmic_pins = {

        .nss = 10,

        .rxtx = LMIC_UNUSED_PIN,

        .rst = 9,

        .dio = {2, 6, 7},

    };

    Note

    The LMIC and SPI library headers #include lmic.h and #include spi.h import the libraries.

    The SensorPin and sensorValue declarations at the top of the sketch define which analog pin the sensor is connected to and set an initial value of -1.

    lmic_pinmap is used to inform the LMIC library of the Arduino pins your shield uses (referred to as a pin mapping). The pin mapping in the code above is for the Dragino shield, but if you are using a different shield, you need to update this struct. Refer to your hardware documentation for the correct pin mappings. The settings are:

    • .nss - for the ‘slave select’ connection
    • .rxtx - for controlling the antenna switch, not used by this software so set to LMIC_UNUSED_PIN
    • .rst - reset pin, used to reset the transceiver
    • .dio - digital I/O pins to get status information from the shield, for example when a transmission starts or is complete

    Learn more about pin mapping at the Pin mapping section of the Ardunio-LMIC library README.

  4. Add the bolded lines below to the bottom of the sketch to set the variables for Over-the-Air Activation (OTAA):

        .dio = {2, 6, 7},

    };

     

    // Insert Device EUI here

    static const u1_t PROGMEM DEVEUI[8] = {

      DEV_EUI

    };

     

    // Insert App Key here

    static const u1_t PROGMEM APPKEY[16] = {

      APP_KEY

    };

     

    void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

    void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

     

    static const u1_t PROGMEM APPEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00 };

    void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

    Note

    The lines you have just added set the keys used for OTAA.

    DEVEUI[8] defines the Device EUI (DevEUI). A DevEUI is a globally-unique identifier that uniquely identifies your device across any network. DEV_EUI is a placeholder for the real DevEUI. You generated a DevEUI earlier using the Semtech Network Server and will set this in the next step.

    APPKEY[16] defines the Application Key (AppKey). The AppKey is an AES-128 root key specific to the device. The AppKey is used in the join procedure to derive the session keys. APP_KEY is a placeholder for the real AppKey. You generated an AppKey earlier using the Semtech Network Server and will set this in the next step.

    APPEUI[8] defines the Application EUI (AppEUI), renamed Join EUI (JoinEUI) in LoRaWAN Link Layer Specification v1.0.4 and v1.1. The AppEUI/JoinEUI is used to identify a Join Server that sits apart from the Network Server, responsible for handling the Join Procedure. The Semtech Network Server does not require an AppEUI/JoinEUI and can handle the Join Procedure itself, so this is set to the dummy value { 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00 }.

  5. Edit the code to replace the DEV_EUI and APP_KEY placeholders with the values listed below.
    1. DEV_EUI:

      Use the DEV_EUI you saved in the section Add Your Device. Replace DEV_EUI in the code with the DEV_EUI value.

    2. APP_KEY:

      Use the APP_KEY you saved in the section Add Your Device. Replace APP_KEY in the code with the APP_KEY value.

    Check that the code is formatted as below, using the keys you generated in place of the examples below.

    // Insert Device EUI here

    static const u1_t PROGMEM DEVEUI[8] = {

      0x6d, 0x10, 0xdf, 0x93, 0xaf, 0x3b, 0x03, 0x36

    };

     

    // Insert App Key here

    static const u1_t PROGMEM APPKEY[16] = {

      0x77, 0x21, 0x7A, 0x25, 0x43, 0x2A, 0x46, 0x2D, 0x4A, 0x61, 0x4E, 0x64, 0x52, 0x67, 0x55, 0x6A

    };

  6. Add the bolded lines below to the bottom of the sketch, setting the frequency of broadcast to once every 30 seconds.

    void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

    // Schedule uplink to send every TX_INTERVAL seconds

    const unsigned TX_INTERVAL = 30;

    Note

    The duty cycle, which is the amount of time a device is allowed to broadcast in the LoRaWAN spectrum, is regulated by government. A duty cycle limit of 1% means that for any given time period the device may only broadcast for 1% of that time, e.g. 864 seconds within a 24-hour period. In addition, TTN has a fair usage policy limiting the uplink time per device to 30 seconds per day.

    Use this Airtime Calculator to estimate your airtime for an uplink message.

  7. Add the following bolded lines to the bottom of the sketch file to to send an uplink containing the reading:

    const unsigned TX_INTERVAL = 30;

    void do_send(osjob_t* j) {

        // Check if there is not a current TX/RX job running

        if (LMIC.opmode & OP_TXRXPEND) {

            Serial.println(F(OP_TXRXPEND, not sending));

        } else {

     

            // Prepare upstream data transmission at the next possible time.

            sensorValue = analogRead(SensorPin);

            Serial.println(Reading is: );

            Serial.println(sensorValue);

     

            // int -> byte array

            byte payload[2];

            payload[0] = lowByte(sensorValue);

            payload[1] = highByte(sensorValue);

     

            // transmit packet at the next available slot. The parameters are:

            // - 1, FPort: the port used to send the packet, port 1

            // - payload: the payload to send

            // - sizeof(payload): the size of the payload

            // - 0: if we want an acknowledgement response (ack), 0 means we do not want an ack

            LMIC_setTxData2(1, payload, sizeof(payload), 0);

            Serial.println(F(Payload queued));

        }

    }

     

    Note

    analogRead(SensorPin) reads the measurement from the sensor.

    lowByte and highByte convert the integer value into a small two-byte array payload.

    LMIC_setTxData2 sets the payload ready for the next transmission by the LMIC library.

  8. Add the following bolded lines to the bottom of the sketch file to handle events from the LMIC library:

            Serial.println(F(Payload queued));

        }

    }

    static osjob_t sendjob;

    void onEvent (ev_t ev) {

        switch(ev) {

            case EV_JOINING:

                Serial.println(EV_JOINING);

                break;

            case EV_JOINED:

                Serial.println(EV_JOINED);

                // We will disable link check mode, this is used to periodically verify network connectivity, which we do not need in this tutorial

                LMIC_setLinkCheckMode(0);

                break;

            case EV_JOIN_FAILED:

                Serial.println(EV_JOIN_FAILED);

                break;

            case EV_REJOIN_FAILED:

                Serial.println(EV_REJOIN_FAILED);

                break;

            case EV_TXCOMPLETE:

                Serial.println(EV_TXCOMPLETE);

                // Schedule next transmission

                os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);

                break;

             default:

                break;

        }

    }

     

    Note

    When the LMIC library completes an event, it calls the onEvent function, passing the name of the event (ev).

    Examples of events include when joining is complete (EV_JOINED) and when transmission is complete (EX_TXCOMPLETE).

    Join and transmission events are logged to the Arduino Serial Monitor using Serial.println().

    When the EX_TXCOMPLETE event is received indicating that the transmission is complete, the next uplink message is scheduled by instructing the os_setTimedCallback function to call the do_send in TX_INTERVAL seconds, which you set to 30 earlier.

  9. Add the following bolded lines to the bottom of the sketch file to run the methods you just created:

                break;

        }

    }

    void setup() {

        Serial.begin(9600);

        Serial.println(F(Starting));

     

        // Initalizes the LIMIC library,

        os_init();

     

        // Resets the MAC state - this removes sessions, meaning the device must repeat the join process each time it is started.

        LMIC_reset();

     

        // Let LMIC compensate for an inaccurate clock

        LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

     

        // Disable link check validation - this is used to periodically verify network connectivity. Not needed in this tutorial.

        LMIC_setLinkCheckMode(0);

     

        // Set data rate to Spreading Factor 7 and transmit power to 14 dBi for uplinks

        LMIC_setDrTxpow(DR_SF7, 14);

     

        // Start job

        do_send(&sendjob);

    }

     

    void loop() {

        os_runloop_once();

    }

    Note

    The Ardunio setup function is called automatically when a sketch starts. It runs all the setup functions. These functions are detailed in the comments in the sketch above.

    The dosend() method starts the OTAA Join Procedure.

    The loop() function is called on a consecutive loop by Ardunio, and is used to call the LMIC method os_runloop_once(). At that point it hands control over to LMIC. LMIC then sends queued transmissions and runs other radio events. When an event is complete, the onEvent method is called.

Join Your Device to the Network

  1. Log in to the Semtech Network Server website if you haven’t already done so.

  1. Click Gateways in the menu on the left.

  2. Verify that your gateway has a recent date listed under Last Seen.

    /uploads/documents/images/NS0801-last-seen.png

    Gateways page showing gateway as online.

    Note

    If you do not see your gateway listed, or if it is offline, verify that it is turned on and recheck the steps you followed in the Register and Connect Your Gateway to the Semtech Network Server section of the Semtech Network User Guide.

  3. Click Applications in the menu on the left.

  4. Click the link to the application you created earlier.

    /uploads/documents/images/NS05-choose-application.png

    Link to Application

  5. The devices registered to the application appear. Click the link in the DevEUI field of the device you are about to join to the network.

    /uploads/documents/images/NS0801-choose-device.png

    Link to Device

  6. Select the Events tab.

    /uploads/documents/images/NS0801-events-tab.png

    Events Tab in the Device Page

  7. A spinning wheel displays. As events occur, they will appear here. Leave this tab open while you complete the remaining steps in this section.

    Note

    The last 10 events are always visible on this page, so if you accidentally close it, you can reopen it and continue to view the events.

  8. Connect the Arduino board to your computer via the USB-B cable. You should see power LEDs illuminate on the Arduino and on the shield.

  9. At the Arduino IDE menu, select Tools > Port. Select the port labeled with the model of your Arduino board.

    Note

    If none of the ports are labeled, disconnect the Arduino board and reopen the menu; the entry that disappears should be your board. Reconnect the board, then select the entry that had disappeared.

  10. At the Arduino IDE menu, open the Serial Monitor by selecting Tools > Serial Monitor. Verify that the 9600 baud option is selected.

  11. Verify and upload the sketch using the buttons in the Sketch Window menu bar.

  12. The logs showing the EV_JOINING and EV_JOINED messages display in the Serial Monitor. The device has now completed the OTAA process, using the Device EUI and Application Key.

    /uploads/documents/images/Join_Process.png

    Serial Monitor showing the join process

    Warning

    If you only see the EV_JOINING message, read on to learn how to open the events tab in the Semtech Network Server and debug further.

  13. The join event appears in the Events view when the OTAA process completes, as shown in Figure 1 at label A.

    /uploads/documents/images/NS08A-join-network-view-data-events-arduino.png

    Figure 1: Events Tab Showing join (A) and up (B, C) Events

    When the device sends uplinks, the up event appears, as shown in Figure 1 at B and C.

    Read the ChirpStack documentation Event types page to view a list of all event types.

    Warning

    If no messages display, double-check that the DevEUI is correct, revisiting the section Configure Your LoRa Device. If an error message displays reporting Message Integrity Code (MIC) issues, make sure that the AppKey is correct, revisiting the section Configure Your LoRa Device.

  14. On the same page, select the Dashboard tab, indicated in Figure 2 at A.

    The Last seen field on the left shows a recent timestamp, shown in Figure 2 at B. The Enabled field on the right shows that the device is enabled, shown in Figure 2 at C.

    /uploads/documents/images/NS0801-dashboard-tab.png

    Figure 2: Dashboard Tab Showing Location of the Tab (A), Last seen Field (B), and Enabled Field (C)

  15. On the same page, select the LoRaWAN frames tab. This tab shows the LoRaWAN frames sent to or from the device. Figure 3 shows the LoRaWAN frames that generated the events shown in Figure 1.

    /uploads/documents/images/NS08A-join-network-view-data-frames-arduino.png

    Figure 3: LoRaWAN frames Tab Showing JoinRequest (A), JoinAccept (B), UnconfirmedDataUp (C) and UnconfirmedDataDown (D) Frames

    The JoinRequest frame sent from the device to the network server shown in Figure 3 at A, and the JoinAccept sent from the network server to the device shown at B, are the two frames that make up the join event shown in Figure 1.

    The UnconfirmedDataUp frame sent from the device to the network server shown in Figure 3 at C creates the up event shown in Figure 1 at B.

    Note

    You can inspect any frame in the Details pane by clicking the magnifying glass ( Plus icon inside blue lozenge ) icon. To easily understand the contents of the Details pane, you should first learn the format of each type of frame so that you can easily identify the fields by name and understand what each means and how to interpret it.

    Read the In-Depth: LoRaWAN End Device Activation paper to learn the structure of the Join Request frame and the structure of the Join Accept frame.

    Read the In-Depth: Sending and Receiving Messages with LoRaWAN paper to learn the structure of the uplink frame and the structure of the downlink frame downlink fields.

You have now successfully updated your device’s DevEUI and AppKey and joined to the network.

Update the Device Profile Codec to Decode the Payload

  1. Open the Semtech Network Server website.

  2. Click Device profiles in the menu on the left.

  3. Click the Device profile link to the device profile you created earlier.

  4. Select the Codec tab.

  5. Choose JavaScript functions from the Payload codec options, as shown in Figure 4.

    /uploads/documents/images/NS07-codec-options-javascript.png

    Figure 4: Codec tab (A), and JavaScript functions Payload codec option (B).

  6. Paste the following code into the Codec functions field that appears, replacing all the boilerplate code:

    // Decode uplink function.
    //
    // Input is an object with the following fields:
    // - bytes = Byte array containing the uplink payload, e.g. [255, 230, 255, 0]
    // - fPort = Uplink fPort.
    // - variables = Object containing the configured device variables.
    //
    // Output must be an object with the following fields:
    // - data = Object representing the decoded payload.
    function decodeUplink(input) {
     let data = {};
    
     // check that this is an application message, which is sent over Frame Port 1 in our code
      if (input.fPort === 1) {
       // decode the encoded moisture reading
       data.moisture = input.bytes[0] + input.bytes[1] * 256;
     }
    
     // return the object containing the data field, conforming to the specification
     return {
      data: data
     }
    }
    
    /uploads/documents/images/NS07-decode-function.png

    Completed Codec form.

  7. Click the Submit button to save the codec to the device profile.

Inspect the Decoded Payload in the Semtech Network Server

  1. Click Applications in the menu on the left.

  2. Click on the link to the application you created earlier.

  3. The devices registered to the application appear. Click on the link in the DevEUI field of your device.

  4. Click on the Events tab.

  5. Click on the plus icon ( Plus icon inside blue lozenge ) inside any of the up events to open the Details pane for that event.

    Note

    The up events are created when the device sends each uplink. The most recent 10 events are available in the Events tab.

  6. In the Details pane, look for the object key containing the moisture key and value, as shown below. The moisture value is decoded using the JavaScript decodeUplink function you created.

    /uploads/documents/images/NS0802B-arduino-payload.png

    moisture Key and Value Inside the object Key