The Things Uno does not work unless serial monitor is open

Hi,

I’ve set up my TTN Uno and can’t get it to work without it being connected to my laptop with the serial monitor open.

I have added a GPS shield and wan’t to be able to wander round without my laptop to see where it can and cannot hit.

The code below even states it will go headless after a period of time, but it doesn’t. Even once its working and close the serial monitor, it stops tx’ing

Thanks
Mike

/*
 * Author: JP Meijers
 * Date: 2016-09-07
 *
 * This example program is meant for a The Things UNO board with an
 * "Adafruit Ultimate GPS+Logging Shield" on top of it. Make sure the switch on
 * the GPS shield is switched to the "Soft. Serial" position.
 *
 * Coordinates from the GPS is packed into a LoRaWan packet using binary
 * encoding, and then sent out on the air using the TTN UNO's RN2xx3 module.
 * This happens as fast as possible, while still keeping to the 1% duty cycle
 * rules enforced by the RN2483's built in LoRaWAN stack. Even though this is
 * allowed by the radio regulations of the 868MHz band, the fair use policy of
 * TTN may prohibit this.
 *
 * CHECK THE RULES BEFORE USING THIS PROGRAM!
 *
 * CHANGE ADDRESS!
 * Change the device address, network (session) key, and app (session) key to
 * the values that are registered via the TTN dashboard.
 * The appropriate line is "myLora.initABP(XXX);" or "myLora.initOTAA(XXX);"
 * When using ABP, it is advised to enable "relax frame count" on the dashboard.
 *
 * TO CONTRIBUTE TO TTN Mapper:
 * 1. Register a new Application and/or new device on the
 *     TTN Dashboard (https://console.thethingsnetwork.org).
 * 2. Copy the correct keys into the line "myLora.initABP(XXX);"
 *     or "myLora.initOTAA(XXX);" in this program.
 * 3. Comment out or remove the line: "while(!Serial); //wait for Serial to
       be available - remove this line after successful test run"
 * 4. Make sure packets are arriving on the TTN console when your node is
 *     powered and in reach of a gateway.
 * 5. Share your Application ID, Access Key and Device ID with
 *     contribute@ttnmapper.org so that your measurements can be automatically
 *     imported into TTN Mapper.
 *
 *
 * To decode the binary payload, you can use the following
 * javascript decoder function. It should work with the TTN console.
 *
function Decoder(bytes, port) {
  // Decode an uplink message from a buffer
  // (array) of bytes to an object of fields.
  var decoded = {};

  // if (port === 1) decoded.led = bytes[0];
  decoded.lat = ((bytes[0]<<16)>>>0) + ((bytes[1]<<8)>>>0) + bytes[2];
  decoded.lat = (decoded.lat / 16777215.0 * 180) - 90;

  decoded.lon = ((bytes[3]<<16)>>>0) + ((bytes[4]<<8)>>>0) + bytes[5];
  decoded.lon = (decoded.lon / 16777215.0 * 360) - 180;

  var altValue = ((bytes[6]<<8)>>>0) + bytes[7];
  var sign = bytes[6] & (1 << 7);
  if(sign)
  {
    decoded.alt = 0xFFFF0000 | altValue;
  }
  else
  {
    decoded.alt = altValue;
  }

  decoded.hdop = bytes[8] / 10.0;

  return decoded;
}
 *
 */
#include "TinyGPS++.h"
#include <SoftwareSerial.h>
#include "rn2xx3.h"

SoftwareSerial gpsSerial(8, 9); // RX, TX
TinyGPSPlus gps;
rn2xx3 myLora(Serial1);

unsigned long last_update = 0;
String toLog;
uint8_t txBuffer[9];
uint32_t LatitudeBinary, LongitudeBinary;
uint16_t altitudeGps;
uint8_t hdopGps;

#define PMTK_SET_NMEA_UPDATE_05HZ  "$PMTK220,2000*1C"
#define PMTK_SET_NMEA_UPDATE_1HZ  "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_OUTPUT_RMCGGA "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28"

void setup() {
  //output LED pin
  pinMode(13, OUTPUT);
  led_on();

  Serial.begin(57600); //serial to computer
  gpsSerial.begin(9600); //serial to gps
  Serial1.begin(57600); //serial to RN2xx3

  // make sure usb serial connection is available,
  // or after 10s go on anyway for 'headless' use of the
  // node.
  while ((!Serial) && (millis() < 10000));

  Serial.println("TTN UNO + GPS shield startup");

  //set up RN2xx3
  initialize_radio();
  //transmit a startup message
  myLora.tx("TTN Mapper on TTN Uno with GPS");

  gpsSerial.println(F(PMTK_SET_NMEA_OUTPUT_RMCGGA));
  gpsSerial.println(F(PMTK_SET_NMEA_UPDATE_1HZ));   // 1 Hz update rate

  led_off();
  delay(1000);
}

void initialize_radio()
{
  delay(100); //wait for the RN2xx3's startup message
  Serial1.flush();

  //print out the HWEUI so that we can register it via ttnctl
  String hweui = myLora.hweui();
  while(hweui.length() != 16)
  {
    Serial.println("Communication with RN2xx3 unsuccessful. Power cycle the TTN UNO board.");
    delay(10000);
    hweui = myLora.hweui();
  }
  Serial.println("When using OTAA, register this DevEUI: ");
  Serial.println(hweui);
  Serial.println("RN2xx3 firmware version:");
  Serial.println(myLora.sysver());

  //configure your keys and join the network
  Serial.println("Trying to join TTN");
  bool join_result = false;

  //ABP: initABP(String addr, String AppSKey, String NwkSKey);
  join_result = myLora.initABP("26011A41", "525845966077203A851B2DA2AE52AED7", "3D3C8F645B26F30932FFF51F0DF61D9A");

  //OTAA: initOTAA(String AppEUI, String AppKey);
  //join_result = myLora.initOTAA("70B3D57ED00001A6", "A23C96EE13804963F8C2BD6285448198");

  while(!join_result)
  {
    Serial.println("Unable to join. Are your keys correct, and do you have TTN coverage?");
    delay(60000); //delay a minute before retry
    join_result = myLora.init();
  }
  Serial.println("Successfully joined TTN");

}

void loop() {
  while (gpsSerial.available()){
    gps.encode(gpsSerial.read());
  }

  if (gps.location.age() < 1000 && (millis() - last_update) >= 1000) {
    led_on();
    Serial.print("Interval: ");
    Serial.println(millis()-last_update);

    build_packet();

    Serial.println(toLog);
    myLora.txBytes(txBuffer, sizeof(txBuffer));
    Serial.println("TX done");

    led_off();
    last_update = millis();
  }


}

void build_packet()
{
  LatitudeBinary = ((gps.location.lat() + 90) / 180.0) * 16777215;
  LongitudeBinary = ((gps.location.lng() + 180) / 360.0) * 16777215;

  txBuffer[0] = ( LatitudeBinary >> 16 ) & 0xFF;
  txBuffer[1] = ( LatitudeBinary >> 8 ) & 0xFF;
  txBuffer[2] = LatitudeBinary & 0xFF;

  txBuffer[3] = ( LongitudeBinary >> 16 ) & 0xFF;
  txBuffer[4] = ( LongitudeBinary >> 8 ) & 0xFF;
  txBuffer[5] = LongitudeBinary & 0xFF;

  altitudeGps = gps.altitude.meters();
  txBuffer[6] = ( altitudeGps >> 8 ) & 0xFF;
  txBuffer[7] = altitudeGps & 0xFF;

  hdopGps = gps.hdop.value()/10;
  txBuffer[8] = hdopGps & 0xFF;

  toLog = "";
  for(size_t i = 0; i<sizeof(txBuffer); i++)
  {
    char buffer[3];
    sprintf(buffer, "%02x", txBuffer[i]);
    toLog = toLog + String(buffer);
  }
}

void led_on(){
  digitalWrite(13, 1);
}

void led_off(){
  digitalWrite(13, 0);
}

If you remove the serial cable you have no power.
So… how do you power both boards ?

You can safely remove the while statement, however did you ever try to run it without computer at all? After 10s it should run.

I power the board with a usb power bank. I have removed the while statement yes and it should proceed, but doesn’t.

Should the board not be powered via usb if not connected to a computer?

I usually power through a powerbank an Arduino-based node, and I initially lost time due to waiting for serial when not connected.
Are you sending to a single channel gateway or a real gateway? In the former case, only a fraction of messages can be received, so you may have to wait many minutes before a message is successfully captured by the gateway.

As a side comment, please do not leave real keys in the code posted here :wink:

1 Like

I’m actually too far away from a gateway. Theres a hill near by me where I can access Liverpool.

I am using ABP rather than OTAA as OTAA wouldn’t work. I sat on top of the hill with my laptop and managed to get the packets showing in TTN console with ABP

With ABP in the serial monitor, for some reason it says successfully joined then continues to send packets. Without the serial monitor it does nothing even with the while loop removed.

I understand about the keys as well, these are changing frequently however haha