fab-lab.eu
Published

GPS Mapper for The Things Network (TTN) - LoRaWAN

Help mapping the signal strength of the TTN in your region with this tiny GPS mapper feeding the ttnmapper.org.

IntermediateFull instructions provided2 hours16,736
GPS Mapper for The Things Network (TTN) - LoRaWAN

Things used in this project

Hardware components

Adafruit Feather HUZZAH with ESP8266 WiFi
Adafruit Feather HUZZAH with ESP8266 WiFi
×1
Adafruit GPS Wing
wire TX to PIN 0 of Adafruit Feather ESP8266 and the needed coin cell battery for quick first fix
×1
Adafruit Lora Wing
select the right frequency for your region e.g. 868MHz (named 900) for EU, you need two 1N4001 diodes for wiring in addition
×1

Story

Read more

Custom parts and enclosures

enclosure

enclosure top (loose fit, good to glue together)

Code

TTN GPS Mapper

Arduino
please change to your EUIs for device and application plus the key for encryption - ATTENTION please change the transmit interval in this example it is 10sec which is *not* fair use of the LoRaWAN specs! for testing only ...
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <lmic.h>
#include <hal/hal.h>

uint8_t coords[9];

static const int RXPin = 0, TXPin = 1; // TXPin not used / dummy
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device

SoftwareSerial ss(RXPin, TXPin);
uint32_t timer = millis();

// LoraWAN Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
// https://github.com/matthijskooijman/arduino-lmic
// -------- LoRa PinMapping FeatherWing Octopus

// THIS WORKS ONLY with the two additional diodes see wiring diagram
const lmic_pinmap lmic_pins = {  
  .nss = 2,                            // Connected to pin D
  .rxtx = LMIC_UNUSED_PIN,             // For placeholder only, Do not connected on RFM92/RFM95
  .rst = LMIC_UNUSED_PIN,              // Needed on RFM92/RFM95? (probably not) D0/GPIO16 
  .dio = {
    15, 15, LMIC_UNUSED_PIN         }
};

// replace with YOUR DEVEUI here use LSB and copy hex to replace 0x00
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);
}

// replace with YOUR APPEUI here use LSB and copy hex to replace 0x00
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);
}

// replace with YOUR APPKEY here use MSB and copy hex to replace 0x00
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);
};

volatile int LoRaWAN_Tx_Ready      = 0; // Merker für ACK 

int LoRaWAN_Rx_Payload = 0 ;
// -------- LoRa Event 
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"));
      LoRaWAN_Rx_Payload = 0; 
      for (int i = 0;i<LMIC.dataLen;i++) { 
        Serial.println(LMIC.frame[i+ LMIC.dataBeg],HEX);
        LoRaWAN_Rx_Payload = 256*LoRaWAN_Rx_Payload+LMIC.frame[i+ LMIC.dataBeg];
      }
    }
    LoRaWAN_Tx_Ready = 1;
    // 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 setup(){ // Einmalige Initialisierung
  Serial.begin(115200);
  ss.begin(GPSBaud);
  
  // -- Initialisiere LoraWAN 
  os_init();             // LMIC LoraWAN
  LMIC_reset();          // Reset the MAC state 
  LMIC.txpow = 27;       // Maximum TX power 
  LMIC.datarate=DR_SF12; // Long Range
  LMIC.rps = updr2rps(LMIC.datarate);

}

void loop() { // Kontinuierliche Wiederholung 
  
  while (ss.available() > 0)
  
  if (gps.encode(ss.read()))
  {

    if (gps.location.isValid()) {

    Serial.print(gps.altitude.meters(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
    Serial.print(F(","));
    Serial.println(gps.location.isValid(), 6);
        
    
    if (LMIC.opmode & (1 << 7)) { 
      Serial.println(F("OP_TXRXPEND, not sending"));
    } 
    else {
      // Prepare upstream data transmission at the next possible time.
      LoRaWAN_Tx_Ready = 0;    
      int32_t lati = gps.location.lat() * 10000;
      int32_t lon = gps.location.lng() * 10000;
      int32_t altitudeGPS = gps.altitude.meters(); // int16_t
      int8_t hdopGPS = gps.hdop.value(); 

      Serial.println(lati);
      Serial.println(lon);
      Serial.println(altitudeGPS);
      Serial.println(hdopGPS);

      // Pad 2 int32_t to 6 8uint_t, big endian (24 bit each, having 11 meter precision)
      coords[0] = lati;
      coords[1] = lati >> 8;
      coords[2] = lati >> 16;

      coords[3] = lon;
      coords[4] = lon >> 8;
      coords[5] = lon >> 16;

      coords[6] = altitudeGPS;
      coords[7] = altitudeGPS >> 8;

      coords[8] = hdopGPS;
   
      LMIC_setTxData2(1, (uint8_t*) coords, sizeof(coords), 0);
   
      Serial.println(F("Packet queued"));
      while(LoRaWAN_Tx_Ready==0) {
        yield();
        os_runloop_once();
      };  // Warte bis gesendet
    //}
    // Blockende
      Serial.print(F("Waiting "));

      for (int i = 0;i<10;i++) { 
        Serial.print(F("."));
        delay(1000); // for test only - this results in 10 sec transmit, change to much high value to be conform with the duty cycle !!!
      }
      Serial.println(" done.");

     }
    } else {
      Serial.println("no GPS fix");
    }
 }
}

Credits

fab-lab.eu

fab-lab.eu

22 projects • 275 followers
Maker!

Comments