Make your own LED timepiece! Use FLORA and its GPS module to tell time with a ring of pixels. A leather cuff holds the circuit and hides the battery. The watch is chunky but still looks and feels great on tiny wrists!

The circuit sandwich becomes the face of the watch, and you'll use a tactile switch to make a mode selector. The watch has timekeeping (one LED for hours and one for minutes), GPS navigation (customize your waypoint in the provided Arduino sketch), and compass modes.

This is an intermediate-level project requiring soldering and precision crafting. Before you begin, you should read and practice the following guides:
This project is a collaboration with Tyler Cooper! Project help and modeling from Risa Rose.
For this project you will need:
Any entry level 'all-in-one' soldering iron that you might find at your local hardware store should work. As with most things in life, you get what you pay for.
Upgrading to a higher end soldering iron setup, like the Hakko FX-888 that we stock in our store, will make soldering fun and easy.

Do not use a "ColdHeat" soldering iron
! They are not suitable for delicate electronics work and can damage the boards (see here).

Click here to buy our entry level adjustable 30W 110V soldering iron.

Click here to upgrade to a Genuine Hakko FX-888 adjustable temperature soldering iron.

Learn how to solder with tons of tutorials!
You will want rosin core, 60/40 solder. Good solder is a good thing. Bad solder leads to bridging and cold solder joints which can be tough to find.

Click here to buy a spool of leaded solder (recommended for beginners).

Click here to buy a spool of lead-free solder.
Sharp scissors are a must!
Don't forget your wire strippers, pliers, and flush snips! Tweezers can help manipulate the wires connecting components in your circuit.
A helping third hand tool really makes this project a joy to build.

Click here to buy a helping third hand tool.

E6000 craft adhesive dries clear and flexible with a very strong bond. We prefer the small tubes over a single large one, which tends to get gummed up over time. It should be used in a well ventilated area and takes 24 hours to fully cure.

If you've never used this stuff before, let me put it this way: if E6000 were a new truck, hot glue would be a beat up station wagon with no muffler. Trust me, use the good stuff, you won't regret it!

Each component connects to FLORA main board as follows:

GPS:
  • 3.3V->3.3V
  • TX-> FLORA RX
  • RX-> FLORA TX
  • GND-> GND

Accelerometer:
  • GND-> GND
  • SCL -> SCL
  • SDA -> SDA
  • 3.3V-> 3.3V

NeoPixel ring:
  • Vcc (power)-> FLORA VBATT
  • IN (Data Input)-> FLORA D6
  • Gnd (ground)-> GND

Tactile switch:
  • any two diagonal pins -> FLORA D10 and GND

Battery plugs in via the onboard JST port
Gather your tools and supplies on a clean, stable work surface with good lighting.
Start by soldering small stranded wires to your electronics components, about two inches long each. Strip the wire ends, twirl the stranded core to make it more easily pass through the circuit boards' holes, and solder to the NeoPixel ring's IN, Vcc, and Gnd pads. It's best to solder on the back side of this particular board, since the pads are quite close to the leads of the NeoPixels on the front of the board, where a large dab of solder could bridge the two.
Repeat the process of attaching wires to the GPS (3.3V, RX, TX, GND) and accelerometer/compass module (3V, SDA, SCL, GND).
Trim off any wire ends with flush snips.
The first thing that gets attached to the FLORA main board is the GPS. Use the NeoPixel ring to help position the round GPS module in the center back of FLORA. The ring is exactly the same size as FLORA, and so functions as a jig. Use double stick tape or a dab of E6000 to hold the GPS in place.

Hold the circuit with the help of a third hand tool and wire the GPS connections to FLORA according to the circuit diagram. Make sure the wires are not longer than they need to be, and sit flush to the board.

My third hand tool has heat shrink tubing over the grippy alligator clips. This was Collin Cunningham's pro tip, and prevents scratching my circuits and their components!
Flip the circuit over and solder the wires to the FLORA main board. Trim any excess wire ends.
Use a piece of double sided foam tape to mount the accelerometer in the center of the FLORA board, right on top of the central 32u4 microcontroller chip. The foam helps distance the boards from one another to avoid shorting any components on the board.

Trim, strip, and solder the wire connections of the accelerometer/compass according to the circuit diagram.
To prepare the tactile switch, flatten and snip off any two diagonal pins.

Insert the switch into D10 and GND on the busy side of the FLORA board. Bend out the leads to hold it in position and solder the joints.

This big tactile button makes it easy to switch watch modes by holding down the whole face of the watch for a few seconds.

Verify that your solder connections are secure with a multimeter.

Before you proceed, test the GPS and accelerometer with the sample sketches provided with their respective code libraries. The next steps will make it hard to correct any bad solder joints or stray wires, so don't skimp on testing the circuit now!
Glue the NeoPixel to FLORA, lining up the PCB edges exactly. Don't pinch the boards together too much-- there should be a cushion of glue separating the two boards. Use a toothpick to fill in any gaps with more adhesive, for instance near where the GPS wires route under the board.

The watch code will allow you to adjust which LED is at 12 o'clock, so the orientation of the ring doesn't matter.

Allow the glue to set up for at least an hour before trimming, stripping, and soldering the ring's wires to pads on FLORA according to the circuit diagram. Load the NeoPixel test code to be sure the ring is connected and functionaing properly.

It turns out the wires around the outside of the circuit aren't super durable (catches on clothing), so if we were you or had this project to do over again, we'd solder the NeoPixel ring's wires via the inside of the ring before glueing the ring to FLORA.

The circuit is finished! Now let's make it a watch.
The watch circuit will be held in place by the small strap on a leather watch cuff. The USB port and JST port line up perpendicularly to the band for easy access, and the tactile switch is on the "top" side of the watch. This will point FLORA's onboard power switch towards you while wearing the watch.
Unthread the small strap from one half the cuff and lay it over the busy side of the FLORA board, between the USB port and JST battery connector. The tactile switch intersects with this strap for easy mode selection when you're wearing it.
Use two small strips of fabric to make "belt loops" for the circuit. Apply a small dollop of E6000 adhesive to either side of the USB connector and clip a fabric strips to FLORA with a binder clip. Wipe away and overflow adhesive.
Repeat with another belt loop to the other side of the USB port.
Line up the circuit with the band again, this time placing it between the circuit and the fabric strips.

Apply two more small dollops of adhesive, this time on either side of the JST battery connector, and stick the fabric down taught across the leather band.

Clamp with more binder clips and allow to dry for 24 hours.

Less glue is more! Check to make sure there's no adhesive touching the leather band. Your circuit should slide along the band freely so you can adjust it, so here's a place where being tidy really yields the best result!
After drying, you can remove the clips and trim the fabric close to the board. It should slide along the band but not be too loose or your watch will be floppy! If your fabric strips aren't tight enough, you can use a needle and thread to cinch them up now.
Glide your watch face toward the buckle side and thread the free end back through the cuff.

The FLORA NeoGeo Watch is very easy to use. It has three modes. To change between modes, press and hold the button for about 2-3 seconds. You can hold down the button and it will change from mode 1 to mode 2 to mode 3 and then back to mode 1. The three modes are:

  1. Watch Mode
  2. Navigation Mode
  3. Compass Mode

Watch Mode works by having showing the "hour hand" as an orange LED, the "minute hand" as a yellow LED, and if both "hands" are on top of each other, the LED will glow purple. When you first turn on your watch, you need to give the GPS a clear view of the sky. Once the GPS locks on, it will automatically update the time for you. Now, if you lose a GPS signal, it will still remember the time (until you disconnect the watch from power).

Navigation Mode works by pointing an LED in the direction you need to go to reach the coordinates you entered in the sketch. When you get close to your destination, the LED will change from yellow to red. You need to have a constant GPS lock for this mode to work.

Compass Mode works by always pointing north with a blue LED.

The code for the FLORA NeoGeo Watch is pretty simple and straightforward. We are using the standard Adafruit GPS Library, a Time Library, the LSM303 Compass Module Library, and the FLORA Pixel Library. You will find links to the libraries at https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/master/Flora_NeoGeo_Watch.

// SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
//
// SPDX-License-Identifier: MIT

// Test code for Adafruit Flora GPS modules
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired.
//
// Tested and works great with the Adafruit Flora GPS module
// ------> http://adafruit.com/products/1059
// Pick one up today atAdafruit https://www.adafruit.com/
// and help support open source hardware & software! 

#include <Adafruit_GPS.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303DLH_Mag.h>


Adafruit_GPS GPS(&Serial1);
/* Assign a unique ID to this sensor at the same time */
Adafruit_LSM303DLH_Mag_Unified mag = Adafruit_LSM303DLH_Mag_Unified(12345);

// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences
#define GPSECHO false

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;

//--------------------------------------------------|
//                    WAYPOINT                      |
//--------------------------------------------------|
//Please enter the latitude and longitude of your   |
//desired destination:                              |
#define GEO_LAT                48.009551
#define GEO_LON               -88.771131
//--------------------------------------------------|
//Your NeoPixel ring may not line up with ours.     |
//Enter which NeoPixel led is your top LED (0-15).  |
#define TOP_LED                1
//--------------------------------------------------|
//Your compass module may not line up with ours.    |
//Once you run compass mode, compare to a separate  |
//compass (like one found on your smartphone).      |
//Point your TOP_LED north, then count clockwise    |
//how many LEDs away from TOP_LED the lit LED is    |
#define LED_OFFSET             0
//--------------------------------------------------|

// Navigation location
float targetLat = GEO_LAT;
float targetLon = GEO_LON;

// Trip distance
float tripDistance;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, 6, NEO_GRB + NEO_KHZ800);

// Offset hours from gps time (UTC)
//const int offset = 1;   // Central European Time
//const int offset = -4;  // Eastern Daylight Time (USA)
const int offset = -5;  // Central Daylight Time (USA)
//const int offset = -8;  // Pacific Standard Time (USA)
//const int offset = -7;  // Pacific Daylight Time (USA)

int topLED = TOP_LED;
int compassOffset = LED_OFFSET;

int lastMin = 16;
int lastHour = 16;
int startLED = 0;
int startLEDlast = 16;
int lastCombined = 0;
int start = 0;
int mode = 0;
int lastDir = 16;
int dirLED_r = 0;
int dirLED_g = 0;
int dirLED_b = 255;
int compassReading;

// Calibration offsets
float magxOffset = 2.55;
float magyOffset = 27.95;

// Pushbutton setup
int buttonPin = 10;             // the number of the pushbutton pin
int buttonState;               // the current reading from the input pin
int lastButtonState = HIGH;    // the previous reading from the input pin
long buttonHoldTime = 0;         // the last time the output pin was toggled
long buttonHoldDelay = 2500;      // how long to hold the button down

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;     // the last time the output pin was toggled
long debounceDelay = 50;       // the debounce time; increase if the output flickers
long menuDelay = 2500;
long menuTime;

float fLat = 0.0;
float fLon = 0.0;

void setup()
{
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");

  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
  // the parser doesn't care about other sentences at this time
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
  // For the parsing code to work nicely and have time to sort thru the data, and
  // print it out we don't suggest using anything higher than 1 Hz

  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);

  /* Initialise the sensor */
  if(!mag.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
    while(1);
  }
  // Ask for firmware version
  Serial1.println(PMTK_Q_RELEASE);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  // Make input & enable pull-up resistors on switch pins for pushbutton
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH); 
}

uint32_t gpsTimer = millis();
uint32_t startupTimer = millis();
uint32_t compassTimer = millis();

void loop() // run over and over again
{
  compassCheck();
  // read the state of the switch into a local variable:
  int buttonState = digitalRead(buttonPin);

  if (buttonState == LOW) {
    buttonCheck();
  }

  lastButtonState = buttonState;

  //Serial.println(buttonState);
  // read data from the GPS in the 'main loop'
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  if (GPSECHO)
    if (c) Serial.print(c);
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
    if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
      return; // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (gpsTimer > millis()) gpsTimer = millis();

  if (start == 0) {
    if (GPS.fix) {
      // set the Time to the latest GPS reading
      setTime(GPS.hour, GPS.minute, GPS.seconds, GPS.day, GPS.month, GPS.year);
      delay(50);
      adjustTime(offset * SECS_PER_HOUR);
      delay(500);
      tripDistance = (double)calc_dist(fLat, fLon, targetLat, targetLon);
      start = 1;
    }
  }    
  // approximately every 60 seconds or so, update time
  if ((millis() - gpsTimer > 60000) && (start == 1)) {
    gpsTimer = millis(); // reset the timer
    if (GPS.fix) {
      // set the Time to the latest GPS reading
      setTime(GPS.hour, GPS.minute, GPS.seconds, GPS.day, GPS.month, GPS.year);
      delay(50);
      adjustTime(offset * SECS_PER_HOUR);
      delay(500);
    }
  }

  if (GPS.fix) {
    fLat = decimalDegrees(GPS.latitude, GPS.lat);
    fLon = decimalDegrees(GPS.longitude, GPS.lon);
  }

  if (mode == 0) {
    clockMode();
  }

  if (mode == 1) {
    navMode();
  }

  if (mode == 2) {
    compassMode();
  }
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void buttonCheck() {
  menuTime = millis();
  int buttonState = digitalRead(buttonPin);
  if (buttonState == LOW && lastButtonState == HIGH) {
    buttonHoldTime = millis();
  }

  if (buttonState == LOW && lastButtonState == LOW) {
    if ((millis() - buttonHoldTime) > buttonHoldDelay) {

      if(mode == 2) {
        mode = 0;
        lastMin = 16;
        lastHour = 16;
        colorWipe(strip.Color(0, 0, 0), 20);
        buttonHoldTime = millis();
      } 
      else {
        mode = mode + 1;
        colorWipe(strip.Color(0, 0, 0), 20);
        buttonHoldTime = millis();
      }
    }
  }
}

void clockMode() {
  if (start == 1) {
    strip.setPixelColor(startLEDlast, strip.Color(0, 0, 0));
    strip.show();

    float gpsMin = (minute() + (second()/60.0));
    unsigned int ledMin = 0;
    int minTemp = 0;
    minTemp = topLED - (gpsMin + 1.875)/3.75;

    if (minTemp < 0) {
      ledMin = minTemp + 16;
    } 
    else {
      ledMin = minTemp;
    }

    float gpsHour = (hour() + (minute()/60.0));
    if (gpsHour > 12) { 
      gpsHour = gpsHour - 12; 
    }
    unsigned int ledHour = 0;
    int hourTemp = 0;
    hourTemp = topLED - (gpsHour + .375)/.75;

    if (hourTemp < 0) {
      ledHour = hourTemp + 16;
    } 
    else {
      ledHour = hourTemp;
    }

    if ((ledHour == ledMin) && (lastCombined == 0)) {
      strip.setPixelColor(lastHour, strip.Color(0, 0, 0));
      strip.setPixelColor(lastMin, strip.Color(0, 0, 0));
      strip.setPixelColor(ledHour, strip.Color(255, 0, 255));
      strip.show();
      lastCombined = 1;
      lastHour = ledHour;
      lastMin = ledMin;
    } 
    else {
      if (lastHour != ledHour) {
        strip.setPixelColor(lastHour, strip.Color(0, 0, 0));
        strip.setPixelColor(ledHour, strip.Color(255, 50, 0));
        strip.show();
        lastHour = ledHour;
      }
      if (lastMin != ledMin) {
        strip.setPixelColor(lastMin, strip.Color(0, 0, 0));
        strip.setPixelColor(ledMin, strip.Color(200, 200, 0));
        if (lastCombined == 1) {
          strip.setPixelColor(ledHour, strip.Color(255, 0, 0));
          lastCombined = 0;
        }
        strip.show();
        lastMin = ledMin;
      }
    }   
  } 
  else {
    // if millis() or timer wraps around, we'll just reset it
    if (startupTimer > millis()) startupTimer = millis();

    // approximately every 10 seconds or so, update time
    if (millis() - startupTimer > 200) {
      startupTimer = millis(); // reset the timer
      if (startLED == 16) {
        startLED = 0;
      }
      strip.setPixelColor(startLEDlast, strip.Color(0, 0, 0));
      strip.setPixelColor(startLED, strip.Color(0, 255, 0));
      strip.show();
      startLEDlast = startLED;
      startLED++;
      //delay(200);
    }
  }
}

void navMode() {
  if (start == 1) {

    compassCheck();

    headingDistance((double)calc_dist(fLat, fLon, targetLat, targetLon));

    if ((calc_bearing(fLat, fLon, targetLat, targetLon) - compassReading) > 0) {
      compassDirection(calc_bearing(fLat, fLon, targetLat, targetLon)-compassReading);
    } 
    else {
      compassDirection(calc_bearing(fLat, fLon, targetLat, targetLon)-compassReading+360);
    }

  } 
  else {
    // if millis() or timer wraps around, we'll just reset it
    if (startupTimer > millis()) startupTimer = millis();

    // approximately every 10 seconds or so, update time
    if (millis() - startupTimer > 200) {
      startupTimer = millis(); // reset the timer
      if (startLED == 16) {
        startLED = 0;
      }
      strip.setPixelColor(startLEDlast, strip.Color(0, 0, 0));
      strip.setPixelColor(startLED, strip.Color(0, 0, 255));
      strip.show();
      startLEDlast = startLED;
      startLED++;
    }
  }
}

int calc_bearing(float flat1, float flon1, float flat2, float flon2)
{
  float calc;
  float bear_calc;

  float x = 69.1 * (flat2 - flat1); 
  float y = 69.1 * (flon2 - flon1) * cos(flat1/57.3);

  calc=atan2(y,x);

  bear_calc= degrees(calc);

  if(bear_calc<=1){
    bear_calc=360+bear_calc; 
  }
  return bear_calc;
}
void headingDistance(int fDist)
{
  //Use this part of the code to determine how far you are away from the destination.
  //The total trip distance (from where you started) is divided into five trip segments.
  float tripSegment = tripDistance/5;

  if (fDist >= (tripSegment*4)) {
    dirLED_r = 255;
    dirLED_g = 0;
    dirLED_b = 0;
  }

  if ((fDist >= (tripSegment*3))&&(fDist < (tripSegment*4))) {
    dirLED_r = 255;
    dirLED_g = 0;
    dirLED_b = 0;
  }

  if ((fDist >= (tripSegment*2))&&(fDist < (tripSegment*3))) {
    dirLED_r = 255;
    dirLED_g = 255;
    dirLED_b = 0;
  }

  if ((fDist >= tripSegment)&&(fDist < (tripSegment*2))) {
    dirLED_r = 255;
    dirLED_g = 255;
    dirLED_b = 0;
  }

  if ((fDist >= 5)&&(fDist < tripSegment)) {
    dirLED_r = 255;
    dirLED_g = 255;
    dirLED_b = 0;
  }

  if ((fDist < 5)) { // You are now within 5 meters of your destination.
    //Serial.println("Arrived at destination!");
    dirLED_r = 0;
    dirLED_g = 255;
    dirLED_b = 0;
  }
}


unsigned long calc_dist(float flat1, float flon1, float flat2, float flon2)
{
  float dist_calc=0;
  float dist_calc2=0;
  float diflat=0;
  float diflon=0;

  diflat=radians(flat2-flat1);
  flat1=radians(flat1);
  flat2=radians(flat2);
  diflon=radians((flon2)-(flon1));

  dist_calc = (sin(diflat/2.0)*sin(diflat/2.0));
  dist_calc2= cos(flat1);
  dist_calc2*=cos(flat2);
  dist_calc2*=sin(diflon/2.0);
  dist_calc2*=sin(diflon/2.0);
  dist_calc +=dist_calc2;

  dist_calc=(2*atan2(sqrt(dist_calc),sqrt(1.0-dist_calc)));

  dist_calc*=6371000.0; //Converting to meters
  return dist_calc;
}

// Convert NMEA coordinate to decimal degrees
float decimalDegrees(float nmeaCoord, char dir) {
  uint16_t wholeDegrees = 0.01*nmeaCoord;
  int modifier = 1;

  if (dir == 'W' || dir == 'S') {
    modifier = -1;
  }

  return (wholeDegrees + (nmeaCoord - 100.0*wholeDegrees)/60.0) * modifier;
}

void compassMode() {
  dirLED_r = 0;
  dirLED_g = 0;
  dirLED_b = 255;
  compassDirection(compassReading);   
}

void compassCheck() {
  // if millis() or timer wraps around, we'll just reset it
  if (compassTimer > millis()) compassTimer = millis();

  // approximately every 10 seconds or so, update time
  if (millis() - compassTimer > 50) {
    /* Get a new sensor event */
    sensors_event_t event; 
    mag.getEvent(&event);

    float Pi = 3.14159;

    compassTimer = millis(); // reset the timer

    // Calculate the angle of the vector y,x
    float heading = (atan2(event.magnetic.y + magyOffset,event.magnetic.x + magxOffset) * 180) / Pi;

    // Normalize to 0-360
    if (heading < 0)
    {
      heading = 360 + heading;
    }
    compassReading = heading; 
  }  
}  

void compassDirection(int compassHeading) 
{
  //Serial.print("Compass Direction: ");
  //Serial.println(compassHeading);

  unsigned int ledDir = 2;
  int tempDir = 0;
  //Use this part of the code to determine which way you need to go.
  //Remember: this is not the direction you are heading, it is the direction to the destination (north = forward).

  if ((compassHeading > 348.75)||(compassHeading < 11.25)) {
      tempDir = topLED;
  }
  for(int i = 1; i < 16; i++){
    float pieSliceCenter = 45/2*i;
    float pieSliceMin = pieSliceCenter - 11.25;
    float pieSliceMax = pieSliceCenter + 11.25;
    if ((compassHeading >= pieSliceMin)&&(compassHeading < pieSliceMax)) {
      if (mode == 2 ) {
        tempDir = topLED - i;
      } 
      else {
        tempDir = topLED + i;
      }
    }
  }

  if (tempDir > 15) {
    ledDir = tempDir - 16;
  }

  else if (tempDir < 0) {
    ledDir = tempDir + 16;
  } 
  else {
    ledDir = tempDir;
  }

  if (mode == 1) {
    ledDir = ledDir + compassOffset;
    if (ledDir > 15) {
      ledDir = ledDir - 16;
    }
  } 
  else {
    ledDir = ledDir + compassOffset;
    if (ledDir > 15) {
      ledDir = ledDir - 16;
    }
  }

  if (lastDir != ledDir) {
    strip.setPixelColor(lastDir, strip.Color(0, 0, 0));
    strip.setPixelColor(ledDir, strip.Color(dirLED_r, dirLED_g, dirLED_b));
    strip.show();
    lastDir = ledDir;
  }
}

Follow each library’s README file for more information about installing each library.

Follow the FLORA Pixel tutorial for more information about installing the library. Test out the pixel sample code to be sure your pixels are functioning properly.

Next, we need to test out the GPS module. Enter this code into the Arduino IDE and upload to your FLORA with the GPS module attached:

// test a passthru between USB and hardware serial
void setup() {
 while (!Serial);
 Serial.begin(9600);
 Serial1.begin(9600);
}
void loop() {
 if (Serial.available()) {
 char c = Serial.read();
 Serial1.write(c);
 }
 if (Serial1.available()) {
 char c = Serial1.read();
 Serial.write(c);
 }
}

To make sure your GPS has a direct view of the sky, hang your watch out the window (but don’t let it fall out). I used a USB extension cable so I could have the watch out the window but still plugged in to the computer!

Open the Arduino IDE serial monitor. You can access the serial monitor by clicking the magnifying glass icon to the far right of the top toolbar. Make sure the dropdown in the lower right of the serial monitor is set to “9600 baud.” If you see a constant stream of GPS data, your GPS module is correctly installed.

The next step is to test out the compass module. With the LSM303DLHC library (https://github.com/adafruit/Adafruit_LSM303DLHC) installed in your Adafruit Arduino IDE, open up the magsensor example, or manually enter the code below and upload to your FLORA.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
/* Assign a unique ID to this sensor at the same time */
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
void setup(void)
{
 Serial.begin(9600);
 Serial.println("Magnetometer Test"); Serial.println("");
 /* Enable auto-gain */
 mag.enableAutoRange(true);
 /* Initialise the sensor */
 if(!mag.begin())
 {
 /* There was a problem detecting the LSM303 ...
 check your connections */
 Serial.println(
 "Ooops, no LSM303 detected ... Check your wiring!");
 while(1);
 }
}
void loop(void)
{
 /* Get a new sensor event */
 sensors_event_t event;
 mag.getEvent(&event);
 /* Display the results (magnetic vector values are in micro-Tesla (uT))
*/
 Serial.print("X: "); Serial.print(event.magnetic.x);
 Serial.print(" ");
 Serial.print("Y: "); Serial.print(event.magnetic.y);
 Serial.print(" ");
 Serial.print("Z: "); Serial.print(event.magnetic.z);
 Serial.print(" ");Serial.println("uT");
 delay(500);
}

Again, open the serial monitor and make sure you don’t get the “Ooops, no LSM303 detected … Check your wiring!” warning. You should see the X, Y, and Z values change as you move your NeoGeo watch around.

Now that you have confirmed all of the sensors are working, it is time to modify the main NeoGeo watch sketch. Find this part of the code near the top of the sketch:

//--------------------------------------------------|
//                    WAYPOINT                      |
//--------------------------------------------------|
//Please enter the latitude and longitude of your   |
//desired destination:                              |
  #define GEO_LAT                44.998531
  #define GEO_LON               -93.230322
//--------------------------------------------------|
//Your NeoPixel ring may not line up with ours.     |
//Enter which NeoPixel led is your top LED (0-15).  |
  #define TOP_LED                1
//--------------------------------------------------|
//Your compass module may not line up with ours.    |
//Once you run compass mode, compare to a separate  |
//compass (like one found on your smartphone).      |
//Point your TOP_LED north, then count clockwise    |
//how many LEDs away from TOP_LED the lit LED is    |
  #define LED_OFFSET             0
//--------------------------------------------------|

We like getLatLong.net for finding latitudes and longitudes online. Dump in a location, such as your home, so you will always be able to find your way home.

We also know that your NeoPixel Ring and compass sensor won't line up perfectly with our design (even our two prototypes didn't line up exactly). So, we made it easy for you to calibrate your watch. The first thing you want to do is calibrate your NeoPixel Ring. This is as simple as lighting up each pixel using the NeoPixel code and determining which pixel is your top pixel (from 0-15). In the code, it is set to pixel 1.

Next, you need to make sure your watch knows which way north is. This is really easy to do. When your watch is on, hold down the button until you get to mode 3, which is the compass mode. Then, using a compass on your smartphone, or the old fashioned kind, point your TOP_LED north. Count clockwise how many pixels away the lit LED is away from the TOP_LED. So, if you aim your TOP_LED north, and the LED 4 spots over (counting clockwise) is lit up, you would change the 0 in the LED_OFFSET code above and replace it with 4.

That's it, you should be ready to upload the code to your FLORA, and start using your NeoGeo Watch!

Plug in a tiny lipoly battery and tuck it into the cuff! Although you can place it directly behind the circuit, we liked it better tucked into one of the "side pockets" where the cuff overlaps the strap. A piece of gaffer tape holds the battery nicely to the strap, where it can be protected by the cuff.
FLORA's onboard power switch should still be accessible, hidden under the part of the watch closest to you. If you don't have nails, use a toothpick or other pointy nonconductive object to flip the switch!
The watch fetches the time of day from GPS satellites, so when it first powers on it needs to get a GPS fix by directly seeing the sky. Set it on your windowsill or go for a walk in the sunshine so your watch knows what time it is! It can take several minutes to first acquire a GPS fix, but only needs to do this once on power up. You can attach an optional backup battery to the GPS to keep its fix between battery charges, and tuck it in the opposite "side pocket" of the cuff or right behind the face.
Once the GPS gets a fix, the watch will display the current time, with one pixel color for the hours "hand" and another for minutes.
Press and hold near the top of the watch face to engage the tactile switch for a few seconds to change modes. Compass mode lights up blue in the direction of north.
GPS navigation mode points towards the coordinates you configure in the Arduino sketch, and grows redder the closer you get to your destination.
This watch is not waterproof! Take it off and power it down if you get stuck in the rain. Don't wear it while doing the dishes, etc.

Enjoy your new geo watch!

This guide was first published on Sep 25, 2013. It was last updated on Sep 25, 2013.