User Tools

Site Tools


project:lora_nodes

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
project:lora_nodes [2018/02/25 12:46] dpproject: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.
  
 ===== Arduino i podrška za ESP32 ===== ===== Arduino i podrška za ESP32 =====
Line 6: Line 7:
   * https://www.arduino.cc/en/Main/Software   * https://www.arduino.cc/en/Main/Software
  
-Instaliraj Arduino podršku za ESP32 mikroknotrolere+Instaliraj Arduino podršku za ESP32 mikrokontrolere
   * https://github.com/espressif/arduino-esp32   * https://github.com/espressif/arduino-esp32
  
Line 14: Line 15:
   * https://console.thethingsnetwork.org/   * https://console.thethingsnetwork.org/
  
-Pod TTN Applications registriraj device+Pod TTN Applications registriraj novu aplikaciju (grupa uređaja)
   * https://console.thethingsnetwork.org/applications/   * https://console.thethingsnetwork.org/applications/
 +
 +Registriraj novi device.
 +
  
 ===== Example code ===== ===== Example code =====
  
-==== Spremi primjer i instaliraj librarije koji nedostaju ====+==== Spremi primjer ====
  
-<file cpp otaa_example.ino>+<file cpp otaa_abp_example.ino>
 #include <lmic.h> #include <lmic.h>
 #include <hal/hal.h> #include <hal/hal.h>
Line 32: 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, this means to reverse +// cycle limitations)
-// the bytesFor TTN issued EUIs the last bytes should be 0xD5, 0xB3, +const unsigned TX_INTERVAL 20;
-// 0x70. +
-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); +
-}+
  
-// 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, DEVEUI, 8); +
-}+
  
-// 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, 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); 
 +  } 
 +   
 +  // 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, 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] = { 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, APPKEY, 16); 
 +  }
  
-static uint8_t mydata[] = "Hi";+#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 77: Line 105:
   Serial.print(": ");   Serial.print(": ");
   switch (ev) {   switch (ev) {
-case EV_SCAN_TIMEOUT: +    case EV_SCAN_TIMEOUT: 
-  Serial.println(F("EV_SCAN_TIMEOUT")); +      Serial.println(F("EV_SCAN_TIMEOUT")); 
-  u8x8.drawString(0, 7, "EV_SCAN_TIMEOUT"); +      u8x8.drawString(0, 7, "EV_SCAN_TIMEOUT"); 
-  break; +      break; 
-case EV_BEACON_FOUND: +    case EV_BEACON_FOUND: 
-  Serial.println(F("EV_BEACON_FOUND")); +      Serial.println(F("EV_BEACON_FOUND")); 
-  u8x8.drawString(0, 7, "EV_BEACON_FOUND"); +      u8x8.drawString(0, 7, "EV_BEACON_FOUND"); 
-  break; +      break; 
-case EV_BEACON_MISSED: +    case EV_BEACON_MISSED: 
-  Serial.println(F("EV_BEACON_MISSED")); +      Serial.println(F("EV_BEACON_MISSED")); 
-  u8x8.drawString(0, 7, "EV_BEACON_MISSED"); +      u8x8.drawString(0, 7, "EV_BEACON_MISSED"); 
-  break; +      break; 
-case EV_BEACON_TRACKED: +    case EV_BEACON_TRACKED: 
-  Serial.println(F("EV_BEACON_TRACKED")); +      Serial.println(F("EV_BEACON_TRACKED")); 
-  u8x8.drawString(0, 7, "EV_BEACON_TRACKED"); +      u8x8.drawString(0, 7, "EV_BEACON_TRACKED"); 
-  break; +      break; 
-case EV_JOINING: +    case EV_JOINING: 
-  Serial.println(F("EV_JOINING")); +      Serial.println(F("EV_JOINING")); 
-  u8x8.drawString(0, 7, "EV_JOINING"); +      u8x8.drawString(0, 7, "EV_JOINING"); 
-  break; +      break; 
-case EV_JOINED: +    case EV_JOINED: 
-  Serial.println(F("EV_JOINED")); +      Serial.println(F("EV_JOINED")); 
-  u8x8.drawString(0, 7, "EV_JOINED "); +      u8x8.drawString(0, 7, "EV_JOINED "); 
-            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("EV_RFU1")); +      Serial.println(F("EV_RFU1")); 
-  u8x8.drawString(0, 7, "EV_RFUI"); +      u8x8.drawString(0, 7, "EV_RFUI"); 
-  break; +      break; 
-case EV_JOIN_FAILED: +    case EV_JOIN_FAILED: 
-  Serial.println(F("EV_JOIN_FAILED")); +      Serial.println(F("EV_JOIN_FAILED")); 
-  u8x8.drawString(0, 7, "EV_JOIN_FAILED"); +      u8x8.drawString(0, 7, "EV_JOIN_FAILED"); 
-  break; +      break; 
-case EV_REJOIN_FAILED: +    case EV_REJOIN_FAILED: 
-  Serial.println(F("EV_REJOIN_FAILED")); +      Serial.println(F("EV_REJOIN_FAILED")); 
-  u8x8.drawString(0, 7, "EV_REJOIN_FAILED"); +      u8x8.drawString(0, 7, "EV_REJOIN_FAILED"); 
-  //break; +      //break; 
-  break; +      break; 
-case EV_TXCOMPLETE: +    case EV_TXCOMPLETE: 
-  Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); +      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); 
-  u8x8.drawString(0, 7, "EV_TXCOMPLETE"); +      u8x8.drawString(0, 7, "EV_TXCOMPLETE"); 
-  digitalWrite(BUILTIN_LED, LOW); +      digitalWrite(BUILTIN_LED, LOW); 
-  if (LMIC.txrxFlags & TXRX_ACK) { +      if (LMIC.txrxFlags & TXRX_ACK) { 
-    Serial.println(F("Received ack")); +        Serial.println(F("Received ack")); 
-    u8x8.drawString(0, 7, "Received ACK"); +        u8x8.drawString(0, 7, "Received ACK"); 
-  +      
-  if (LMIC.dataLen) { +      if (LMIC.dataLen) { 
-    Serial.println(F("Received ")); +        Serial.println(F("Received ")); 
-    u8x8.drawString(0, 6, "RX "); +        u8x8.drawString(0, 6, "RX "); 
-    Serial.println(LMIC.dataLen); +        Serial.println(LMIC.dataLen); 
-    u8x8.setCursor(4, 6); +        u8x8.setCursor(4, 6); 
-    u8x8.printf("%i bytes", LMIC.dataLen); +        u8x8.printf("%i bytes", LMIC.dataLen); 
-    Serial.println(F(" bytes of payload")); +        Serial.println(F(" bytes of payload")); 
-    u8x8.setCursor(0, 7); +        u8x8.setCursor(0, 7); 
-    u8x8.printf("RSSI %d SNR %.1d", LMIC.rssi, LMIC.snr); +        u8x8.printf("RSSI %d SNR %.1d", LMIC.rssi, LMIC.snr); 
-  +      
-  // Schedule next transmission +      // Schedule next transmission 
-  os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); +      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); 
-  break; +      break; 
-case EV_LOST_TSYNC: +    case EV_LOST_TSYNC: 
-  Serial.println(F("EV_LOST_TSYNC")); +      Serial.println(F("EV_LOST_TSYNC")); 
-  u8x8.drawString(0, 7, "EV_LOST_TSYNC"); +      u8x8.drawString(0, 7, "EV_LOST_TSYNC"); 
-  break; +      break; 
-case EV_RESET: +    case EV_RESET: 
-  Serial.println(F("EV_RESET")); +      Serial.println(F("EV_RESET")); 
-  u8x8.drawString(0, 7, "EV_RESET"); +      u8x8.drawString(0, 7, "EV_RESET"); 
-  break; +      break; 
-case EV_RXCOMPLETE: +    case EV_RXCOMPLETE: 
-  // data received in ping slot +      // data received in ping slot 
-  Serial.println(F("EV_RXCOMPLETE")); +      Serial.println(F("EV_RXCOMPLETE")); 
-  u8x8.drawString(0, 7, "EV_RXCOMPLETE"); +      u8x8.drawString(0, 7, "EV_RXCOMPLETE"); 
-  break; +      break; 
-case EV_LINK_DEAD: +    case EV_LINK_DEAD: 
-  Serial.println(F("EV_LINK_DEAD")); +      Serial.println(F("EV_LINK_DEAD")); 
-  u8x8.drawString(0, 7, "EV_LINK_DEAD"); +      u8x8.drawString(0, 7, "EV_LINK_DEAD"); 
-  break; +      break; 
-case EV_LINK_ALIVE: +    case EV_LINK_ALIVE: 
-  Serial.println(F("EV_LINK_ALIVE")); +      Serial.println(F("EV_LINK_ALIVE")); 
-  u8x8.drawString(0, 7, "EV_LINK_ALIVE"); +      u8x8.drawString(0, 7, "EV_LINK_ALIVE"); 
-  break; +      break; 
-default: +    default: 
-  Serial.println(F("Unknown event")); +      Serial.println(F("Unknown event")); 
-  u8x8.setCursor(0, 7); +      u8x8.setCursor(0, 7); 
-  u8x8.printf("UNKNOWN EVENT %d", ev); +      u8x8.printf("UNKNOWN EVENT %d", ev); 
-  break;+      break;
   }   }
 } }
Line 171: 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("OP_TXRXPEND, not sending")); +    Serial.println(F("OP_TXRXPEND, not sending")); 
-u8x8.drawString(0, 7, "OP_TXRXPEND, not sent");+    u8x8.drawString(0, 7, "OP_TXRXPEND, not sent");
   } else {   } else {
-// Prepare upstream data transmission at the next possible time. +    // Prepare upstream data transmission at the next possible time. 
-LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0); +    LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0); 
-Serial.println(F("Packet queued")); +    Serial.println(F("Packet queued")); 
-u8x8.drawString(0, 7, "PACKET QUEUED"); +    u8x8.drawString(0, 7, "PACKET QUEUED"); 
-digitalWrite(BUILTIN_LED, HIGH);+    digitalWrite(BUILTIN_LED, HIGH);
   }   }
   // Next TX is scheduled after TX_COMPLETE event.   // Next TX is scheduled after TX_COMPLETE event.
 } }
 +
  
 void setup() { void setup() {
Line 189: Line 218:
   u8x8.begin();   u8x8.begin();
   u8x8.setFont(u8x8_font_chroma48medium8_r);   u8x8.setFont(u8x8_font_chroma48medium8_r);
-  u8x8.drawString(0, 1, "LoRaWAN LMiC");+  u8x8.drawString(0, 1, "radiona.org");
  
   SPI.begin(5, 19, 27);   SPI.begin(5, 19, 27);
Line 197: 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_SF1214); //set join at SF12  + 
-  // Start job (sending automatically starts OTAA too+#ifndef USE_JOINING 
-  do_send(&sendjob);+    #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(appskeyAPPSKEY, sizeof(APPSKEY)); 
 +      memcpy_P(nwkskey, NWKSKEY, sizeof(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, so be sure to configure the full frequency range of 
 +  // your network here (unless your network autoconfigures them). 
 +  // Setting up channels should happen after LMIC_setSession, as that 
 +  // configures the minimal channel set
 +  // NA-US channels 0-71 are configured automatically 
 +  LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band 
 +  LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band 
 +  // TTN defines an additional channel at 869.525Mhz using SF9 for class B 
 +  // devices' ping slots. LMIC does not have an easy way to define set this 
 +  // frequency and support for class B is spotty and untested, so this 
 +  // frequency is not configured here. 
 + 
 +  // Disable link check validation 
 +  //LMIC_setLinkCheckMode(0)
 + 
 +  // TTN uses SF9 for its RX2 window. 
 +  //LMIC.dn2Dr = DR_SF9; 
 +   
 +   
 +  LMIC_setDrTxpow(DR_SF7, 14); //set join at SF12
  
   pinMode(BUILTIN_LED, OUTPUT);   pinMode(BUILTIN_LED, OUTPUT);
   digitalWrite(BUILTIN_LED, LOW);   digitalWrite(BUILTIN_LED, LOW);
 +  
 +  // Start job (sending automatically starts OTAA too)
 +  do_send(&sendjob);
 } }
  
Line 208: Line 285:
   os_runloop_once();   os_runloop_once();
 } }
 +
 </file> </file>
  
-==== Koprija EUI i ključeve s TTN konzole u kod ==== +==== 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 ''msb'' formatu), te device id (kopira se direktno kao broj). U TTN konzoli da ideš na ABP join i pod settings treba maknuti najdoljnju kvačicu ''Frame Counter Checks''
 + 
 +==== Za OTTA mode ==== 
 +OTAA mode (sa joinanjem) se enejbla otkomentiravanjem ''"#define USE_JOINING"'' 
 + 
 +Kopraj EUI i ključeve s TTN konzole u kod:
   * Device EUI ''lsb''   * Device EUI ''lsb''
   * Application EUI ''lsb''   * Application EUI ''lsb''
Line 233: Line 316:
 {{ :project:lora_modem_packet_formating.png?nolink&600 |}} {{ :project:lora_modem_packet_formating.png?nolink&600 |}}
  
-==== Upload-aj kod ==== +==== Instaliraj librarije koji nedostaju ==== 
-Izaberi odgovarajućboard u Arduino-u+Sketch / Include Library / Manage Libraries ... ''lmic'' ''U8x8''
  
 +==== Upload-aj kod ====
 +U Arduino IDE-u pod ''Tools / Boards'' izaberi odgovarajuću pločicu (u našem slučaju ''Heltec_WIFI_Kit_32'') i pod ''Port'' izaberi port na kojem se nalazi device.
 ==== Provjeri primljene poruke u konzoli ==== ==== Provjeri primljene poruke u konzoli ====
   * https://console.thethingsnetwork.org/applications/   * https://console.thethingsnetwork.org/applications/
Line 246: Line 331:
  
 [[https://play.google.com/store/apps/details?id=com.jpmeijers.ttnmapper&hl=en|TTN mapper]] android aplikacija pomoću koje se može upariti telefon s GPS-om i LoRa node, kako bi se moglo testirati i mapirati pokrivenost mreže. [[https://play.google.com/store/apps/details?id=com.jpmeijers.ttnmapper&hl=en|TTN mapper]] android aplikacija pomoću koje se može upariti telefon s GPS-om i LoRa node, kako bi se moglo testirati i mapirati pokrivenost mreže.
 +
 +===== Random links =====
 +  * https://lcd-web.nl/ttngenerator/
  
project/lora_nodes.1519559190.txt.gz · Last modified: by dp