{"id":419,"date":"2016-07-11T20:29:01","date_gmt":"2016-07-11T19:29:01","guid":{"rendered":"https:\/\/www.kolkataonweb.com\/code-bank\/?p=419"},"modified":"2016-07-24T19:36:35","modified_gmt":"2016-07-24T18:36:35","slug":"gps-tracker-using-neo-6m-and-esp-12","status":"publish","type":"post","link":"https:\/\/www.kolkataonweb.com\/code-bank\/esp-8266\/gps-tracker-using-neo-6m-and-esp-12\/","title":{"rendered":"GPS Tracker Using NEO 6M and ESP-12"},"content":{"rendered":"<p>The below code outputs current co-ordinate and speed in km\/hr . The code is a first draft and there are optimizations to be done. It uses a Ublox NEO 6M for the GPS module and an ESP-12 (of the ESP 8266 family) for the collecting the GPS data from the NEO 6M module, processing the data and outputting in JSON format.<\/p>\n<p>The ESP-12 is working as a webserver. When connected it first asks for the WiFi password set in the code as &#8220;WiFiAPPSK&#8221;. And for an added layer of security a password is also needed with the HTTP request. (<em>This will made proper in future<\/em>).\u00a0 Without the password the server will reject the request.<\/p>\n<p><a href=\"https:\/\/www.kolkataonweb.com\/code-bank\/esp-8266\/esp8266-programming-using-arduino-ide\/\">Arduino IDE is used for programming the ESP-12.<\/a><\/p>\n<p>&nbsp;<\/p>\n<pre class='wp-code-highlight prettyprint'>\/\/#include &lt;SoftwareSerial.h&gt; \/\/causing the module to reset automatically intermittently\r\n#include &lt;ESP8266WiFi.h&gt;\r\n#include &lt;EEPROM.h&gt;\r\n\r\n\/\/SoftwareSerial gps(14,12);\r\n\r\nchar WiFiAPPSK[] = \"123456#\";\r\nchar savedPass[9] = \"12345678\", suppliedPass[9], hashedPass[9];\r\nint addr = 0;\r\n\r\nshort int resetWifiFlag = 0;\r\n\r\nWiFiServer server(80);\r\n\r\nvoid encodePass(char *pass, char *hash) \/\/encoding using XOR, need to change as this generates characters that causes problems while passed through GET method\r\n{\r\n\u00a0 short int i;\r\n\u00a0 char key[9] = \"ikirmiki\"; \/\/8 chars\r\n\u00a0 \r\n\u00a0 i = strlen(pass);\r\n\u00a0 \r\n\u00a0 \/\/i is pointing at the end of the string. Now fillup the rest string with NULL\r\n\u00a0 for(; i&lt;=9; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 pass[i] = '\\0';\r\n\u00a0 }\r\n\u00a0 \/\/at this point the pass is filled with pass and all empty cells are filled with NULL\r\n\u00a0 \/\/now let's do the XOR\r\n\u00a0 for(i=0; i&lt;=9;i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 \/\/hash[i] = pass[i] ^ key[i];\r\n\u00a0\u00a0\u00a0 *(hash+i) = *(pass+i) \/*^ key[i]*\/;\r\n\u00a0 }\r\n}\r\n\r\nvoid decodePass(char *pass, char *hash)\r\n{\r\n\u00a0 short int i;\r\n\u00a0 char key[9] = \"ikirmiki\"; \/\/8 chars\r\n\u00a0 \r\n\u00a0 \/\/check the hash by decoding\r\n\u00a0 \/\/now let's do the XOR\r\n\u00a0 for(i=0; i&lt;=9;i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 *(pass+i) = *(hash+i) \/*^ key[i]*\/; \/\/Overridden for now as XOR creates some special characters sometimes which is not being interpreted by browser address bar properly.\r\n\u00a0 }\r\n}\r\n\r\nvoid explodeString(char *delimiter, char *str, char explodedArray[][32]) \r\n{\r\n\u00a0 int i = 0;\r\n\u00a0 char* token;\r\n\u00a0 \r\n\u00a0 token = strtok(str, delimiter);\r\n\u00a0 while(token != NULL)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0 \/\/explodedArray[i] = (char *)malloc(strlen(token)+1);\r\n\u00a0\u00a0\u00a0\u00a0 strcpy(explodedArray[i++],token);delay(1);\r\n\u00a0\u00a0\u00a0\u00a0 token = strtok(NULL, delimiter);\r\n\u00a0 }\r\n}\r\n\r\n\r\nshort int ensure8CharPass(char *pass, char *tempPass) \/\/for the XOR ing with 8 chars key we need to ensure the pass is also 8 chars\r\n{\r\n\u00a0 short int i;\r\n\r\n\u00a0 for(i=0;i&lt;9;i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 pass[i]=tempPass[i];\r\n\u00a0 }\r\n\u00a0 pass[i] = '\\0';\r\n\u00a0 \r\n\u00a0 if(strlen(pass) != 8)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 return 0;\r\n\u00a0 }\r\n\u00a0 else\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 return 1;\r\n\u00a0 }\r\n}\r\n\r\nString getSpeed(String rawLatLong)\r\n{\r\n\u00a0 int firstPos, lastPos = 0;\r\n\u00a0 int i;\r\n\r\n\u00a0 firstPos = rawLatLong.indexOf(\"$GPVTG,\");\r\n\u00a0 for(i=0; i &lt; 7; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 firstPos = rawLatLong.indexOf(\",\", firstPos+1); \/\/$GPVTG,279.67,T,,M,4.903,N,9.080,K,A*3F -- go to 9.080\r\n\u00a0\u00a0\u00a0 delay(1); \r\n\u00a0 }\r\n\u00a0 firstPos = firstPos + 1; \/\/skip the comma that is infront of 9.080\r\n\u00a0 lastPos = firstPos;\r\n\u00a0 for(i=0; i &lt; 2; i++) \/\/go to the comma after K\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 lastPos = rawLatLong.indexOf(\",\", lastPos+1);\r\n\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0 }\r\n\u00a0 return rawLatLong.substring(firstPos,lastPos);\r\n}\r\n\r\n\r\nString getLatLong(String rawLatLong)\r\n{\r\n\u00a0 int firstPos = 0, lastPos = 0, i, degree;\r\n\u00a0 char latLong[5][32], buff[64];\r\n\u00a0 float latitude, longitude, minute;\r\n\u00a0 String temp;\r\n\r\n\u00a0 firstPos = rawLatLong.indexOf(\"$GPRMC,\"); \/\/same concept as in above ($GPVTG)\r\n\u00a0 for(i=0; i &lt; 3; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 firstPos = rawLatLong.indexOf(\",\", firstPos+1);\r\n\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0 }\r\n\u00a0 firstPos = firstPos + 1; \/\/skip the comma -- same concept as in above ($GPVTG)\r\n\u00a0 lastPos = firstPos;\r\n\u00a0 for(i=0; i &lt; 4; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 lastPos = rawLatLong.indexOf(\",\", lastPos+1);\r\n\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0 }\r\n\u00a0 \r\n\u00a0 temp = rawLatLong.substring(firstPos,lastPos); delay(1); \/\/ delay(1) need to checked if necessary or not. \r\n\u00a0 temp.toCharArray(buff,64); delay(1); \/\/ delay(1) need to checked if necessary or not.\r\n\u00a0 explodeString(\",\",buff,latLong); delay(1);\u00a0 \/\/ delay(1) need to checked if necessary or not.\r\n\u00a0 \/\/at this point latLong must have all the elemnts in consequetive array\r\n\u00a0 \/\/convert the values in position 0 and 2\r\n\u00a0 \/\/fist check if the values at those positions are valid or not\r\n\u00a0 if(strlen(latLong[0]) &amp;&amp; strlen(latLong[2])) \/\/convert to decimal format from degree, minute\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 latitude = atof(latLong[0]);\r\n\u00a0\u00a0\u00a0 longitude = atof(latLong[2]);\r\n\u00a0\u00a0\u00a0 latitude = latitude \/ 100;\r\n\u00a0\u00a0\u00a0 longitude = longitude \/ 100;\r\n\r\n\u00a0\u00a0\u00a0 degree = (int)latitude;\r\n\u00a0\u00a0\u00a0 minute = latitude - degree;\r\n\u00a0\u00a0\u00a0 minute = minute * 100;\r\n\u00a0\u00a0\u00a0 latitude = degree + (minute\/60);\r\n\r\n\u00a0\u00a0\u00a0 degree = (int)longitude;\r\n\u00a0\u00a0\u00a0 minute = longitude - degree;\r\n\u00a0\u00a0\u00a0 minute = minute * 100;\r\n\u00a0\u00a0\u00a0 longitude = degree + (minute\/60);\r\n\r\n\u00a0\u00a0\u00a0 delay(1); \/\/need to check if needed\r\n\u00a0\u00a0\u00a0 \/\/Serial.println(String(latitude,6)+\",\"+latLong[1]+\",\"+String(longitude)+\",\"+latLong[3]);\r\n\u00a0\u00a0\u00a0 return (String(latitude,6)+\",\"+latLong[1]+\",\"+String(longitude,6)+\",\"+latLong[3]); \/\/String(latitude,6) the second parameter to string sets the precision after decimal. \r\n\r\n\u00a0\u00a0 \u00a0\r\n\u00a0 }\r\n\u00a0 else\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 return String(\"Yet to get a fix\");\r\n\u00a0 }\r\n\u00a0 \r\n}\r\n\r\nvoid writeSettings(int addr, char *toWrite)\r\n{\r\n\u00a0 int i;\r\n\u00a0 for(i=0; i&lt;9; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 EEPROM.write((addr+i), toWrite[i]);\r\n\u00a0 }\r\n\u00a0 EEPROM.commit();\r\n}\r\n\r\nvoid readSettings(int addr, char *toRead) \/\/ will have to change this function - need to make it such t\r\n{\r\n\u00a0 int i;\r\n\u00a0 for(i=0; i&lt;9; i++)\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 toRead[i] = EEPROM.read((addr+i));\r\n\u00a0 }\r\n\u00a0 toRead[i] = '\\0';\r\n}\r\n\r\nvoid setupWiFi()\r\n{\r\n\u00a0 WiFi.mode(WIFI_AP);\r\n\r\n\u00a0 \/\/ Do a little work to get a unique-ish name. Append the\r\n\u00a0 \/\/ last two bytes of the MAC (HEX'd) to \"Thing-\":\r\n\u00a0 uint8_t mac[WL_MAC_ADDR_LENGTH];\r\n\u00a0 WiFi.softAPmacAddress(mac);\r\n\u00a0 String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);\r\n\u00a0 macID.toUpperCase();\r\n\u00a0 String AP_NameString = \"GPS Tracker \" + macID;\r\n\r\n\u00a0 char AP_NameChar[AP_NameString.length() + 1];\r\n\u00a0 memset(AP_NameChar, 0, AP_NameString.length() + 1);\r\n\r\n\u00a0 for (int i=0; i&lt;AP_NameString.length(); i++)\r\n\u00a0\u00a0\u00a0 AP_NameChar[i] = AP_NameString.charAt(i);\r\n\r\n\u00a0 WiFi.softAP(AP_NameChar, WiFiAPPSK);\r\n\r\n\u00a0 resetWifiFlag = 0; \/\/look in loop for explanation\r\n}\r\n\r\n\r\nvoid setup() \r\n{\r\n\u00a0 \/\/ put your setup code here, to run once:\r\n\u00a0 Serial.begin(9600);\r\n\u00a0 EEPROM.begin(64); \/\/initiate 64 bytes to write\/read\r\n\u00a0 \/\/gps.begin(9600);\r\n\u00a0\r\n\u00a0 readSettings(addr+0, hashedPass); \/\/read the saved pass at addr+0 location\r\n\u00a0 if(strlen(hashedPass) == 8) \/\/id the saved password is of proper length then decode it and use it.\r\n\u00a0\u00a0\u00a0 decodePass(savedPass, hashedPass);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0 strcpy(WiFiAPPSK,savedPass); \/\/set the Wifi Password also\r\n\u00a0 setupWiFi(); \/\/start the wifi\r\n\u00a0 \r\n\u00a0 server.begin();\r\n}\r\n\r\nvoid loop() \r\n{\r\n\u00a0 \/\/check if any variable is redundant\r\n\u00a0 volatile unsigned long startTime, currentTime;\r\n\u00a0 String serialBuffer, latLong;\r\n\u00a0 int pos,flag,i,j,temp;\r\n\u00a0 short int passError = 1, len, latLongFlag = 0, speedFlag = 0;\r\n\u00a0 char serialDataByte;\r\n\r\n\u00a0 if(resetWifiFlag == 1) \/\/ if the password is changed then this will be called to re-initialize the WIFI-AP with the new password\r\n\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 setupWiFi();\r\n\u00a0\u00a0 }\r\n\u00a0 \r\n\u00a0 \/\/start the webserver and send the data\r\n\u00a0 \/\/ Check if a client has connected\r\n\u00a0 WiFiClient client = server.available();\r\n\u00a0 if (!client) \r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0 return;\r\n\u00a0 }\r\n\u00a0 else\r\n\u00a0 {\r\n\u00a0\u00a0\u00a0 delay(1);\r\n\r\n\u00a0\u00a0\u00a0 \/\/Read the first line of the request\r\n\u00a0\u00a0\u00a0 String req = client.readStringUntil('\\r');\r\n\r\n\u00a0\u00a0\u00a0 \/\/now check if password change requested or not\r\n\u00a0\u00a0\u00a0 pos = req.indexOf(\"\/changepass\/\");\r\n\u00a0\u00a0\u00a0 if(pos != -1)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/get the new pass\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 len = pos+12+8; \/\/12 chars of \/changepass\/ AND 8 of password\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 for(i=pos+12,j=0; i&lt;len; i++,j++)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(req.charAt(i) == '\/')\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hashedPass[j] = req.charAt(i);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 hashedPass[j] = '\\0';\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 decodePass(suppliedPass, hashedPass);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 strcpy(savedPass,suppliedPass);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/save the password\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/Serial.println(\"New Pass: \"+ String(hashedPass));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 writeSettings(addr+0, hashedPass); \/\/save the password\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/not calling a function for sending the data to save the function call overhead.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Prepare the response. Start with the common header:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 String s = \"HTTP\/1.1 200 OK\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"Content-Type: application\/json\\r\\n\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"{\"succcess\":\"Password Changed To: \"+ String(suppliedPass)+\"\"}\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Send the response to the client\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.print(s);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.stop();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ESP.restart(); \/\/to make the new password in effect immediately - USING THIS WILL NOT DISPLAY THE RESULT. It seems the loop needs to be exited to send the result to client Using a delay of 10 seconds also didn't work\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/AS THE restart method is not available so setting up the wifi again with the new password\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 strcpy(WiFiAPPSK,suppliedPass); \/\/set the Wifi Password also\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 resetWifiFlag =1; \/\/ if the wifi pass is changed here now then client will loose connection before printing the result. the loop() will have to be exited to print the result. so we are setting the flag here and changing the password in the next iteration of the loop()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1); \/\/safe side\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return;\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 pos = req.indexOf(\"\/pass\/\");\r\n\u00a0\u00a0\u00a0 if(pos == -1) \/\/ that means no password supplied\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/not calling a function for sending the data to save the function call overhead.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Prepare the response. Start with the common header:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 String s = \"HTTP\/1.1 200 OK\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"Content-Type: application\/json\\r\\n\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"{\"error\":\"Auhentication Error 1\"}\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Send the response to the client\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.print(s);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 client.stop();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 return;\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/Serial.println(\"Client Connected\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/read upto the next slash\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 len = pos+6+8; \/\/6 chars of \/changepass\/ AND 8 of password\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 for(i=pos+6,j=0; i&lt;len; i++,j++)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(req.charAt(i) == '\/')\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hashedPass[j] = req.charAt(i);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 hashedPass[j] = '\\0';\r\n\u00a0\u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/now decode the pass \r\n\u00a0\u00a0\u00a0\u00a0\u00a0 decodePass(suppliedPass, hashedPass);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if(strcmp(suppliedPass,savedPass))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/not calling a function for sending the data to save the function call overhead.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 client.flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Prepare the response. Start with the common header:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String s = \"HTTP\/1.1 200 OK\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"Content-Type: application\/json\\r\\n\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 s += \"{\"error\":\"Auhentication Error 2\"}\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Send the response to the client\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 client.print(s);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 client.flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 client.stop();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 startTime = currentTime = 0;\r\n\u00a0\u00a0\u00a0 serialBuffer = latLong = \"\";\r\n\u00a0 \r\n\u00a0\u00a0\u00a0 flag = -1;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 startTime = millis();\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 \/\/ put your main code here, to run repeatedly:\r\n\u00a0\u00a0\u00a0 while(flag == -1)\u00a0 \/\/read 5 seconds of data\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if(Serial.available() &gt; 0)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialBuffer += (char)Serial.read();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(serialBuffer.indexOf(\"$GPRMC,\") &gt;=0)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 while(1)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialDataByte = (char)Serial.read();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(serialDataByte == '\\r' || serialDataByte == '$') \/\/need to optimize - check if \\r is sufficient\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLong = getLatLong(serialBuffer);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialBuffer = serialDataByte; \/\/reset the serial buffer for the next line\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialBuffer += serialDataByte;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(serialBuffer.indexOf(\"$GPVTG,\") &gt;=0)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 while(1)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialDataByte = (char)Serial.read();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if(serialDataByte == '\\r' || serialDataByte == '$') \/\/need to optimize - check if \\r is sufficient\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 flag = 1;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLong = latLong + \",\" + getSpeed(serialBuffer);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLong = \"{\"success\":\"\"+latLong+\"\"}\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serialBuffer += serialDataByte;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if(millis()- startTime &gt; 5000)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/Serial.println(\"TimeOut\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLong = \"Timeout\"; \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLong = \"{\"error\":\"\"+latLong+\"\"}\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 latLongFlag = speedFlag = 0;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 delay(1);\r\n\u00a0\u00a0\u00a0 } \r\n\u00a0\u00a0\u00a0 \/\/Serial.println(\"LN: \"+latLong);\r\n\u00a0 }\r\n\r\n\u00a0 client.flush();\r\n\u00a0 \/\/ Prepare the response. Start with the common header:\r\n\u00a0 String s = \"HTTP\/1.1 200 OK\\r\\n\";\r\n\u00a0 s += \"Content-Type: application\/json\\r\\n\\r\\n\";\r\n\u00a0 \/\/s += \"&lt;!DOCTYPE HTML&gt;\\r\\n&lt;html&gt;\\r\\n&lt;body&gt;\\r\\n\";\r\n\u00a0 s += latLong;\r\n\u00a0 \/\/s += \"&lt;\/body&gt;\\r\\n&lt;\/html&gt;\\n\";\r\n\u00a0 \/\/ Send the response to the client\r\n\u00a0 client.print(s);\r\n\u00a0 client.flush();\r\n\u00a0 \/\/delay(100); Serial.println(\"Client disonnected\");\r\n\u00a0 latLongFlag = speedFlag = 0; \u00a0\r\n\u00a0 delay(1);\r\n\u00a0 client.stop();\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Notes:<\/strong><\/p>\n<ul>\n<li>The <em>setupWifi<\/em> code is from <a href=\"https:\/\/learn.sparkfun.com\/tutorials\/esp8266-thing-hookup-guide\/all\">Sparkfun&#8217;s code<\/a><\/li>\n<li>The Software Serial is causing trouble. The WiFi Access Point (AP) is dying after sometime if the Software Serial Library is used.<\/li>\n<li>The <em>delays<\/em> are needed to allow the ESP8266 to do it&#8217;s own internal tasks (like maintaining the wifi connection). The delays are needed where there can be long loops.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The below code outputs current co-ordinate and speed in km\/hr . The code is a first draft and there are optimizations to be done. It uses a Ublox NEO 6M for the GPS module and an ESP-12 (of the ESP 8266 family) for the collecting the GPS data from the NEO 6M module, processing the&hellip; <a class=\"more-link\" href=\"https:\/\/www.kolkataonweb.com\/code-bank\/esp-8266\/gps-tracker-using-neo-6m-and-esp-12\/\">Continue reading <span class=\"screen-reader-text\">GPS Tracker Using NEO 6M and ESP-12<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[64],"tags":[17,20,70,68,72,69],"class_list":["post-419","post","type-post","status-publish","format-standard","hentry","category-esp-8266","tag-ai-cloud-inside","tag-esp-8266","tag-esp-8266-webserver","tag-esp-12","tag-gps-tracking-with-esp8266","tag-ublox-neo-6m","entry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/posts\/419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/comments?post=419"}],"version-history":[{"count":12,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/posts\/419\/revisions"}],"predecessor-version":[{"id":460,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/posts\/419\/revisions\/460"}],"wp:attachment":[{"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/media?parent=419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/categories?post=419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kolkataonweb.com\/code-bank\/wp-json\/wp\/v2\/tags?post=419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}