Stage 1: Building Your Sensor Node

Stage 1: Building Your Sensor Node


Configure the LoRaWAN® Node Moisture Sensor

  1. In the Arduino IDE, create a new sketch: File > New.
  2. Remove the starting code so that you are left with an empty file.
  3. Copy and paste the following code into the sketch:
#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},
};

 

// Insert Device EUI here
static const u1_t PROGMEM DEVEUI[8] = { 0x84, 0x14, 0xBD, 0xF8, 0xA4, 0x9F, 0xA9, 0x00 };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

 

// Insert Application EUI here
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);}

 

// Insert App Key here
static const u1_t PROGMEM APPKEY[16] = { 0x59, 0x21, 0xB1, 0xF7, 0xC3, 0x59, 0xEF, 0xE5, 0xF3, 0x8D, 0xA4, 0x1D, 0xF4, 0x3E, 0x59, 0x73 };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

 

// Schedule uplink to send every TX_INTERVAL seconds
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:
        // - FPort, the port used to send the packet -- port 1
        // - the payload to send
        // - the size of the payload
        // - if we want an acknowledgement (ack), costing 1 downlink message; 0 means we do not want an ack
        LMIC_setTxData2(1, payload, sizeof(payload), 0);
        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;
    }
}

 

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();
    // 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();
}

 

  1. Since you are setting up a private instance, use the sample code as it is, with the default values provided. Note, there are two values in this script which are configurable for each device you want to register: DEVEUI and APPKEY.

    DEVEUI, Device Extended-Unique-Identifier (EUI), is a globally unique 64-bit identifier that uniquely identifies your end device. In the Arduino code it is written in least significant bit (LSB) format.

    APPKEY, Application Key, is an Advanced Encryption Standard (AES) 128-bit root key unique to the end device. The AppKey is used by both the end device and ChirpStack to derive the session keys during the OTAA process, and to verify the integrity of the join request and join accept messages sent during the OTAA process. In the Arduino code it is written in most significant bit (MSB) format.

    The APPEUI is not required by the ChirpStack network server. It is required by the LMIC library, so each byte is set to zero in the sample code.
     
  2. Connect the Arduino to the computer’s USB port using the USB-B cable. You should see a power LED illuminate on the Arduino and on the shield.
     
  3. At the Arduino IDE menu, select Tools > Port. You need to select the serial port that the Arduino is connected to. Select the port which has the model name of your Arduino board alongside it. If none of the ports are labeled, disconnect the Arduino board and reopen the menu; the entry which disappears should be your board. Reconnect the board, then select the entry which had disappeared.
     
  4. At the top of the sketch window, click the Upload icon (right arrow) to the right of the Verify icon. This will upload the sketch to the device.

    When the upload is complete, the message Done uploading will display at the bottom of the sketch file window, confirming the upload has taken place.
     
  5. At the menu, select Tools > Serial Monitor. The Serial Monitor window will open.
     
  6. Select the 9600 baud option from the drop-down menu at the bottom right of the Serial Monitor.
   Figure 4: Selecting the baud rate in Arduino Serial Monitor
  1. If the code uploaded successfully, you will see logging in the Serial Monitor that shows the attempted communication of the device.