Sleepy Snail-Mail Concierge
Monitor your mailbox, indicate when you have physical mail. Extensive use of Power Down Sleep mode extends battery life to about 40 days
Components and supplies
1
Arduino Nano
1
Resistor 100k ohm
2
5 mm LED: Red
1
Perf Board, 2.5 x 3.5 inches
3
Resistor 1M ohm
1
Battery Holder, 18650 x 2
1
LED Flip Light for LEDs and reflector
1
Photo resistor
1
Buck Converter Module, adjustable, LM2596 Based
1
Phototransistor BPW85B
1
Mailbox, black plastic
Tools and machines
1
Solder Wire, Lead Free
1
Soldering iron (generic)
Project description
Code
Mailbox Monitor Code
arduino
Code for Mailbox Monitoring system
1#include <LowPower.h>// Library for sleep routines 2#include <stdio.h> 3 4int sensePin = A0; // Photo Resistor Sensor Pin 5int lightPin = 2; // LED Illuminator Control Pin 6int doorPin = 3; // Photo Transistor Door Interrupt Pin 7int ledPin = 13; // Status LED Pin 8int voltPin = A7; // Battery Voltage Sense Pin 9 10long lastCheckMillis = 0; // time of last mail check in millis 11long testTimeout; // In test mode, returns to normal mode when millis() exceeds this value 12const bool ON = LOW; // For controlling Illuminator LEDs 13const bool OFF = HIGH;// For controlling Illuminator LEDs 14volatile bool boxWasOpened = false;// Set to true when mailbox needs checked for mail 15 16int testMode = 0;// Select from mormal run mode (0 value) or a test mode (1 = voltage, 2 = Light sensor, illuminator off, 3 = Light sensor, Illuminator on) 17bool mailInBox = false; // set to true if mail is detected in box 18 19 20void setup() { 21 // initialize digital pin LED_BUILTIN as an output. 22 pinMode(LED_BUILTIN, OUTPUT); 23 pinMode(lightPin, OUTPUT); 24 pinMode(doorPin, INPUT); 25 digitalWrite(lightPin, ON); 26 attachInterrupt(digitalPinToInterrupt(doorPin), doorInterrupt, FALLING); // Interrupt for door sensing 27 28 Serial.begin(115200); 29 Light(OFF); // Start with illuminator off 30} 31void doorInterrupt(void) { 32 boxWasOpened = true;// Ready for mail checking next time through main loop 33 mailInBox = false; 34} 35 36int readAverage(int myPin) { // Read an average value on any analog pin, 10 iterations 37 int i = 0; 38 int iterations = 10; 39 long readVals = 0; 40 for (i = 1; i <= iterations; i++) 41 { 42 readVals += analogRead(myPin); 43 } 44 return (readVals / iterations); 45} 46 47void Light(bool myStatus) { // Control Illuminator LEDs 48 digitalWrite(lightPin, myStatus); 49} 50 51void LED(bool myStatus) { // Control Status LEDs 52 digitalWrite(ledPin, !myStatus); 53} 54 55bool CheckMail(bool haveMail) { // Check for mail in mailbox after door close interrupt 56 long senseVal; // Photo Transistor value read 57 bool retVal = false ; // Return value for function 58 Light(ON); 59 delay(300); // Allow time for illuminator to stabilize 60 lastCheckMillis = millis(); 61 62 senseVal = readAverage(sensePin); 63 Serial.println(senseVal); 64 if (senseVal >= 35) { // Mail detected at this light level 65 retVal = true; 66 } 67 Light(OFF); 68 Serial.println(retVal); 69 return retVal; 70} 71 72void wakeUp() 73{ 74 // Just a handler for the pin interrupt. 75} 76 77 78 79int testCheck(void) { // check for and initiate test modes 80 81 if ((digitalRead(doorPin) == HIGH) && readAverage(sensePin) < 100) { 82 delay(1000); // Only enter test mode if Photoresistor is blocked, door is opened 83 84 if ((digitalRead(doorPin) == HIGH) && readAverage(sensePin) < 100) { 85 testMode ++; // Increment test mode when command received 86 if (testMode > 3) { 87 testMode = 0; 88 Light(OFF); 89 boxWasOpened = true; 90 } 91 Serial.print("Test mode = "); 92 Serial.println(testMode); 93 for (int x = 1; x < 11; x++) { // Indicate test mode selected on the status LEDs before starting test display 94 flashFast(testMode); 95 delay (500); 96 97 } 98 testTimeout = millis() + 60000; //exit test mode after 60 seconds 99 delay(1000); 100 101 } 102 else { 103 104 } 105 } 106} 107 108void sleepNow() { // Sleep mode used for NO mail present 109 110 if ((digitalRead(doorPin) == LOW) && analogRead(sensePin) <= 25) { // OK for sleep mode 111 112 113 attachInterrupt(0, wakeUp, LOW); //set wakeup interrupt 114 Serial.println("Going to sleep now."); 115 delay(200); 116 LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // Set sleep mode NO timeout 117 // Disable external pin interrupt on wake up pin. 118 119 detachInterrupt(0); 120 Serial.println("Now I'm up!"); 121 } 122 else { 123 Serial.println("Not tired yet"); 124 } 125} 126void sleep2() { // Sleep mode used for mail IS present 127 attachInterrupt(0, wakeUp, LOW); 128 Serial.println("Going into sleep2 now."); 129 delay(200); 130 LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); // Set sleep mode with 2 second timeout 131 // Disable external pin interrupt on wake up pin. 132 133 detachInterrupt(0); 134 Serial.println("NOw I'm up!"); 135 136} 137 138void flash(int iterations) { // Flash status LEDs number of times requested in <iterations> 139 for (int x = 1; x <= iterations; x++ ) { 140 141 //digitalWrite(ledPin, HIGH); 142 LED(ON); 143 delay(150); 144 //digitalWrite(ledPin, LOW); 145 LED(OFF); 146 delay(200); 147 } 148} 149 150void flashFast(int iterations) { // double Speed Flash status LEDs number of times requested in <iterations> 151 for (int x = 1; x <= iterations; x++ ) { 152 153 LED(ON); 154 delay(150); 155 LED(OFF); 156 delay(100); 157 } 158} 159 160void showSenseRead(int myVall) { // Display Sensor reading on status LEDs 161 int intDigit; 162 String myChar; 163 char valStr[5]; 164 165 sprintf(valStr, "%d", myVall);// Convert reading to a character string 166 Serial.print("Sensor Value "); 167 Serial.println(valStr); 168 169 if (myVall == 0) {// Quickly flash 15 time if reading is zero 170 flashFast(15); 171 } 172 else if ((myVall > 0) && (myVall < 10)) { 173 flash(myVall); 174 delay(300); 175 } 176 else if (myVall > 9 && myVall < 100) { 177 int xVal; 178 xVal = myVall / 10; 179 flash(xVal); 180 delay(300); 181 xVal = myVall % 10; 182 flash(xVal); 183 delay (300); 184 } 185 else if (myVall > 99 && myVall < 1000) { 186 int xVal; 187 xVal = myVall / 100; 188 flash(xVal); 189 delay(300); 190 xVal = (myVall - xVal * 100) / 10; 191 flash(xVal); 192 delay(300); 193 xVal = myVall % 10; 194 flash(xVal); 195 delay (300); 196 } 197} 198 199void showVolts(float myVolts) {// Display battery voltage on status LEDs 200 int intDigit; 201 if (myVolts == 0.00) {// Send 0 to force voltage reading 202 myVolts = readVolts(); 203 } 204 myVolts *= 1.00; 205 String myChar; 206 char voltStr[6]; 207 208 dtostrf(myVolts, 4, 2, voltStr);// Convert voltage to a character string 209 210 Serial.print("ShowVolts VOltage "); 211 Serial.println(voltStr); 212 // delay(10); 213 dtostrf(myVolts, 4, 2, voltStr);// Convert voltage to a character string 214 myChar = voltStr[0]; 215 216 intDigit = String(myChar).toInt(); 217 // Serial.print("Corrent Digit "); 218 //Serial.println(intDigit); 219 flash(intDigit); 220 delay(300); 221 222 myChar = voltStr[2]; 223 224 intDigit = String(myChar).toInt(); 225 226 //Serial.print("Corrent Digit "); 227 //Serial.println(intDigit); 228 229 if (intDigit > 0 ) { 230 flash(intDigit); 231 delay( 300); 232 } 233 else { 234 delay(400); 235 } 236 // my 237 myChar = voltStr[3]; 238 239 intDigit = String(myChar).toInt(); 240 241 //Serial.print("Corrent Digit "); 242 // Serial.println(intDigit); 243 244 if (intDigit > 0 ) { 245 flash(intDigit); 246 delay( 300); 247 } 248 else { 249 delay(400); 250 } 251 252} 253 254float readVolts(void) {// Get current battery voltage and return it 255 float myRead; 256 float myVolts; 257 myRead = float(readAverage(voltPin)); 258 float myConv = 4.63 / 1023.00; 259 myVolts = (myRead * 2 * myConv * 1.0811); 260 Serial.println(myVolts); 261 return (myVolts); 262} 263void loop() { 264 static bool lowVolts = false; 265 float curVolts; 266 curVolts = readVolts(); 267 if (curVolts <= 6.5) { 268 lowVolts = true; // If battery is running low, LEDs will flasw 3 times, not one for mail indication 269 270 } 271 testCheck(); // Check for test mode request 272 if ((millis() > testTimeout) && testMode > 0) {// Return to normal mode after 1 minute of test mode 273 testMode = 0; 274 Light(OFF); 275 boxWasOpened = true;// want to ensure check 276 } 277 if (testMode == 0) {// Normal mail display mode 278 279 if (digitalRead(doorPin) == HIGH) {// Stop mail indication when door is opened 280 digitalWrite(ledPin, LOW); 281 mailInBox = false;// will be set to true once door is closed 282 } 283 if (readAverage(sensePin >= 25)) {// Can be due to EITHER door being opened 284 285 boxWasOpened = true; 286 while (readAverage(sensePin) >= 25) { 287 //do nothing until door is closed again 288 } 289 290 } 291 if (boxWasOpened && digitalRead(doorPin) == LOW) { 292 delay(200); 293 if (boxWasOpened && digitalRead(doorPin) == LOW) { 294 //delay(2000); 295 mailInBox = CheckMail(mailInBox);// Actual mail check 296 boxWasOpened = false; 297 } 298 299 } 300 301 Serial.println(); 302 Serial.println(mailInBox); 303 Serial.println(); 304 if (mailInBox == true) {// Mail Present in Box 305 LED(ON); 306 Serial.println("LED ON"); 307 delay(100); 308 LED(OFF); 309 310 if (lowVolts) {// Blink 3 times instead of one for low voltage 311 delay(200); 312 LED(ON); 313 delay(100); 314 LED(OFF); 315 delay(200); 316 LED(ON); 317 delay(100); 318 LED(OFF); 319 320 321 322 } 323 324 Serial.println(readAverage(sensePin)); 325 //delay(2350); 326 sleep2(); 327 328 } 329 else { 330 LED(OFF); 331 332 delay(200); 333 sleepNow();// No mail, go to hard sleep 334 } 335 } 336 else if (testMode == 1) { // Test mode 1 display 337 // curVolts = readVolts(); 338 int myVall; 339 myVall = readAverage(sensePin); 340 341 showVolts(curVolts); 342 //flash(5); 343 delay (2000); 344 } 345 346 else if (testMode > 1) { // Test modes 2, 3 display 347 Light (testMode == 2);// light on if testmode is 3 348 int myVall; 349 myVall = readAverage(sensePin); 350 Serial.print("Light Value "); 351 Serial.println(myVall); 352 showSenseRead(myVall); 353 delay(2000); 354 } 355}
Mailbox Monitor Code
arduino
Code for Mailbox Monitoring system
1#include <LowPower.h>// Library for sleep routines 2#include <stdio.h> 3 4int sensePin = A0; // Photo Resistor Sensor Pin 5int lightPin = 2; // LED Illuminator Control Pin 6int doorPin = 3; // Photo Transistor Door Interrupt Pin 7int ledPin = 13; // Status LED Pin 8int voltPin = A7; // Battery Voltage Sense Pin 9 10long lastCheckMillis = 0; // time of last mail check in millis 11long testTimeout; // In test mode, returns to normal mode when millis() exceeds this value 12const bool ON = LOW; // For controlling Illuminator LEDs 13const bool OFF = HIGH;// For controlling Illuminator LEDs 14volatile bool boxWasOpened = false;// Set to true when mailbox needs checked for mail 15 16int testMode = 0;// Select from mormal run mode (0 value) or a test mode (1 = voltage, 2 = Light sensor, illuminator off, 3 = Light sensor, Illuminator on) 17bool mailInBox = false; // set to true if mail is detected in box 18 19 20void setup() { 21 // initialize digital pin LED_BUILTIN as an output. 22 pinMode(LED_BUILTIN, OUTPUT); 23 pinMode(lightPin, OUTPUT); 24 pinMode(doorPin, INPUT); 25 digitalWrite(lightPin, ON); 26 attachInterrupt(digitalPinToInterrupt(doorPin), doorInterrupt, FALLING); // Interrupt for door sensing 27 28 Serial.begin(115200); 29 Light(OFF); // Start with illuminator off 30} 31void doorInterrupt(void) { 32 boxWasOpened = true;// Ready for mail checking next time through main loop 33 mailInBox = false; 34} 35 36int readAverage(int myPin) { // Read an average value on any analog pin, 10 iterations 37 int i = 0; 38 int iterations = 10; 39 long readVals = 0; 40 for (i = 1; i <= iterations; i++) 41 { 42 readVals += analogRead(myPin); 43 } 44 return (readVals / iterations); 45} 46 47void Light(bool myStatus) { // Control Illuminator LEDs 48 digitalWrite(lightPin, myStatus); 49} 50 51void LED(bool myStatus) { // Control Status LEDs 52 digitalWrite(ledPin, !myStatus); 53} 54 55bool CheckMail(bool haveMail) { // Check for mail in mailbox after door close interrupt 56 long senseVal; // Photo Transistor value read 57 bool retVal = false ; // Return value for function 58 Light(ON); 59 delay(300); // Allow time for illuminator to stabilize 60 lastCheckMillis = millis(); 61 62 senseVal = readAverage(sensePin); 63 Serial.println(senseVal); 64 if (senseVal >= 35) { // Mail detected at this light level 65 retVal = true; 66 } 67 Light(OFF); 68 Serial.println(retVal); 69 return retVal; 70} 71 72void wakeUp() 73{ 74 // Just a handler for the pin interrupt. 75} 76 77 78 79int testCheck(void) { // check for and initiate test modes 80 81 if ((digitalRead(doorPin) == HIGH) && readAverage(sensePin) < 100) { 82 delay(1000); // Only enter test mode if Photoresistor is blocked, door is opened 83 84 if ((digitalRead(doorPin) == HIGH) && readAverage(sensePin) < 100) { 85 testMode ++; // Increment test mode when command received 86 if (testMode > 3) { 87 testMode = 0; 88 Light(OFF); 89 boxWasOpened = true; 90 } 91 Serial.print("Test mode = "); 92 Serial.println(testMode); 93 for (int x = 1; x < 11; x++) { // Indicate test mode selected on the status LEDs before starting test display 94 flashFast(testMode); 95 delay (500); 96 97 } 98 testTimeout = millis() + 60000; //exit test mode after 60 seconds 99 delay(1000); 100 101 } 102 else { 103 104 } 105 } 106} 107 108void sleepNow() { // Sleep mode used for NO mail present 109 110 if ((digitalRead(doorPin) == LOW) && analogRead(sensePin) <= 25) { // OK for sleep mode 111 112 113 attachInterrupt(0, wakeUp, LOW); //set wakeup interrupt 114 Serial.println("Going to sleep now."); 115 delay(200); 116 LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // Set sleep mode NO timeout 117 // Disable external pin interrupt on wake up pin. 118 119 detachInterrupt(0); 120 Serial.println("Now I'm up!"); 121 } 122 else { 123 Serial.println("Not tired yet"); 124 } 125} 126void sleep2() { // Sleep mode used for mail IS present 127 attachInterrupt(0, wakeUp, LOW); 128 Serial.println("Going into sleep2 now."); 129 delay(200); 130 LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); // Set sleep mode with 2 second timeout 131 // Disable external pin interrupt on wake up pin. 132 133 detachInterrupt(0); 134 Serial.println("NOw I'm up!"); 135 136} 137 138void flash(int iterations) { // Flash status LEDs number of times requested in <iterations> 139 for (int x = 1; x <= iterations; x++ ) { 140 141 //digitalWrite(ledPin, HIGH); 142 LED(ON); 143 delay(150); 144 //digitalWrite(ledPin, LOW); 145 LED(OFF); 146 delay(200); 147 } 148} 149 150void flashFast(int iterations) { // double Speed Flash status LEDs number of times requested in <iterations> 151 for (int x = 1; x <= iterations; x++ ) { 152 153 LED(ON); 154 delay(150); 155 LED(OFF); 156 delay(100); 157 } 158} 159 160void showSenseRead(int myVall) { // Display Sensor reading on status LEDs 161 int intDigit; 162 String myChar; 163 char valStr[5]; 164 165 sprintf(valStr, "%d", myVall);// Convert reading to a character string 166 Serial.print("Sensor Value "); 167 Serial.println(valStr); 168 169 if (myVall == 0) {// Quickly flash 15 time if reading is zero 170 flashFast(15); 171 } 172 else if ((myVall > 0) && (myVall < 10)) { 173 flash(myVall); 174 delay(300); 175 } 176 else if (myVall > 9 && myVall < 100) { 177 int xVal; 178 xVal = myVall / 10; 179 flash(xVal); 180 delay(300); 181 xVal = myVall % 10; 182 flash(xVal); 183 delay (300); 184 } 185 else if (myVall > 99 && myVall < 1000) { 186 int xVal; 187 xVal = myVall / 100; 188 flash(xVal); 189 delay(300); 190 xVal = (myVall - xVal * 100) / 10; 191 flash(xVal); 192 delay(300); 193 xVal = myVall % 10; 194 flash(xVal); 195 delay (300); 196 } 197} 198 199void showVolts(float myVolts) {// Display battery voltage on status LEDs 200 int intDigit; 201 if (myVolts == 0.00) {// Send 0 to force voltage reading 202 myVolts = readVolts(); 203 } 204 myVolts *= 1.00; 205 String myChar; 206 char voltStr[6]; 207 208 dtostrf(myVolts, 4, 2, voltStr);// Convert voltage to a character string 209 210 Serial.print("ShowVolts VOltage "); 211 Serial.println(voltStr); 212 // delay(10); 213 dtostrf(myVolts, 4, 2, voltStr);// Convert voltage to a character string 214 myChar = voltStr[0]; 215 216 intDigit = String(myChar).toInt(); 217 // Serial.print("Corrent Digit "); 218 //Serial.println(intDigit); 219 flash(intDigit); 220 delay(300); 221 222 myChar = voltStr[2]; 223 224 intDigit = String(myChar).toInt(); 225 226 //Serial.print("Corrent Digit "); 227 //Serial.println(intDigit); 228 229 if (intDigit > 0 ) { 230 flash(intDigit); 231 delay( 300); 232 } 233 else { 234 delay(400); 235 } 236 // my 237 myChar = voltStr[3]; 238 239 intDigit = String(myChar).toInt(); 240 241 //Serial.print("Corrent Digit "); 242 // Serial.println(intDigit); 243 244 if (intDigit > 0 ) { 245 flash(intDigit); 246 delay( 300); 247 } 248 else { 249 delay(400); 250 } 251 252} 253 254float readVolts(void) {// Get current battery voltage and return it 255 float myRead; 256 float myVolts; 257 myRead = float(readAverage(voltPin)); 258 float myConv = 4.63 / 1023.00; 259 myVolts = (myRead * 2 * myConv * 1.0811); 260 Serial.println(myVolts); 261 return (myVolts); 262} 263void loop() { 264 static bool lowVolts = false; 265 float curVolts; 266 curVolts = readVolts(); 267 if (curVolts <= 6.5) { 268 lowVolts = true; // If battery is running low, LEDs will flasw 3 times, not one for mail indication 269 270 } 271 testCheck(); // Check for test mode request 272 if ((millis() > testTimeout) && testMode > 0) {// Return to normal mode after 1 minute of test mode 273 testMode = 0; 274 Light(OFF); 275 boxWasOpened = true;// want to ensure check 276 } 277 if (testMode == 0) {// Normal mail display mode 278 279 if (digitalRead(doorPin) == HIGH) {// Stop mail indication when door is opened 280 digitalWrite(ledPin, LOW); 281 mailInBox = false;// will be set to true once door is closed 282 } 283 if (readAverage(sensePin >= 25)) {// Can be due to EITHER door being opened 284 285 boxWasOpened = true; 286 while (readAverage(sensePin) >= 25) { 287 //do nothing until door is closed again 288 } 289 290 } 291 if (boxWasOpened && digitalRead(doorPin) == LOW) { 292 delay(200); 293 if (boxWasOpened && digitalRead(doorPin) == LOW) { 294 //delay(2000); 295 mailInBox = CheckMail(mailInBox);// Actual mail check 296 boxWasOpened = false; 297 } 298 299 } 300 301 Serial.println(); 302 Serial.println(mailInBox); 303 Serial.println(); 304 if (mailInBox == true) {// Mail Present in Box 305 LED(ON); 306 Serial.println("LED ON"); 307 delay(100); 308 LED(OFF); 309 310 if (lowVolts) {// Blink 3 times instead of one for low voltage 311 delay(200); 312 LED(ON); 313 delay(100); 314 LED(OFF); 315 delay(200); 316 LED(ON); 317 delay(100); 318 LED(OFF); 319 320 321 322 } 323 324 Serial.println(readAverage(sensePin)); 325 //delay(2350); 326 sleep2(); 327 328 } 329 else { 330 LED(OFF); 331 332 delay(200); 333 sleepNow();// No mail, go to hard sleep 334 } 335 } 336 else if (testMode == 1) { // Test mode 1 display 337 // curVolts = readVolts(); 338 int myVall; 339 myVall = readAverage(sensePin); 340 341 showVolts(curVolts); 342 //flash(5); 343 delay (2000); 344 } 345 346 else if (testMode > 1) { // Test modes 2, 3 display 347 Light (testMode == 2);// light on if testmode is 3 348 int myVall; 349 myVall = readAverage(sensePin); 350 Serial.print("Light Value "); 351 Serial.println(myVall); 352 showSenseRead(myVall); 353 delay(2000); 354 } 355}
Downloadable files
Schematic
Schematic
Comments
Only logged in users can leave comments