Tag Archives: Ai-Cloud inside

GPS Tracker Using NEO 6M and ESP-12

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.

The ESP-12 is working as a webserver. When connected it first asks for the WiFi password set in the code as “WiFiAPPSK”. And for an added layer of security a password is also needed with the HTTP request. (This will made proper in future).  Without the password the server will reject the request.

Arduino IDE is used for programming the ESP-12.

 

//#include <SoftwareSerial.h> //causing the module to reset automatically intermittently
#include <ESP8266WiFi.h>
#include <EEPROM.h>

//SoftwareSerial gps(14,12);

char WiFiAPPSK[] = "123456#";
char savedPass[9] = "12345678", suppliedPass[9], hashedPass[9];
int addr = 0;

short int resetWifiFlag = 0;

WiFiServer server(80);

void encodePass(char *pass, char *hash) //encoding using XOR, need to change as this generates characters that causes problems while passed through GET method
{
  short int i;
  char key[9] = "ikirmiki"; //8 chars
  
  i = strlen(pass);
  
  //i is pointing at the end of the string. Now fillup the rest string with NULL
  for(; i<=9; i++)
  {
    pass[i] = '\0';
  }
  //at this point the pass is filled with pass and all empty cells are filled with NULL
  //now let's do the XOR
  for(i=0; i<=9;i++)
  {
    //hash[i] = pass[i] ^ key[i];
    *(hash+i) = *(pass+i) /*^ key[i]*/;
  }
}

void decodePass(char *pass, char *hash)
{
  short int i;
  char key[9] = "ikirmiki"; //8 chars
  
  //check the hash by decoding
  //now let's do the XOR
  for(i=0; i<=9;i++)
  {
    *(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.
  }
}

void explodeString(char *delimiter, char *str, char explodedArray[][32]) 
{
  int i = 0;
  char* token;
  
  token = strtok(str, delimiter);
  while(token != NULL)
  {
     //explodedArray[i] = (char *)malloc(strlen(token)+1);
     strcpy(explodedArray[i++],token);delay(1);
     token = strtok(NULL, delimiter);
  }
}


short int ensure8CharPass(char *pass, char *tempPass) //for the XOR ing with 8 chars key we need to ensure the pass is also 8 chars
{
  short int i;

  for(i=0;i<9;i++)
  {
    pass[i]=tempPass[i];
  }
  pass[i] = '\0';
  
  if(strlen(pass) != 8)
  {
    return 0;
  }
  else
  {
    return 1;
  }
}

String getSpeed(String rawLatLong)
{
  int firstPos, lastPos = 0;
  int i;

  firstPos = rawLatLong.indexOf("$GPVTG,");
  for(i=0; i < 7; i++)
  {
    firstPos = rawLatLong.indexOf(",", firstPos+1); //$GPVTG,279.67,T,,M,4.903,N,9.080,K,A*3F -- go to 9.080
    delay(1); 
  }
  firstPos = firstPos + 1; //skip the comma that is infront of 9.080
  lastPos = firstPos;
  for(i=0; i < 2; i++) //go to the comma after K
  {
    lastPos = rawLatLong.indexOf(",", lastPos+1);
    delay(1);
  }
  return rawLatLong.substring(firstPos,lastPos);
}


String getLatLong(String rawLatLong)
{
  int firstPos = 0, lastPos = 0, i, degree;
  char latLong[5][32], buff[64];
  float latitude, longitude, minute;
  String temp;

  firstPos = rawLatLong.indexOf("$GPRMC,"); //same concept as in above ($GPVTG)
  for(i=0; i < 3; i++)
  {
    firstPos = rawLatLong.indexOf(",", firstPos+1);
    delay(1);
  }
  firstPos = firstPos + 1; //skip the comma -- same concept as in above ($GPVTG)
  lastPos = firstPos;
  for(i=0; i < 4; i++)
  {
    lastPos = rawLatLong.indexOf(",", lastPos+1);
    delay(1);
  }
  
  temp = rawLatLong.substring(firstPos,lastPos); delay(1); // delay(1) need to checked if necessary or not. 
  temp.toCharArray(buff,64); delay(1); // delay(1) need to checked if necessary or not.
  explodeString(",",buff,latLong); delay(1);  // delay(1) need to checked if necessary or not.
  //at this point latLong must have all the elemnts in consequetive array
  //convert the values in position 0 and 2
  //fist check if the values at those positions are valid or not
  if(strlen(latLong[0]) && strlen(latLong[2])) //convert to decimal format from degree, minute
  {
    latitude = atof(latLong[0]);
    longitude = atof(latLong[2]);
    latitude = latitude / 100;
    longitude = longitude / 100;

    degree = (int)latitude;
    minute = latitude - degree;
    minute = minute * 100;
    latitude = degree + (minute/60);

    degree = (int)longitude;
    minute = longitude - degree;
    minute = minute * 100;
    longitude = degree + (minute/60);

    delay(1); //need to check if needed
    //Serial.println(String(latitude,6)+","+latLong[1]+","+String(longitude)+","+latLong[3]);
    return (String(latitude,6)+","+latLong[1]+","+String(longitude,6)+","+latLong[3]); //String(latitude,6) the second parameter to string sets the precision after decimal. 

    
  }
  else
  {
    return String("Yet to get a fix");
  }
  
}

void writeSettings(int addr, char *toWrite)
{
  int i;
  for(i=0; i<9; i++)
  {
    EEPROM.write((addr+i), toWrite[i]);
  }
  EEPROM.commit();
}

void readSettings(int addr, char *toRead) // will have to change this function - need to make it such t
{
  int i;
  for(i=0; i<9; i++)
  {
    toRead[i] = EEPROM.read((addr+i));
  }
  toRead[i] = '\0';
}

void setupWiFi()
{
  WiFi.mode(WIFI_AP);

  // Do a little work to get a unique-ish name. Append the
  // last two bytes of the MAC (HEX'd) to "Thing-":
  uint8_t mac[WL_MAC_ADDR_LENGTH];
  WiFi.softAPmacAddress(mac);
  String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
                 String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
  macID.toUpperCase();
  String AP_NameString = "GPS Tracker " + macID;

  char AP_NameChar[AP_NameString.length() + 1];
  memset(AP_NameChar, 0, AP_NameString.length() + 1);

  for (int i=0; i<AP_NameString.length(); i++)
    AP_NameChar[i] = AP_NameString.charAt(i);

  WiFi.softAP(AP_NameChar, WiFiAPPSK);

  resetWifiFlag = 0; //look in loop for explanation
}


void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  EEPROM.begin(64); //initiate 64 bytes to write/read
  //gps.begin(9600);
 
  readSettings(addr+0, hashedPass); //read the saved pass at addr+0 location
  if(strlen(hashedPass) == 8) //id the saved password is of proper length then decode it and use it.
    decodePass(savedPass, hashedPass);
    
  strcpy(WiFiAPPSK,savedPass); //set the Wifi Password also
  setupWiFi(); //start the wifi
  
  server.begin();
}

void loop() 
{
  //check if any variable is redundant
  volatile unsigned long startTime, currentTime;
  String serialBuffer, latLong;
  int pos,flag,i,j,temp;
  short int passError = 1, len, latLongFlag = 0, speedFlag = 0;
  char serialDataByte;

  if(resetWifiFlag == 1) // if the password is changed then this will be called to re-initialize the WIFI-AP with the new password
   {
      setupWiFi();
   }
  
  //start the webserver and send the data
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) 
  {
    delay(1);
    return;
  }
  else
  {
    delay(1);

    //Read the first line of the request
    String req = client.readStringUntil('\r');

    //now check if password change requested or not
    pos = req.indexOf("/changepass/");
    if(pos != -1)
    {
      //get the new pass
      len = pos+12+8; //12 chars of /changepass/ AND 8 of password
      for(i=pos+12,j=0; i<len; i++,j++)
      {
        if(req.charAt(i) == '/')
          break;
        else
          hashedPass[j] = req.charAt(i);
      }
      hashedPass[j] = '\0';
      decodePass(suppliedPass, hashedPass);
      strcpy(savedPass,suppliedPass);
      //save the password
      //Serial.println("New Pass: "+ String(hashedPass));
      writeSettings(addr+0, hashedPass); //save the password

      //not calling a function for sending the data to save the function call overhead.
      // Prepare the response. Start with the common header:
      String s = "HTTP/1.1 200 OK\r\n";
      s += "Content-Type: application/json\r\n\r\n";
      s += "{"succcess":"Password Changed To: "+ String(suppliedPass)+""}";
      // Send the response to the client
      client.print(s);
      client.flush();
      delay(1);
      client.stop();
      //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
      //AS THE restart method is not available so setting up the wifi again with the new password
      strcpy(WiFiAPPSK,suppliedPass); //set the Wifi Password also
      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()
      delay(1); //safe side
      return;
    }

    pos = req.indexOf("/pass/");
    if(pos == -1) // that means no password supplied
    {
      //not calling a function for sending the data to save the function call overhead.
      client.flush();
      // Prepare the response. Start with the common header:
      String s = "HTTP/1.1 200 OK\r\n";
      s += "Content-Type: application/json\r\n\r\n";
      s += "{"error":"Auhentication Error 1"}";
      // Send the response to the client
      client.print(s);
      client.flush();
      delay(1);
      client.stop();
      return;
    }
    else
    {
      //Serial.println("Client Connected");
      //read upto the next slash
      len = pos+6+8; //6 chars of /changepass/ AND 8 of password
      for(i=pos+6,j=0; i<len; i++,j++)
      {
        if(req.charAt(i) == '/')
          break;
        else
          hashedPass[j] = req.charAt(i);
      }
      hashedPass[j] = '\0';
      
      //now decode the pass 
      decodePass(suppliedPass, hashedPass);
      if(strcmp(suppliedPass,savedPass))
      {
        //not calling a function for sending the data to save the function call overhead.
        client.flush();
        // Prepare the response. Start with the common header:
        String s = "HTTP/1.1 200 OK\r\n";
        s += "Content-Type: application/json\r\n\r\n";
        s += "{"error":"Auhentication Error 2"}";
        // Send the response to the client
        client.print(s);
        client.flush();
        delay(1);
        client.stop();
        return;
      }
    }
   
    startTime = currentTime = 0;
    serialBuffer = latLong = "";
  
    flag = -1;
    
    startTime = millis();
    
    // put your main code here, to run repeatedly:
    while(flag == -1)  //read 5 seconds of data
    {
      if(Serial.available() > 0)
      {
        serialBuffer += (char)Serial.read();
        if(serialBuffer.indexOf("$GPRMC,") >=0)
        {

          while(1)
          {
            serialDataByte = (char)Serial.read();
            if(serialDataByte == '\r' || serialDataByte == '$') //need to optimize - check if \r is sufficient
            {
              latLong = getLatLong(serialBuffer);
              serialBuffer = serialDataByte; //reset the serial buffer for the next line
              break;
            }
            else
            {
              serialBuffer += serialDataByte;
            }
            delay(1);
          }
        }

        if(serialBuffer.indexOf("$GPVTG,") >=0)
        {
          while(1)
          {
            serialDataByte = (char)Serial.read();
            if(serialDataByte == '\r' || serialDataByte == '$') //need to optimize - check if \r is sufficient
            {
              flag = 1;
              latLong = latLong + "," + getSpeed(serialBuffer);
              latLong = "{"success":""+latLong+""}";
              break;
            }
            else
            {
              serialBuffer += serialDataByte;
            }
            delay(1);
          }
        }
      }

      if(millis()- startTime > 5000)
      {
        //Serial.println("TimeOut");
        latLong = "Timeout"; 
        latLong = "{"error":""+latLong+""}";
        latLongFlag = speedFlag = 0;
        break;
      }
      delay(1);
    } 
    //Serial.println("LN: "+latLong);
  }

  client.flush();
  // Prepare the response. Start with the common header:
  String s = "HTTP/1.1 200 OK\r\n";
  s += "Content-Type: application/json\r\n\r\n";
  //s += "<!DOCTYPE HTML>\r\n<html>\r\n<body>\r\n";
  s += latLong;
  //s += "</body>\r\n</html>\n";
  // Send the response to the client
  client.print(s);
  client.flush();
  //delay(100); Serial.println("Client disonnected");
  latLongFlag = speedFlag = 0;  
  delay(1);
  client.stop();
}

 

Notes:

  • The setupWifi code is from Sparkfun’s code
  • The Software Serial is causing trouble. The WiFi Access Point (AP) is dying after sometime if the Software Serial Library is used.
  • The delays are needed to allow the ESP8266 to do it’s own internal tasks (like maintaining the wifi connection). The delays are needed where there can be long loops.

ESP8266 Programming Using Arduino IDE

The ESP8266 can be programmed using the Arduino IDE. The best part is the codes are similar to Arduino. To start programming a ESP8266 using Arduino IDE follow the below steps

Prerequisites

Steps

  • Start Arduino and goto File-> Preferences.
  • In the “Additional Boards Manager URLs” Enter http://arduino.esp8266.com/stable/package_esp8266com_index.json  (You can add multiple URLs, separating them with commas)
  • Click “OK”
  • Open Boards Manager from Tools -> Board menu and find esp8266 platform.
  • Select the version you need from drop-down box.
  • Click install button.
  • ——————————————–
  • Upload a blank sketch to the Arduino.
  • Connect RX to RX and TX to TX
  • GPIO_0 will go to GND
  • VCC and CH_PD will go to the 3.3v supply line
  • Select the appropriate ESP8266 board from Tools > Board menu.
  • Select the appropriate Flash mode (DOUT or QIO. See notes below)
  • Other parameters works mostly as it is – but still check once.
  • Start upload
  • RESET the module. This is a critical step and the timing matters. It may need a few tries to get it perfect.

After the code uploaded

  • Disconnect GPIO_0
  • Reset

 

For further details please check http://esp8266.github.io/Arduino/versions/2.3.0/

Please see this article for a basic code (Blinking LED that is the Hello World of micro-controllers)

Notes

  • While uploading codes through Arduino IDE select DOUT for new chip and either DOUT or QIO for old chips.
  • Keeping it to DOUT will work for both New and Old chips.
  • Burning new chips with QIO (or inappropriate modes) will result in a successful burning but the code will not run.

 

Here is a Troubleshooting Guide and parameters that worked for me.

Flashing guide for new chips.

ESP 8266 – ESP-12E Hello World – Blinking LED

We are using Arduino IDE to program our ESP8266. Please see this article regarding how to setup the Arduino IDE for programming ESP8266.

Here is a blinking LED code for ESP8266 written in Arduino IDE.

#define ESP8266_LED 5 
void setup() 
{   
   pinMode(ESP8266_LED, OUTPUT); 
} 
void loop() 
{   
   digitalWrite(ESP8266_LED, HIGH);   
   delay(500);   
   digitalWrite(ESP8266_LED, LOW);   
   delay(500); 
}

Instructions:

  • Connect a LED (with a resistor in series) to an I/O pin of your ESP8266. Change the pin number to an appropriate one in the first line of the code.
  • Select the appropriate ESP Board/Version fromthe Boards Menu of the Arduino IDE. If your board is not listed then you can select Generic and then set the parameters according to the chip or module version (ESP-01, ESP-06, ESP-12E etc) you are using.
  • Upload the code to the module.
  • The LED should be blinking now.

 

Connect Arduino and BMP 180 to Cloud

BMP 180 connect to Cloud

 

BMP-180

  1. SCL – Grey wire
  2. SDA – Orange Wire

 

Notes:

  • Here the hardware TX and RX has been used for performance.

 

The code:

See Arduino – Communicate with Server – Part 1

Updated code will be posted here some time soon.

For more details on ESP 8266 please see the article “https://www.kolkataonweb.com/code-bank/arduino/esp8266-esp-01/

ESP8266 ESP-01 – Part 2 – Useful AT Commands And Their Outputs

Below are some AT commands for ESP8266 and their outputs

AT
OK
AT+GMR
This will display firmware version and some other details 
AT+CIPMUX=1 
OK
AT+CWMODE=3 
OK
AT+CWJAP="WIRELESS-ROUTER","password"
[WIFI DISCONNECTED] (if it is already connected)
WIFI CONNECTED
WIFI GOT IP
OK
AT+CIPSTART=4,"TCP","x.x.x.x",80
4,CONNECT
OK
AT+CIPSEND=4,205
OK
> [at this point HTTP request will be made, read below for details]
Recv 205 bytes
SEND OK
+IPD,4,203:HTTP/1.1 200 OK
Date: Sun, 14 Feb 2016 20:33:16 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.14
Content-Length: 15
Connection: close
Content-Type: text/html

led_1=0|led_2=14,CLOSED

[The blue colored text above is what the server has sent in reply to the HTTP request]
AT+UART_CUR=2400,8,1,0,0
OK

[This command work with AT ver 6.0 and SDK ver 1.5.2. The changes will be temporary and will be restored to default on resetting. Use ]
AT+UART_DEF=2400,8,1,0,0

[This will make the change permanent. In case things gets wrong then reflash]

If AT+UART doesn't work then use 
AT+IPR

 

An extensive guide can be found here
https://github.com/espressif/ESP8266_AT/wiki/CWSAP

https://docs.espressif.com/projects/esp-at/en/latest/AT_Command_Set/Basic_AT_Commands.html

 

ESP8266 ESP-01 – Part 1 – Flashing and AT commands

This article is about the one that looks like this (aka ESP-01).

esp8266-esp-01-wifi-module-for-iot

 

Flasher version is 2.3
Firmware version is 1.5

Firmware update might be necessary just after purchase. Without firmware update mine was not able to connect to Wi-fi routers (though they were able to find them)

The current firmware available for this is “ESP8266_AT_v0.51”. The direct link to the download http://bbs.espressif.com/viewtopic.php?f=46&t=1451 . The download is at the bottom of the page as an Attachment.

firware files and readme

The flasher (for flashing firmware) can be found here http://bbs.espressif.com/viewtopic.php?f=57&t=433. The .rar version contains the necessary files to update the firmware.

WARNING: read the readme file that came with the firmware.

esp8266-flasher

Please note New chips need DOUT specifically, whereas old ones work with both QIO and DOUT

 Latest Flasher and Firmware Downloads (6th Feb, 2016):

 

Pin configuration of the module

esp8266 - pin

IMPORTANT NOTES:

  • This board runs on 3.3v
  • The default Baud rate is 115200
  • Boot errors are output over 74800. This is default and fixed.
  • For the RX TX line voltage divider using resistors doesn’t work. Using a 150 ohms in series for now, waiting for my Logic Level converter. But then so far (many years now) direct connection didn’t damage the ESP-01.

 

Flashing

  1. Used an Arduino Uno to flash the firmware.
  2. Upload a blank sketch to the Arduino.
  3. The module’s RX will go to Arduino RX and similarly TX will go TX.
  4. GPIO_0 will go to GND
  5. VCC and CH_PD will go to the 3.3v supply line
  6. Load the flasher
  7. Mine one came with “Ai-Cloud insid8” written. This module has a Flash size of 8Mbit: 512KB+512KB. QuadIO and 26MHZ crystal.
  8. Select the appropriate files in the “Download Path Config” section in the flasher tool. Some of the addresses might also need to be adjusted. READ the readme file that came with the firmware.
  9. Select the COM port on which Arduino is connected and the set the Baud rate to 115200 (the default of this board)
  10. Press start. If all goes well it will show finish to the left of the “Start” and “Stop” button
  11. If it fails – press “Stop”. Reset the board by Grounding RESET pin. And press Start again
  12. If the flashing is going on properly then the TX light of Arduino and the Blue light of the module will flash.
  13. Once firmware has been flashed disconnect the GPIO_0 pin from GND. Reset the module and start working

Useful links:
http://www.electrodragon.com/w/Category:ESP8266_Firmware_and_SDK

 

AT Commands

  1. Used Arduino Serial monitor for sending AT commands to the Module.
  2. The RX and TX pin configuration will remain same as above.
  3. Start with the AT command.
  4. List of some useful AT commands : http://www.pridopia.co.uk/pi-doc/ESP8266ATCommandsSet.pdf

 

Notes

  • After flashing the default baud rate becomes 115200. And also the CWMODE might need to be changed to 1 or 3 manually (mine somehow went to mode 2 that is AP mode)
  • If the RTOS firmware is flashed then the “user1.1024.new.2.bin” file inside the AT directory cannot be flashed – it makes the chip non-responsive.
  • The required files for RTOS firmware comes in the zip file named “AT_V0.60_on_ESP8266_NONOS_SDK_V1.5.2_20160203” and is inside “noboot” folder.

 

Updated version of this here: https://www.kolkataonweb.com/code-bank/arduino/esp-01-burning-at-rom-new-and-updated/