brocaar / chirpstack-application-server

ChirpStack Application Server is an open-source LoRaWAN application-server.
https://www.chirpstack.io
MIT License
491 stars 325 forks source link

Documentation on using Arduino LMIC libraries missing #259

Closed proffalken closed 5 years ago

proffalken commented 5 years ago

Is this a bug or a feature request?

Bug in Documentation

What did you expect?

Advice to how fields in the "device configuration" screen map to the Arduino LMIC settings of APPKEY, DEVEUI, and APPEUI

What happened?

When creating a new device using OTAA, the following fields are available from the console of the app-server:

The DEVEUI field is available from the devices overview list on the application screen.

It would be good if there was documentation on how the Network Key and Application Key map to APPKEY and APPEUI, especially as Application Key is listed as optional for Lora 1.0 devices

What version are your using?

2.0.2

How can your issue be reproduced?

Create a new device in the console

NOTE: I'm happy to write the docs, I'm just not sure what the mapping should be for this sample code:

/*******************************************************************************
 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 *
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and redistribution.
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 *
 * This example sends a valid LoRaWAN packet with payload "Hello,
 * world!", using frequency and encryption settings matching those of
 * the The Things Network.
 *
 * This uses OTAA (Over-the-air activation), where where a DevEUI and
 * application key is configured, which are used in an over-the-air
 * activation procedure where a DevAddr and session keys are
 * assigned/generated for use with all further communication.
 *
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
 * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
 * violated by this sketch when left running for longer)!

 * To use this sketch, first register your application and device with
 * the things network, to set or generate an AppEUI, DevEUI and AppKey.
 * Multiple devices can use the same AppEUI, but each device has its own
 * DevEUI and AppKey.
 *
 * Do not forget to define the radio type correctly in config.h.
 *
 *******************************************************************************/

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ 0xHEX };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0xHEX };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = { 0xHEX };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 0,
    .dio = {4, 5, 7},
};

void onEvent (ev_t ev) {
    Serial.print(os_getTime());
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Serial.println(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            Serial.println(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            Serial.println(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            Serial.println(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            Serial.println(F("EV_JOINING"));
            break;
        case EV_JOINED:
            Serial.println(F("EV_JOINED"));

            // Disable link check validation (automatically enabled
            // during join, but not supported by TTN at this time).
            LMIC_setLinkCheckMode(0);
            break;
        case EV_RFU1:
            Serial.println(F("EV_RFU1"));
            break;
        case EV_JOIN_FAILED:
            Serial.println(F("EV_JOIN_FAILED"));
            break;
        case EV_REJOIN_FAILED:
            Serial.println(F("EV_REJOIN_FAILED"));
            break;
            break;
        case EV_TXCOMPLETE:
            Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if (LMIC.txrxFlags & TXRX_ACK)
              Serial.println(F("Received ack"));
            if (LMIC.dataLen) {
              Serial.println(F("Received "));
              Serial.println(LMIC.dataLen);
              Serial.println(F(" bytes of payload"));
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            break;
        case EV_LOST_TSYNC:
            Serial.println(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            Serial.println(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Serial.println(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            Serial.println(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            Serial.println(F("EV_LINK_ALIVE"));
            break;
         default:
            Serial.println(F("Unknown event"));
            break;
    }
}

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.
        LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
        Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
    Serial.begin(9600);
    Serial.println(F("Starting"));

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);
    delay(1000);
    #endif

    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();

    // Start job (sending automatically starts OTAA too)
    do_send(&sendjob);
}

void loop() {
    os_runloop_once();
}
brocaar commented 5 years ago

If you you're willing to create a pull-request with LMIC specific documentation, that would be great! Please note that what you need for OTAA:

(LMIC --> LoRa App Server)

proffalken commented 5 years ago

OK, thanks,

So at the moment, I have the following in the console:

DevEUI: 00415ee3b9a02d4a Network Key (made up by me!): 06647d9527683ccfa457c70ab27b4606 Application Key: ALL ZEROS

In the code, I have the following:

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8];
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0x4A, 0x2D, 0xA0, 0xB9, 0xE3, 0x5E, 0x41, 0x00 }; // 00415EE3B9A02D4A
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = { 0x06, 0x46, 0x7B, 0xB2, 0x0A, 0xC7, 0x57, 0xA4, 0xCF, 0x3C, 0x68, 0x27, 0x95, 0x7D, 0x64, 0x06 };
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}

The serial port shows the "JOIN" message being sent, but the join does not take place.

I'm sure I'm missing something obvious here, but I can't work out what it is!

proffalken commented 5 years ago

@brocaar I'm now wondering whether this is due to the "endian-ness" of the hex that I'm putting in to the LoraServer console.

In the TTN console, there is the option to select the code as straight hex, or as an array that is either LSB or MSB first.

It is this LSB array that I should be using with the LMIC code, but I can't work out whether I need to perform this same transformation on the hex string from LoraServer that I need to for TTN.

brocaar commented 5 years ago

All values in the LoRa App Server interface are presented big endian.

There is an open issue to improve this input in LoRa App Server, if you would like to contribute on this.... :-) https://github.com/brocaar/lora-app-server/issues/74

proffalken commented 5 years ago

I've kept the above values, and made sure that the "endian-ness" is right:

static const u1_t PROGMEM APPEUI[8]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t PROGMEM DEVEUI[8]={ 0x4A, 0x2D, 0xA0, 0xB9, 0xE3, 0x5E, 0x41, 0x00 };
static const u1_t PROGMEM APPKEY[16] = { 0x06, 0x64, 0x7d, 0x95, 0x27, 0x68, 0x3c, 0xcf, 0xa4, 0x57, 0xc7, 0x0a, 0xb2, 0x7b, 0x46, 0x06 };

I can see the join request on the gateway:

Message Type = Join Request
AppEUI = 0000000000000000
DevEUI = 00415EE3B9A02D4A
DevNonce = F07B
MIC = AE6A616A

and the gateway is clearly sending packets to LoraServer because I can see it in the Lora Server Console.

I do see a "join accept" packet sent back, but the device doesn't appear to acknowledge it:

Message Type = Join Accept
AppNonce = 180846
NetID = D73F5E
DevAddr = E88BBA7D
MIC = 06C3747C

I'm now wondering if I've mis-configured the device profile somewhere.

(Note: I'm not worried about these keys etc. being posted here as this is a test app/server setup, so they won't be the final values at all!)

proffalken commented 5 years ago

@brocaar looks like the issue isn't with the LMIC library, but with my setup somewhere:

Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="backend/gateway: rx packet received"
Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="packet(s) collected" dev_eui=00415ee3b9a02d4a gw_count=1 gw_macs=<GWMAC> mtype=JoinRequest
Aug 22 19:32:21 mbc-loranode1 lora-app-server[4747]: time="2018-08-22T19:32:21Z" level=info msg="js: request received" message_type=JoinReq receiver_id=0000000000000000 sender_id=010203 transaction_id=3455401306
Aug 22 19:32:21 mbc-loranode1 lora-app-server[4747]: time="2018-08-22T19:32:21Z" level=info msg="device-keys updated" dev_eui=00415ee3b9a02d4a
Aug 22 19:32:21 mbc-loranode1 lora-app-server[4747]: time="2018-08-22T19:32:21Z" level=info msg="js: sending response" message_type=JoinAns receiver_id=010203 result_code=Success sender_id=0000000000000000 transaction_id=3455401306
Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="device-queue flushed" dev_eui=00415ee3b9a02d4a
Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="device-session saved" dev_addr=07ab7b1f dev_eui=00415ee3b9a02d4a
Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="device-activation created" dev_eui=00415ee3b9a02d4a id=16
Aug 22 19:32:21 mbc-loranode1 loraserver[4761]: time="2018-08-22T19:32:21Z" level=info msg="backend/gateway: publishing tx packet" qos=0 topic=gateway/<MAC>
proffalken commented 5 years ago

I can see the LoraFrames coming in to the UI, as request/accept JOIN, I just don't see the device ever connect.

proffalken commented 5 years ago

I'll close this issue and move it to the forums, once I've got LoraServer connecting properly I'll revisit this and update the docs.