Components and supplies
Antenna, GPS
Resistor 220 ohm
SIM900 development board
Arduino Leonardo
NEO-6M GPS module
LED (generic)
12V to 5V step down module
Adafruit SD card reader
Solder board 7 x 5cm
Flash Memory Card, MicroSD Card
Tools and machines
Soldering iron (generic)
Apps and platforms
Thinger.io Platform
Project description
Code
GPS_tracker_Leonardo_v2.ino
arduino
1#include <SoftwareSerial.h> 2#include <NMEAGPS.h> 3#include <GPSport.h> 4#include <TimeLib.h> 5#include "PF.h" 6#include "PetitSerial.h" 7 8#define UTC_OFFSET 1 // set time zone offset, i.e. 1 = UTC+1 9#define TXPin 8 // SIM900 Tx pin 10#define RXPin 9 // SIM900 Rx pin 11#define PWRPin 7 // SIM900 software power pin 12 13// phone number for triggered notification 14#define DEFAULT_NUMBER "+4712345678" 15 16FATFS fs; // file system object - for reading SD card 17 18// GSM variables 19String textMessage; // holds the last received text message 20String number = DEFAULT_NUMBER; // phone number from last text message 21char sms_msg[160]; // holds the SMS reply text 22 23// location variables 24float Lat = 0, Long = 0; 25boolean valid_location = false; // initial valid location flag 26uint8_t num_sat; 27NeoGPS::Location_t prevFix; // holds previous location for distance calculation 28NMEAGPS gps; // parses the GPS characters 29gps_fix fix; // holds on to the latest values 30 31const char *googlePrefix = "http://maps.google.com/maps?q="; 32const char *filename = "DIST.TXT"; 33const char *settings = "SETTINGS.TXT"; 34 35// time variables 36NeoGPS::time_t timeFix; // time object for current gps fix 37char datePrint[13]; 38char timePrint[10]; 39 40// distance tracking variables 41float totalDistance = 0; // in meters 42// triggerdistance (odometer notification) is read from SD card on init 43float triggerDistance = 4000000; 44 45SoftwareSerial SIM900( TXPin, RXPin ); // SIM900 Tx & Rx is connected to Arduino #8 & #9 46 47void setup() { 48 49 pinMode(3, OUTPUT); 50 pinMode(4, OUTPUT); 51 digitalWrite(3, HIGH); // turn on power LED 52 53 Serial.begin(9600); // serial monitor 54 55 /* the "while (!serial)" construct below must only be enabled for 56 debugging purposes when connected to a PC. If this is kept in the 57 code the program will stop in a loop when connected to external 58 power sources, as no serial connection will be established 59 */ 60 61 // while (!Serial); // wait for serial port to connect - for ATmega32u4 (Leonardo) 62 63 SIM900.begin(9600); // SIM900 module on pins #8 and #9 64 gpsPort.begin(9600); // GPS receiver on Serial1 pins #0 and #1 - defined in GPSport.h 65 66 // initialize the SD card and reads standard setting and accumulated distance 67 initializeSD(); 68 69 // power up SIM900 with software trigger 70 SIM900power(); 71 72 SIM900.println( F("AT") ); // Handshaking with SIM900 73 delay(500); 74 SIM900.println( F("AT+CMGF=1") ); // Configuring TEXT mode 75 delay(500); 76 SIM900.println( F("AT+CNMI=1,2,0,0,0") ); // Decides how newly arrived SMS messages should be handled 77 delay(500); 78 79 connectGPRS(); 80} 81 82void loop() { 83 84 while (gps.available( gpsPort )) { 85 fix = gps.read(); 86 87 num_sat = fix.satellites; 88 89 if (fix.valid.location) { 90 digitalWrite(4, HIGH); // sets GPS lock LED 91 92 Lat = fix.latitude(); 93 Long = fix.longitude(); 94 95 // saves the first "GPS lock" flag - we now have useful data 96 if (Lat != 0 && Long != 0 && !valid_location) { 97 valid_location = true; 98 prevFix = fix.location; 99 } 100 } 101 102 if (fix.valid.date && fix.valid.time) 103 { 104 timeFix = fix.dateTime; 105 updateTime(); 106 } 107 108 // update thinger.io and write values to SD card only for valid gps fix 109 // typically at startup before gps has locked in coordinates first time 110 if (valid_location) 111 { 112 113 // updates the distance travelled every 15 seconds 114 static const unsigned long REFRESH_INTERVAL_UPD = 15000; // 15 seconds 115 static unsigned long lastRefreshTime = millis(); 116 117 if (millis() - lastRefreshTime >= REFRESH_INTERVAL_UPD) 118 { 119 lastRefreshTime += REFRESH_INTERVAL_UPD; 120 121 // calculates distance between current and previous fix in meters 122 float distanceDelta = prevFix.DistanceKm(fix.location) * 1000; 123 124 // only update if distance is greater than 10 meters and less than 10km 125 // 10km check is implemented to avoid erroneous data reading from GPS 126 if (distanceDelta > 10 && distanceDelta < 10000) { 127 totalDistance += distanceDelta; 128 } 129 130 // reset the calculation point for next loop (set "previous" location) 131 prevFix = fix.location; 132 133 } 134 135 // writes distance travelled to SD card every 2 minutes 136 // uploads coordinates to thinger.io every 2 minutes 137 static const unsigned long REFRESH_INTERVAL_WRITE_SD = 120000UL; // 2 minutes 138 static unsigned long lastRefreshTimeWriteSD = millis(); 139 140 if (millis() - lastRefreshTimeWriteSD >= REFRESH_INTERVAL_WRITE_SD) 141 { 142 lastRefreshTimeWriteSD += REFRESH_INTERVAL_WRITE_SD; 143 144 // file write to SD card begin 145 char buf[9]; 146 dtostrf(totalDistance, 8, 0, buf); 147 148 if (PF.open(filename)) Serial.println( F("error open file") ); 149 150 while (1) { 151 UINT nr; 152 if (PF.writeFile(buf, sizeof(buf), &nr)) Serial.println( F("error write file") ); 153 if (nr == sizeof(buf)) 154 { 155 PF.writeFile( 0, 0, &nr); // finalize write operation by writing a null pointer 156 break; 157 } 158 } // Petit FS has no "close" operation on file 159 160 // next section transfers data to thinger.io IoT cloud with HTTP POST request. 161 // only update thinger.io after first successful GPS lock 162 163 char httpContent[60]; 164 char tempstrLong[10]; 165 char tempstrLat[10]; 166 167 dtostrf(Lat, 2, 6, tempstrLat); 168 dtostrf(Long, 2, 6, tempstrLong); 169 170 // data fields to thinger.io bucket. Access to bucket is given through URL authorization in the post function. 171 // format is { "field1 name" : field1 , "field2 name" : field2 , "field3 name" : field3 } with exact byte count. 172 sprintf(httpContent, "{ \\"longitude\\": %s , \\"latitude\\": %s , \\"date\\": \\"%s %s\\" }", tempstrLong, tempstrLat, datePrint, timePrint); 173 174 char httpdataLen[20]; 175 176 // exact byte count for the content must be added to HTTPDATA 177 // otherwise HTTP POST request is invalid, i.e. status 400 is retured. 178 sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent)); 179 180 postDataThinger(httpdataLen, httpContent); 181 182 } 183 } 184 } 185 186 // send SMS notification if the total distance exceeds configured limit 187 if (totalDistance > triggerDistance) { 188 char distanceTotalMsg[10]; 189 itoa( (totalDistance / 1000) , distanceTotalMsg, 10); 190 sprintf(sms_msg, "Empty catchtank! Current distance: %skm", distanceTotalMsg); 191 textMessage = ""; 192 number = DEFAULT_NUMBER; 193 totalDistance = 0; 194 195 sendSMS(sms_msg); 196 } 197 198 updateSerial(); 199} 200 201void updateSerial() 202{ 203 // read incoming buffer. reads content of any text message 204 if (SIM900.available() > 0) { 205 textMessage = SIM900.readString(); 206 } 207 208 if (textMessage.indexOf("POS") >= 0) { 209 210 extractSenderNumber(); 211 textMessage = ""; 212 213 char latPrint[10]; 214 dtostrf(Lat, 5, 6, latPrint); 215 216 char LonPrint[10]; 217 dtostrf(Long, 5, 6, LonPrint); 218 219 if (num_sat >= 3 && valid_location) 220 { 221 sprintf(sms_msg, "Current location: Lat: %s, Long: %s. %s%s,+%s\ 222", latPrint, LonPrint, googlePrefix, latPrint, LonPrint); 223 } 224 else if (num_sat < 3 && valid_location) 225 { 226 sprintf(sms_msg, "No gps fix. Last seen %s%sat: Lat: %s, Long: %s. %s%s,+%s\ 227", 228 datePrint, timePrint, latPrint, LonPrint, googlePrefix, latPrint, LonPrint); 229 } 230 else if (!valid_location) 231 { 232 sprintf(sms_msg, "Tom not found. Maybe he is in North-Korea?"); 233 } 234 235 sendSMS(sms_msg); 236 } 237 238 // returns the current total accumulated distance 239 if (textMessage.indexOf("GETKM") >= 0 ) { 240 char sms_msg[32]; 241 char distanceTotalMsg[10]; 242 itoa( (totalDistance / 1000) , distanceTotalMsg, 10); 243 sprintf(sms_msg, "Current distance: %skm", distanceTotalMsg); 244 textMessage = ""; 245 246 sendSMS(sms_msg); 247 } 248 249 // resets the distance counter to 0 250 if (textMessage.indexOf("RESETKM") >= 0) { 251 totalDistance = 0; 252 char sms_msg[] = "Acknowledge: distance reset"; 253 textMessage = ""; 254 255 sendSMS(sms_msg); 256 } 257 258} 259 260void SIM900power() 261{ 262 // power up SIM900 board from pin #7 (default) -> 2sec. signal 263 pinMode(PWRPin, OUTPUT); 264 digitalWrite(PWRPin, LOW); 265 delay(1000); 266 digitalWrite(PWRPin, HIGH); 267 delay(2000); 268 digitalWrite(PWRPin, LOW); 269 delay(15000); // give module time to boot 270} 271 272void updateSIM900() 273{ 274 // empty incoming buffer from SIM900 with read() 275 delay(500); 276 while (SIM900.available()) 277 { 278 // outputs buffer to serial monitor if connected 279 Serial.write(SIM900.read()); 280 } 281} 282 283void extractSenderNumber() 284{ 285 uint8_t startPos = textMessage.indexOf("+", 6); 286 uint8_t endPos = textMessage.indexOf(","); 287 number = textMessage.substring(startPos, endPos - 1); 288} 289 290void sendSMS(char *content) 291{ 292 // really crappy string conversion since I was too lazy to do proper 293 // char handling in the first place. 294 // SMS is returned to the sender number. 295 char numberChar[number.length() + 1]; 296 number.toCharArray(numberChar, number.length() + 1); 297 298 char cmd_sms[50]; 299 sprintf(cmd_sms, "AT+CMGS=%c%s%c", 0x22, numberChar, 0x22); 300 301 SIM900.println(cmd_sms); 302 updateSIM900(); 303 SIM900.print(content); 304 updateSIM900(); 305 SIM900.write(0x1A); 306} 307 308void connectGPRS() 309{ 310 SIM900.println( F("AT+SAPBR=3,1,\\"CONTYPE\\",\\"GPRS\\"") ); 311 delay(1000); 312 updateSIM900(); 313 314 SIM900.println( F("AT+SAPBR=3,1,\\"APN\\",\\"TeleXXX\\"") ); 315 delay(1000); 316 updateSIM900(); 317 318 SIM900.println( F("AT+SAPBR=1,1") ); 319 delay(1000); 320 updateSIM900(); 321 322 SIM900.println( F("AT+SAPBR=2,1") ); 323 delay(1000); 324 updateSIM900(); 325} 326 327void postDataThinger(char *httpDataLen, char* content) 328{ 329 SIM900.println( F("AT+HTTPINIT") ); 330 delay(1000); 331 updateSIM900(); 332 333 SIM900.println( F("AT+HTTPPARA=\\"CID\\",1") ); 334 delay(1000); 335 updateSIM900(); 336 337 SIM900.println( F("AT+HTTPPARA=\\"URL\\",\\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\\"") ); 338 delay(1000); 339 updateSIM900(); 340 341 SIM900.println( F("AT+HTTPPARA=\\"CONTENT\\",\\"application/json\\"") ); 342 delay(1000); 343 updateSIM900(); 344 345 SIM900.println(httpDataLen); 346 delay(1000); 347 updateSIM900(); 348 349 SIM900.println(content); 350 delay(1000); 351 updateSIM900(); 352 353 SIM900.println( F("AT+HTTPACTION=1") ); 354 delay(10000); 355 updateSIM900(); 356 357 SIM900.println( F("AT+HTTPTERM") ); 358 delay(1000); 359 updateSIM900(); 360 361} 362 363// initialize SD card and retrieves stored distance value 364void initializeSD() 365{ 366 367 // first section read current distance from SD card 368 369 char buf[10]; // buffer to hold retrieved distance value 370 371 // Initialize SD card and file system. 372 if (PF.begin(&fs)) Serial.println( F("error begin file") ); 373 374 // Open file for read - saved accumulated total distance 375 if (PF.open(filename)) Serial.println( F("error open file") ); 376 377 while (1) { 378 UINT nr; 379 if (PF.readFile(buf, sizeof(buf), &nr)) Serial.println( F("error read file") ); 380 if (nr == sizeof(buf)) break; 381 } 382 // no close function for Petit FS. 383 384 // retrieves stored distance value to program 385 totalDistance = atof(buf); 386 387 // second section read odometer notification trigger value 388 389 char bufTrigger[10]; // buffer to hold trigger value 390 391 if (PF.open(settings)) Serial.println( F("error open file") ); 392 393 while (1) { 394 UINT nr; 395 if (PF.readFile(bufTrigger, sizeof(bufTrigger), &nr)) Serial.println( F("error read file") ); 396 if (nr == sizeof(bufTrigger)) break; 397 } 398 399 // retrieves odometer notification value 400 triggerDistance = atof(bufTrigger); 401 402} 403 404// corrects time object with time zone offset 405void updateTime() 406{ 407 // set time from GPS data string 408 setTime(timeFix.hours, timeFix.minutes, timeFix.seconds, 409 timeFix.date, timeFix.month, timeFix.year); 410 411 // calc current time zone time by offset value 412 adjustTime(UTC_OFFSET * SECS_PER_HOUR); 413 414 sprintf(datePrint, "%02d/%02d/%04d ", day(), month(), year()); 415 sprintf(timePrint, "%02d:%02d:%02d ", hour(), minute(), second()); 416} 417
GPS_tracker_Leonardo_v2.ino
arduino
1#include <SoftwareSerial.h> 2#include <NMEAGPS.h> 3#include <GPSport.h> 4#include 5 <TimeLib.h> 6#include "PF.h" 7#include "PetitSerial.h" 8 9#define UTC_OFFSET 10 1 // set time zone offset, i.e. 1 = UTC+1 11#define TXPin 8 // SIM900 Tx 12 pin 13#define RXPin 9 // SIM900 Rx pin 14#define PWRPin 7 // SIM900 15 software power pin 16 17// phone number for triggered notification 18#define 19 DEFAULT_NUMBER "+4712345678" 20 21FATFS fs; // file system object 22 - for reading SD card 23 24// GSM variables 25String textMessage; // 26 holds the last received text message 27String number = DEFAULT_NUMBER; // phone 28 number from last text message 29char sms_msg[160]; // holds the 30 SMS reply text 31 32// location variables 33float Lat = 0, Long = 0; 34boolean 35 valid_location = false; // initial valid location flag 36uint8_t num_sat; 37NeoGPS::Location_t 38 prevFix; // holds previous location for distance calculation 39NMEAGPS gps; 40 // parses the GPS characters 41gps_fix fix; // 42 holds on to the latest values 43 44const char *googlePrefix = "http://maps.google.com/maps?q="; 45const 46 char *filename = "DIST.TXT"; 47const char *settings = "SETTINGS.TXT"; 48 49// 50 time variables 51NeoGPS::time_t timeFix; // time object for current gps fix 52char 53 datePrint[13]; 54char timePrint[10]; 55 56// distance tracking variables 57float 58 totalDistance = 0; // in meters 59// triggerdistance (odometer notification) is 60 read from SD card on init 61float triggerDistance = 4000000; 62 63SoftwareSerial 64 SIM900( TXPin, RXPin ); // SIM900 Tx & Rx is connected to Arduino #8 & #9 65 66void 67 setup() { 68 69 pinMode(3, OUTPUT); 70 pinMode(4, OUTPUT); 71 digitalWrite(3, 72 HIGH); // turn on power LED 73 74 Serial.begin(9600); // serial monitor 75 76 77 /* the "while (!serial)" construct below must only be enabled for 78 debugging 79 purposes when connected to a PC. If this is kept in the 80 code the program 81 will stop in a loop when connected to external 82 power sources, as no serial 83 connection will be established 84 */ 85 86 // while (!Serial); // wait 87 for serial port to connect - for ATmega32u4 (Leonardo) 88 89 SIM900.begin(9600); 90 // SIM900 module on pins #8 and #9 91 gpsPort.begin(9600); // GPS receiver 92 on Serial1 pins #0 and #1 - defined in GPSport.h 93 94 // initialize the SD card 95 and reads standard setting and accumulated distance 96 initializeSD(); 97 98 99 // power up SIM900 with software trigger 100 SIM900power(); 101 102 SIM900.println( 103 F("AT") ); // Handshaking with SIM900 104 delay(500); 105 SIM900.println( 106 F("AT+CMGF=1") ); // Configuring TEXT mode 107 delay(500); 108 SIM900.println( 109 F("AT+CNMI=1,2,0,0,0") ); // Decides how newly arrived SMS messages should be 110 handled 111 delay(500); 112 113 connectGPRS(); 114} 115 116void loop() { 117 118 119 while (gps.available( gpsPort )) { 120 fix = gps.read(); 121 122 num_sat 123 = fix.satellites; 124 125 if (fix.valid.location) { 126 digitalWrite(4, 127 HIGH); // sets GPS lock LED 128 129 Lat = fix.latitude(); 130 Long = 131 fix.longitude(); 132 133 // saves the first "GPS lock" flag - we now have 134 useful data 135 if (Lat != 0 && Long != 0 && !valid_location) { 136 valid_location 137 = true; 138 prevFix = fix.location; 139 } 140 } 141 142 if (fix.valid.date 143 && fix.valid.time) 144 { 145 timeFix = fix.dateTime; 146 updateTime(); 147 148 } 149 150 // update thinger.io and write values to SD card only for valid 151 gps fix 152 // typically at startup before gps has locked in coordinates first 153 time 154 if (valid_location) 155 { 156 157 // updates the distance travelled 158 every 15 seconds 159 static const unsigned long REFRESH_INTERVAL_UPD = 15000; 160 // 15 seconds 161 static unsigned long lastRefreshTime = millis(); 162 163 164 if (millis() - lastRefreshTime >= REFRESH_INTERVAL_UPD) 165 { 166 lastRefreshTime 167 += REFRESH_INTERVAL_UPD; 168 169 // calculates distance between current and 170 previous fix in meters 171 float distanceDelta = prevFix.DistanceKm(fix.location) 172 * 1000; 173 174 // only update if distance is greater than 10 meters and 175 less than 10km 176 // 10km check is implemented to avoid erroneous data reading 177 from GPS 178 if (distanceDelta > 10 && distanceDelta < 10000) { 179 totalDistance 180 += distanceDelta; 181 } 182 183 // reset the calculation point for 184 next loop (set "previous" location) 185 prevFix = fix.location; 186 187 188 } 189 190 // writes distance travelled to SD card every 2 minutes 191 192 // uploads coordinates to thinger.io every 2 minutes 193 static const 194 unsigned long REFRESH_INTERVAL_WRITE_SD = 120000UL; // 2 minutes 195 static 196 unsigned long lastRefreshTimeWriteSD = millis(); 197 198 if (millis() - lastRefreshTimeWriteSD 199 >= REFRESH_INTERVAL_WRITE_SD) 200 { 201 lastRefreshTimeWriteSD += REFRESH_INTERVAL_WRITE_SD; 202 203 204 // file write to SD card begin 205 char buf[9]; 206 dtostrf(totalDistance, 207 8, 0, buf); 208 209 if (PF.open(filename)) Serial.println( F("error open 210 file") ); 211 212 while (1) { 213 UINT nr; 214 if (PF.writeFile(buf, 215 sizeof(buf), &nr)) Serial.println( F("error write file") ); 216 if (nr 217 == sizeof(buf)) 218 { 219 PF.writeFile( 0, 0, &nr); // finalize 220 write operation by writing a null pointer 221 break; 222 } 223 224 } // Petit FS has no "close" operation on file 225 226 // next 227 section transfers data to thinger.io IoT cloud with HTTP POST request. 228 // 229 only update thinger.io after first successful GPS lock 230 231 char httpContent[60]; 232 233 char tempstrLong[10]; 234 char tempstrLat[10]; 235 236 dtostrf(Lat, 237 2, 6, tempstrLat); 238 dtostrf(Long, 2, 6, tempstrLong); 239 240 // 241 data fields to thinger.io bucket. Access to bucket is given through URL authorization 242 in the post function. 243 // format is { "field1 name" : field1 , "field2 244 name" : field2 , "field3 name" : field3 } with exact byte count. 245 sprintf(httpContent, 246 "{ \\"longitude\\": %s , \\"latitude\\": %s , \\"date\\": \\"%s %s\\" }", 247 tempstrLong, tempstrLat, datePrint, timePrint); 248 249 char httpdataLen[20]; 250 251 252 // exact byte count for the content must be added to HTTPDATA 253 // 254 otherwise HTTP POST request is invalid, i.e. status 400 is retured. 255 sprintf(httpdataLen, 256 "AT+HTTPDATA=%i,10000", strlen(httpContent)); 257 258 postDataThinger(httpdataLen, 259 httpContent); 260 261 } 262 } 263 } 264 265 // send SMS notification if 266 the total distance exceeds configured limit 267 if (totalDistance > triggerDistance) 268 { 269 char distanceTotalMsg[10]; 270 itoa( (totalDistance / 1000) , distanceTotalMsg, 271 10); 272 sprintf(sms_msg, "Empty catchtank! Current distance: %skm", distanceTotalMsg); 273 274 textMessage = ""; 275 number = DEFAULT_NUMBER; 276 totalDistance = 0; 277 278 279 sendSMS(sms_msg); 280 } 281 282 updateSerial(); 283} 284 285void updateSerial() 286{ 287 288 // read incoming buffer. reads content of any text message 289 if (SIM900.available() 290 > 0) { 291 textMessage = SIM900.readString(); 292 } 293 294 if (textMessage.indexOf("POS") 295 >= 0) { 296 297 extractSenderNumber(); 298 textMessage = ""; 299 300 char 301 latPrint[10]; 302 dtostrf(Lat, 5, 6, latPrint); 303 304 char LonPrint[10]; 305 306 dtostrf(Long, 5, 6, LonPrint); 307 308 if (num_sat >= 3 && valid_location) 309 310 { 311 sprintf(sms_msg, "Current location: Lat: %s, Long: %s. %s%s,+%s\ 312", 313 latPrint, LonPrint, googlePrefix, latPrint, LonPrint); 314 } 315 else if (num_sat 316 < 3 && valid_location) 317 { 318 sprintf(sms_msg, "No gps fix. Last seen 319 %s%sat: Lat: %s, Long: %s. %s%s,+%s\ 320", 321 datePrint, timePrint, 322 latPrint, LonPrint, googlePrefix, latPrint, LonPrint); 323 } 324 else if (!valid_location) 325 326 { 327 sprintf(sms_msg, "Tom not found. Maybe he is in North-Korea?"); 328 329 } 330 331 sendSMS(sms_msg); 332 } 333 334 // returns the current total 335 accumulated distance 336 if (textMessage.indexOf("GETKM") >= 0 ) { 337 char 338 sms_msg[32]; 339 char distanceTotalMsg[10]; 340 itoa( (totalDistance / 1000) 341 , distanceTotalMsg, 10); 342 sprintf(sms_msg, "Current distance: %skm", distanceTotalMsg); 343 344 textMessage = ""; 345 346 sendSMS(sms_msg); 347 } 348 349 // resets the 350 distance counter to 0 351 if (textMessage.indexOf("RESETKM") >= 0) { 352 totalDistance 353 = 0; 354 char sms_msg[] = "Acknowledge: distance reset"; 355 textMessage 356 = ""; 357 358 sendSMS(sms_msg); 359 } 360 361} 362 363void SIM900power() 364{ 365 366 // power up SIM900 board from pin #7 (default) -> 2sec. signal 367 pinMode(PWRPin, 368 OUTPUT); 369 digitalWrite(PWRPin, LOW); 370 delay(1000); 371 digitalWrite(PWRPin, 372 HIGH); 373 delay(2000); 374 digitalWrite(PWRPin, LOW); 375 delay(15000); // 376 give module time to boot 377} 378 379void updateSIM900() 380{ 381 // empty incoming 382 buffer from SIM900 with read() 383 delay(500); 384 while (SIM900.available()) 385 386 { 387 // outputs buffer to serial monitor if connected 388 Serial.write(SIM900.read()); 389 390 } 391} 392 393void extractSenderNumber() 394{ 395 uint8_t startPos = textMessage.indexOf("+", 396 6); 397 uint8_t endPos = textMessage.indexOf(","); 398 number = textMessage.substring(startPos, 399 endPos - 1); 400} 401 402void sendSMS(char *content) 403{ 404 // really crappy 405 string conversion since I was too lazy to do proper 406 // char handling in the 407 first place. 408 // SMS is returned to the sender number. 409 char numberChar[number.length() 410 + 1]; 411 number.toCharArray(numberChar, number.length() + 1); 412 413 char cmd_sms[50]; 414 415 sprintf(cmd_sms, "AT+CMGS=%c%s%c", 0x22, numberChar, 0x22); 416 417 SIM900.println(cmd_sms); 418 419 updateSIM900(); 420 SIM900.print(content); 421 updateSIM900(); 422 SIM900.write(0x1A); 423} 424 425void 426 connectGPRS() 427{ 428 SIM900.println( F("AT+SAPBR=3,1,\\"CONTYPE\\",\\"GPRS\\"") 429 ); 430 delay(1000); 431 updateSIM900(); 432 433 SIM900.println( F("AT+SAPBR=3,1,\\"APN\\",\\"TeleXXX\\"") 434 ); 435 delay(1000); 436 updateSIM900(); 437 438 SIM900.println( F("AT+SAPBR=1,1") 439 ); 440 delay(1000); 441 updateSIM900(); 442 443 SIM900.println( F("AT+SAPBR=2,1") 444 ); 445 delay(1000); 446 updateSIM900(); 447} 448 449void postDataThinger(char 450 *httpDataLen, char* content) 451{ 452 SIM900.println( F("AT+HTTPINIT") ); 453 454 delay(1000); 455 updateSIM900(); 456 457 SIM900.println( F("AT+HTTPPARA=\\"CID\\",1") 458 ); 459 delay(1000); 460 updateSIM900(); 461 462 SIM900.println( F("AT+HTTPPARA=\\"URL\\",\\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\\"") 463 ); 464 delay(1000); 465 updateSIM900(); 466 467 SIM900.println( F("AT+HTTPPARA=\\"CONTENT\\",\\"application/json\\"") 468 ); 469 delay(1000); 470 updateSIM900(); 471 472 SIM900.println(httpDataLen); 473 474 delay(1000); 475 updateSIM900(); 476 477 SIM900.println(content); 478 delay(1000); 479 480 updateSIM900(); 481 482 SIM900.println( F("AT+HTTPACTION=1") ); 483 delay(10000); 484 485 updateSIM900(); 486 487 SIM900.println( F("AT+HTTPTERM") ); 488 delay(1000); 489 490 updateSIM900(); 491 492} 493 494// initialize SD card and retrieves stored distance 495 value 496void initializeSD() 497{ 498 499 // first section read current distance 500 from SD card 501 502 char buf[10]; // buffer to hold retrieved distance value 503 504 505 // Initialize SD card and file system. 506 if (PF.begin(&fs)) Serial.println( 507 F("error begin file") ); 508 509 // Open file for read - saved accumulated total 510 distance 511 if (PF.open(filename)) Serial.println( F("error open file") ); 512 513 514 while (1) { 515 UINT nr; 516 if (PF.readFile(buf, sizeof(buf), &nr)) Serial.println( 517 F("error read file") ); 518 if (nr == sizeof(buf)) break; 519 } 520 // no 521 close function for Petit FS. 522 523 // retrieves stored distance value to program 524 525 totalDistance = atof(buf); 526 527 // second section read odometer notification 528 trigger value 529 530 char bufTrigger[10]; // buffer to hold trigger value 531 532 533 if (PF.open(settings)) Serial.println( F("error open file") ); 534 535 while 536 (1) { 537 UINT nr; 538 if (PF.readFile(bufTrigger, sizeof(bufTrigger), &nr)) 539 Serial.println( F("error read file") ); 540 if (nr == sizeof(bufTrigger)) break; 541 542 } 543 544 // retrieves odometer notification value 545 triggerDistance = atof(bufTrigger); 546 547} 548 549// 550 corrects time object with time zone offset 551void updateTime() 552{ 553 // set 554 time from GPS data string 555 setTime(timeFix.hours, timeFix.minutes, timeFix.seconds, 556 557 timeFix.date, timeFix.month, timeFix.year); 558 559 // calc current time 560 zone time by offset value 561 adjustTime(UTC_OFFSET * SECS_PER_HOUR); 562 563 sprintf(datePrint, 564 "%02d/%02d/%04d ", day(), month(), year()); 565 sprintf(timePrint, "%02d:%02d:%02d 566 ", hour(), minute(), second()); 567} 568
Downloadable files
track_me_project_bb_uejafKcZyT.png
track_me_project_bb_uejafKcZyT.png
track_me_project_bb_uejafKcZyT.png
track_me_project_bb_uejafKcZyT.png
Documentation
Casing top (compact)
A compact version of the top casing (less space inside enclosure)
Casing top (compact)
settings_iMpR6v81OB.txt
rename to "settings.txt" and place on SD card
settings_iMpR6v81OB.txt
lock2_ZR5SAmG6IJ.stl
Locks SIM900 board in place (no mounting holes on SIM900 board)
lock2_ZR5SAmG6IJ.stl
Casing top (large)
Top of casing for more space (taller). The mounting holes are closed and must be drilled after print (to make for easier printing)
Casing top (large)
casing_bottom_0Cy4SBAx3t.stl
Bottom part of casing - for SIM900 and Arduino board with cutouts for connectors
casing_bottom_0Cy4SBAx3t.stl
dist_1qOG9VMO2D.txt
rename to "dist.txt" and place on SD card
dist_1qOG9VMO2D.txt
Casing top (large)
Top of casing for more space (taller). The mounting holes are closed and must be drilled after print (to make for easier printing)
Casing top (large)
settings_iMpR6v81OB.txt
rename to "settings.txt" and place on SD card
settings_iMpR6v81OB.txt
lock2_ZR5SAmG6IJ.stl
Locks SIM900 board in place (no mounting holes on SIM900 board)
lock2_ZR5SAmG6IJ.stl
casing_bottom_0Cy4SBAx3t.stl
Bottom part of casing - for SIM900 and Arduino board with cutouts for connectors
casing_bottom_0Cy4SBAx3t.stl
lock1_C45eXQfR5p.stl
Locks SIM900 board in place
lock1_C45eXQfR5p.stl
dist_1qOG9VMO2D.txt
rename to "dist.txt" and place on SD card
dist_1qOG9VMO2D.txt
Casing top (compact)
A compact version of the top casing (less space inside enclosure)
Casing top (compact)
Comments
Only logged in users can leave comments
tormods
0 Followers
•0 Projects
Table of contents
Intro
10
0