This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
project:lora_nodes [2018/02/25 10:44] – dp | project:lora_nodes [2018/05/11 10:54] (current) – dp | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== LoRa TTN node setup ====== | ====== LoRa TTN node setup ====== | ||
+ | Osnovni setup za LoRa TTN nodes... za Heltec i TTGO module, al vjerojatno i za druge. | ||
- | Install | + | ===== Arduino i podrška za ESP32 ===== |
+ | |||
+ | Instaliraj | ||
* https:// | * https:// | ||
- | Install ESP32 Arduino | + | Instaliraj |
* https:// | * https:// | ||
- | Create TTN account | + | ===== The Things Network |
- | https:// | + | |
- | Go to TTN Applications | + | Kreiraj TTN account |
+ | * https:// | ||
+ | |||
+ | Pod TTN Applications | ||
* https:// | * https:// | ||
- | Register Device | + | Registriraj novi device. |
+ | |||
+ | |||
+ | ===== Example code ===== | ||
+ | |||
+ | ==== Spremi primjer ==== | ||
- | Download example | + | <file cpp otaa_abp_example.ino> |
- | <file cpp otaa_example.ino> | + | |
#include < | #include < | ||
#include < | #include < | ||
Line 27: | Line 36: | ||
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); | U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); | ||
- | // This EUI must be in little-endian format, so least-significant-byte | + | // Schedule TX every this many seconds (might become longer due to duty |
- | // first. When copying an EUI from ttnctl output, | + | // cycle limitations). |
- | // the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, | + | const unsigned TX_INTERVAL |
- | // 0x70. | + | |
- | static | + | |
- | void os_getArtEui (u1_t* buf) { | + | |
- | memcpy_P(buf, | + | |
- | } | + | |
- | // This should also be in little endian format, see above. | + | //#define USE_JOINING |
- | static const u1_t PROGMEM DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | + | |
- | void os_getDevEui (u1_t* buf) { | + | |
- | memcpy_P(buf, | + | |
- | } | + | |
- | // This key should be in big endian format (or, since it is not really a | + | #ifdef USE_JOINING |
- | // number but a block of memory, endianness does not really apply). In | + | // OTAA join keys |
- | // practice, a key taken from ttnctl can be copied as-is. | + | // This EUI must be in little-endian format, so least-significant-byte |
- | // The key shown here is the semtech default key. | + | // first. When copying an EUI from ttnctl output, this means to reverse |
- | static const u1_t PROGMEM APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | + | // the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, |
- | void os_getDevKey (u1_t* buf) { | + | // 0x70. |
- | memcpy_P(buf, | + | static const u1_t PROGMEM APPEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
- | } | + | void os_getArtEui (u1_t* buf) { |
+ | memcpy_P(buf, | ||
+ | } | ||
+ | |||
+ | // This should also be in little endian format, see above. | ||
+ | static const u1_t PROGMEM DEVEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
+ | void os_getDevEui (u1_t* buf) { | ||
+ | memcpy_P(buf, | ||
+ | } | ||
+ | |||
+ | | ||
+ | // 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] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
+ | void os_getDevKey (u1_t* buf) { | ||
+ | memcpy_P(buf, | ||
+ | } | ||
- | static uint8_t mydata[] = " | + | #else |
+ | // ABP keys | ||
+ | |||
+ | // LoRaWAN NwkSKey, network session key (msb) | ||
+ | static const PROGMEM u1_t NWKSKEY[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
+ | |||
+ | // LoRaWAN AppSKey, application session key (msb) | ||
+ | static const u1_t PROGMEM APPSKEY[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
+ | |||
+ | // LoRaWAN end-device address (DevAddr) | ||
+ | static const u4_t DEVADDR = 0xffffffff; | ||
+ | |||
+ | void os_getArtEui (u1_t* buf) { } | ||
+ | void os_getDevEui (u1_t* buf) { } | ||
+ | void os_getDevKey (u1_t* buf) { } | ||
+ | |||
+ | #endif | ||
+ | |||
+ | |||
+ | static uint8_t mydata[] = {13, 37}; | ||
static osjob_t sendjob; | 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 | // Pin mapping | ||
Line 72: | Line 105: | ||
Serial.print(": | Serial.print(": | ||
switch (ev) { | switch (ev) { | ||
- | case EV_SCAN_TIMEOUT: | + | |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_BEACON_FOUND: | + | case EV_BEACON_FOUND: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_BEACON_MISSED: | + | case EV_BEACON_MISSED: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_BEACON_TRACKED: | + | case EV_BEACON_TRACKED: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_JOINING: | + | case EV_JOINING: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_JOINED: | + | case EV_JOINED: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | LMIC_setDrTxpow(DR_SF12, 14); //added fixed SF after join for longer range messages | + | LMIC_setDrTxpow(DR_SF7, 14); //added fixed SF after join for longer range messages |
- | // Disable link check validation (automatically enabled | + | // Disable link check validation (automatically enabled |
- | // during join, but not supported by TTN at this time). | + | // during join, but not supported by TTN at this time). |
- | LMIC_setLinkCheckMode(0); | + | LMIC_setLinkCheckMode(0); |
- | break; | + | break; |
- | case EV_RFU1: | + | case EV_RFU1: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_JOIN_FAILED: | + | case EV_JOIN_FAILED: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_REJOIN_FAILED: | + | case EV_REJOIN_FAILED: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | //break; | + | //break; |
- | break; | + | break; |
- | case EV_TXCOMPLETE: | + | case EV_TXCOMPLETE: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | digitalWrite(BUILTIN_LED, | + | digitalWrite(BUILTIN_LED, |
- | if (LMIC.txrxFlags & TXRX_ACK) { | + | if (LMIC.txrxFlags & TXRX_ACK) { |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | } | + | } |
- | if (LMIC.dataLen) { | + | if (LMIC.dataLen) { |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | Serial.println(LMIC.dataLen); | + | Serial.println(LMIC.dataLen); |
- | u8x8.setCursor(4, | + | u8x8.setCursor(4, |
- | u8x8.printf(" | + | u8x8.printf(" |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.setCursor(0, | + | u8x8.setCursor(0, |
- | u8x8.printf(" | + | u8x8.printf(" |
- | } | + | } |
- | // Schedule next transmission | + | // Schedule next transmission |
- | os_setTimedCallback(& | + | os_setTimedCallback(& |
- | break; | + | break; |
- | case EV_LOST_TSYNC: | + | case EV_LOST_TSYNC: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_RESET: | + | case EV_RESET: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_RXCOMPLETE: | + | case EV_RXCOMPLETE: |
- | // data received in ping slot | + | // data received in ping slot |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_LINK_DEAD: | + | case EV_LINK_DEAD: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | case EV_LINK_ALIVE: | + | case EV_LINK_ALIVE: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | break; | + | break; |
- | default: | + | default: |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.setCursor(0, | + | u8x8.setCursor(0, |
- | u8x8.printf(" | + | u8x8.printf(" |
- | break; | + | break; |
} | } | ||
} | } | ||
Line 166: | Line 199: | ||
// Check if there is not a current TX/RX job running | // Check if there is not a current TX/RX job running | ||
if (LMIC.opmode & OP_TXRXPEND) { | if (LMIC.opmode & OP_TXRXPEND) { | ||
- | Serial.println(F(" | + | |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
} else { | } else { | ||
- | // Prepare upstream data transmission at the next possible time. | + | |
- | LMIC_setTxData2(1, | + | LMIC_setTxData2(1, |
- | Serial.println(F(" | + | Serial.println(F(" |
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
- | digitalWrite(BUILTIN_LED, | + | digitalWrite(BUILTIN_LED, |
} | } | ||
// Next TX is scheduled after TX_COMPLETE event. | // Next TX is scheduled after TX_COMPLETE event. | ||
Line 185: | Line 218: | ||
u8x8.begin(); | u8x8.begin(); | ||
u8x8.setFont(u8x8_font_chroma48medium8_r); | u8x8.setFont(u8x8_font_chroma48medium8_r); | ||
- | u8x8.drawString(0, | + | u8x8.drawString(0, |
SPI.begin(5, | SPI.begin(5, | ||
Line 193: | Line 226: | ||
// Reset the MAC state. Session and pending data transfers will be discarded. | // Reset the MAC state. Session and pending data transfers will be discarded. | ||
LMIC_reset(); | LMIC_reset(); | ||
- | LMIC_setDrTxpow(DR_SF12, 14); //set join at SF12 | + | |
- | // Start job (sending automatically starts OTAA too) | + | #ifndef USE_JOINING |
- | | + | #ifdef PROGMEM |
+ | // On AVR, these values are stored in flash and only copied to RAM | ||
+ | // once. Copy them to a temporary buffer here, LMIC_setSession will | ||
+ | // copy them into a buffer of its own again. | ||
+ | uint8_t appskey[sizeof(APPSKEY)]; | ||
+ | uint8_t nwkskey[sizeof(NWKSKEY)]; | ||
+ | memcpy_P(appskey, APPSKEY, sizeof(APPSKEY)); | ||
+ | memcpy_P(nwkskey, | ||
+ | LMIC_setSession (0x1, DEVADDR, nwkskey, appskey); | ||
+ | #else | ||
+ | // If not running an AVR with PROGMEM, just use the arrays directly | ||
+ | LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); | ||
+ | #endif | ||
+ | #endif | ||
+ | |||
+ | // Set up the channels used by the Things Network, which corresponds | ||
+ | // to the defaults of most gateways. Without this, only three base | ||
+ | // channels from the LoRaWAN specification are used, which certainly | ||
+ | // works, so it is good for debugging, but can overload those | ||
+ | // frequencies, | ||
+ | // your network here (unless your network autoconfigures them). | ||
+ | // Setting up channels should happen after LMIC_setSession, | ||
+ | | ||
+ | // NA-US channels 0-71 are configured automatically | ||
+ | LMIC_setupChannel(0, | ||
+ | LMIC_setupChannel(1, | ||
+ | LMIC_setupChannel(2, | ||
+ | LMIC_setupChannel(3, | ||
+ | LMIC_setupChannel(4, | ||
+ | LMIC_setupChannel(5, | ||
+ | LMIC_setupChannel(6, | ||
+ | LMIC_setupChannel(7, | ||
+ | LMIC_setupChannel(8, | ||
+ | // TTN defines an additional channel | ||
+ | // devices' | ||
+ | // frequency and support for class B is spotty and untested, so this | ||
+ | // frequency is not configured here. | ||
+ | |||
+ | // Disable link check validation | ||
+ | // | ||
+ | |||
+ | | ||
+ | // | ||
+ | |||
+ | |||
+ | LMIC_setDrTxpow(DR_SF7, 14); //set join at SF12 | ||
pinMode(BUILTIN_LED, | pinMode(BUILTIN_LED, | ||
digitalWrite(BUILTIN_LED, | digitalWrite(BUILTIN_LED, | ||
+ | | ||
+ | // Start job (sending automatically starts OTAA too) | ||
+ | do_send(& | ||
} | } | ||
Line 204: | Line 285: | ||
os_runloop_once(); | os_runloop_once(); | ||
} | } | ||
+ | |||
</ | </ | ||
- | In Arduino copy EUI & keys from interface | + | ==== Za ABP mode ==== |
+ | Za korištenje APB u settinzima devicea na TTNu treba označiti APB te će onda biti prikazani i network session key i app session key (kopiraju se u defaultnom '' | ||
+ | |||
+ | ==== Za OTTA mode ==== | ||
+ | OTAA mode (sa joinanjem) se enejbla otkomentiravanjem ''"# | ||
+ | |||
+ | Kopraj | ||
* Device EUI '' | * Device EUI '' | ||
* Application EUI '' | * Application EUI '' | ||
* App Key '' | * App Key '' | ||
- | Upload code | + | ==== Podesi spreading factor i gain ==== |
- | Check the received data in console | + | Spreading Factor (SF #). The higher |
+ | |||
+ | Gain? (drugi broj). | ||
+ | |||
+ | Promjeni u svim linijama! | ||
+ | |||
+ | * za stacionarni node npr '' | ||
+ | * za mapiranje iz vožnje '' | ||
+ | |||
+ | |||
+ | {{ : | ||
+ | |||
+ | LoRa Modem Packet formatting | ||
+ | {{ : | ||
+ | |||
+ | ==== Instaliraj librarije koji nedostaju ==== | ||
+ | Sketch / Include Library / Manage Libraries ... '' | ||
+ | |||
+ | ==== Upload-aj kod ==== | ||
+ | U Arduino IDE-u pod '' | ||
+ | ==== Provjeri primljene poruke u konzoli ==== | ||
* https:// | * https:// | ||
+ | |||
+ | ===== TTN mapper ===== | ||
+ | [[https:// | ||
+ | |||
+ | * https:// | ||
+ | * https:// | ||
+ | |||
+ | [[https:// | ||
+ | |||
+ | ===== Random links ===== | ||
+ | * https:// | ||
+ |