Introduction: GEOFF - Never Forget Your Keys Again

Yes, it’s finally here. A device that even you can make it yourself to let you never leave keys at home. Doesn’t need any skill in programming (‘cause I have already prepared it for you ;) and just requires access to your home WiFi before use.

Step 1: Prepare What You Need

Here are the things you should order before we start DIY. Remember all of these links are what I bought for this project but all of them can be replaced by similar products sold by other manufactures but some functions and designs may vary.

- A reed switch to monitor the status of your home door.

- A distance sensor to monitor the status of your key (whether you place them on the device). It also requires a capacitor that is more than 10uF to stabilize the signal.

- An Arduino Uno board and A sound board for Arduino Uno. To play some sound, of course.

- Two Arduino Boards that supports WiFI connections, here I used Adafruit Feather HUZZAH. One for door sensor, one for the major functions.

- Some jump wires and an LED (optional).

Step 2: Reed Switch

First let's look at the Feather board. Beware of your settings in the Arduino IDE, since you may check if you have the ESP8266 library installed. Make sure you switch to the right board selection when operating in the IDE. Here is the guide you may want check out.

Above on the right side you can find which pins are which. For the door sensor, simply connect one pin of reed switch to pin 13 (the purple one) and another one to the GND (ground). Then link pin 16 to RST to enable the wake function.

Then is the code part, and simply down load these files and put them in a same folder that named after the .ino file

Hang on, don't sync it to the board yet. We have something to do in the next step.

Step 3: All About IO

Create an account on and it's time to set the IO.

First in the Feed page, you may want to add two need feeds that are named "command" and "door". The "battery" feed shown here is to monitor the battery level, but since we don't use a battery in this project, simply ignore it here.

Then turn to the Trigger page to create a new trigger. When the feed "door" equals to 1, send a message to the feed "command" which is valued as 1. This is how we tell the other board when the door is opened.

Then turn to the AIO Key page to get your account information, which you will need in the IDE sketch for the board of reed switch (in config.h). Also you need to input your WiFI information too, in the same file.

It's all! Now you can upload the sketch to the board and it will starts to work. Every 3 seconds it will detect if the door is opened, and when it is opened it will send a feed to "door" which value is one, and the trigger will immediately add a value "1" to the feed "command", which will be used in the other board we are going to introduce in the next step.

Step 4: The Body

Assemble your sound board and stack it on the Uno before we start. You may find how to assemble it in the product information page where you ordered it. Remember you don't really need to connect it to a speaker that comes with the board, and you can actually use any of your speakers that supports 3.5 mm jack.

We need to connect the Digital pin 6 to the pin 5 on the Feather board. And you may want to connect the 5V and GND to the 3V and GND pins on the Feather too if you want use just one power cable. (Don't reverse the connection because it may cause some failure in other parts that requires high voltage) That's everything about the sound board.

On the feather board, there are more connections. Connect the + end of LED to pin 4 and - end to ground. And connect the VIN pin, GND pin and OUT pin of the distance sensor to the power, ground and pin 17, which is the only analog pin on the Feather board. Connect a capacitor which is more than 10uF between the power and ground which connects to the sensor.

Then open the Arduino IDE. First, follow this instruction to install the library to support the sound board Then create a new sketch and copy the codes below into it.

* This example plays every .WAV file it finds on the SD card in a loop */ #include #include

#define COM_PIN 6

SdReader card; // This object holds the information for the card FatVolume vol; // This holds the information for the partition on the card FatReader root; // This holds the information for the volumes root directory WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time

uint8_t dirLevel; // indent level for file/dir names (for prettyprinting) dir_t dirBuf; // buffer for directory reads

/* * Define macro to put error messages in flash memory */ #define error(msg) error_P(PSTR(msg))

// Function definitions (we define them here, but the code is below) void play(FatReader &dir);

//////////////////////////////////// SETUP void setup() { pinMode(COM_PIN, INPUT);

Serial.begin(9600); // set up Serial library at 9600 bps for debugging putstring_nl("\nWave test!"); // say we woke up! putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad Serial.println(FreeRam());

// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you if (!card.init()) { //play with 8 MHz spi (default faster!) error("Card init. failed!"); // Something went wrong, lets print out why } // enable optimize read - some cards may timeout. Disable if you're having problems card.partialBlockRead(true); // Now we will look for a FAT partition! uint8_t part; for (part = 0; part < 5; part++) { // we have up to 5 slots to look in if (vol.init(card, part)) break; // we found one, lets bail } if (part == 5) { // if we ended up not finding one :( error("No valid FAT partition!"); // Something went wrong, lets print out why } // Lets tell the user about what we found putstring("Using partition "); Serial.print(part, DEC); putstring(", type is FAT"); Serial.println(vol.fatType(), DEC); // FAT16 or FAT32? // Try to open the root directory if (!root.openRoot(vol)) { error("Can't open root dir!"); // Something went wrong, } // Whew! We got past the tough parts. putstring_nl("Files found (* = fragmented):");

// Print out all of the files in all the directories. | LS_FLAG_FRAGMENTED); }

//////////////////////////////////// LOOP void loop() { root.rewind(); if (digitalRead(COM_PIN) == HIGH) { play(root); } else { delay(1000); } }

/////////////////////////////////// HELPERS /* * print error message and halt */ void error_P(const char *str) { PgmPrint("Error: "); SerialPrint_P(str); sdErrorCheck(); while(1); } /* * print error message and halt if SD I/O error, great for debugging! */ void sdErrorCheck(void) { if (!card.errorCode()) return; PgmPrint("\r\nSD I/O error: "); Serial.print(card.errorCode(), HEX); PgmPrint(", "); Serial.println(card.errorData(), HEX); while(1); } /* * play recursively - possible stack overflow if subdirectories too nested */ void play(FatReader &dir) { FatReader file; while (dir.readDir(dirBuf) > 0) { // Read every file in the directory one at a time // Skip it if not a subdirectory and not a .WAV file if (!DIR_IS_SUBDIR(dirBuf) && strncmp_P((char *)&[8], PSTR("WAV"), 3)) { continue; }

Serial.println(); // clear out a new line for (uint8_t i = 0; i < dirLevel; i++) { Serial.write(' '); // this is for prettyprinting, put spaces in front } if (!, dirBuf)) { // open the file in the directory error(" failed"); // something went wrong } if (file.isDir()) { // check if we opened a new directory putstring("Subdir: "); printEntryName(dirBuf); Serial.println(); dirLevel += 2; // add more spaces // play files in subdirectory play(file); // recursive! dirLevel -= 2; } else { // Aha! we found a file that isnt a directory putstring("Playing "); printEntryName(dirBuf); // print it out if (!wave.create(file)) { // Figure out, is it a WAV proper? putstring(" Not a valid WAV"); // ok skip it } else { Serial.println(); // Hooray it IS a WAV proper!; // make some noise! uint8_t n = 0; while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime putstring("."); if (!(++n % 32))Serial.println(); delay(100); } sdErrorCheck(); // everything OK? // if (wave.errors)Serial.println(wave.errors); // wave decoding errors } } } }

Then it's the code for the feather board. Beware that the settings in IDE for the two boards are different. Follow the warning information if it is shown in the software. And remember to replace the IO and WiFi information.

// visit if you need to create an account,
// or if you need your Adafruit IO key. #define IO_USERNAME "yourwifi" #define IO_KEY "yourkey"

/******************************* WIFI Configuration **************************************/

#define WIFI_SSID "youraccount" #define WIFI_PASS "yourkey"

#include "AdafruitIO_WiFi.h" AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);

/************************ Main Program Starts Here *******************************/ #include #include #include #include

#define LED_PIN 4 #define COM_PIN 5

AdafruitIO_Feed *command = io.feed("command");

void setup() {



// connect to Serial.print("Connecting to Adafruit IO"); io.connect(); // set up a message handler for the 'command' feed. // the handleMessage function (defined below) // will be called whenever a message is // received from adafruit io. command->onMessage(handleMessage);

// wait for a connection while(io.status() < AIO_CONNECTED) { Serial.print("."); delay(500); }

// we are connected Serial.println(); Serial.println(io.statusText());


void loop() {

//; is required for all sketches. // it should always be present at the top of your loop // function. it keeps the client connected to //, and processes any incoming data.;

// read the input on analog pin 0: int sensorValue = analogRead(A0); // print out the value you read: Serial.print("distance <- "); Serial.println(sensorValue); delay(1000); // delay in between reads for stability


// this function is called whenever a 'command' message // is received from Adafruit IO. it was attached to // the command feed in the setup() function above. void handleMessage(AdafruitIO_Data *data) {

int command = data->toInt(); int distanceValue = analogRead(A0);

if (command == 1){ //light up the LED Serial.print("received <- "); Serial.println(command); if (distanceValue < 1000) { digitalWrite(COM_PIN, HIGH); delay(2000); digitalWrite(COM_PIN, LOW); } else { digitalWrite(COM_PIN, LOW); delay(3000); digitalWrite(COM_PIN, HIGH); delay(2000); digitalWrite(COM_PIN, LOW); } digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); } else { Serial.print("received <- "); Serial.println(command); } }

Step 5: Finish It

Make a fancy box for it! Remember to place a hole above the sensor.

Then, fix the reed sensor on your door and plug both boards to power, and you are good to go.