-->
Page 1 of 1

ESP8266 Google Cloud Messaging Notification Android/iOS

PostPosted: Fri Mar 11, 2016 12:02 am
by Vicky Arora
Hello everyone!
I am pretty new here and this is my first post.

My Goal:
Send a PUSH notification to users on Android/iOS devices through ESP

Environment:
Arduino Sketch

Code Used:

https://github.com/beegee-tokyo/GCM-ESP8266/wiki - Thank you BeeGee for the code!
Well documented, so please have a look at the link. I did change few things which are reflected in the two files below
[list=]gcm_esp.ino
gcm_esp_test.ino[/list]

1. gcm_esp.ino
Code: Select all   // Embedded System + GCM

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <FS.h>

//   /** Google API key */
const String API_key = "MyGCM_APIKey";

// Serial Output
#define DEBUG_OUT
   
/** Google Cloud Messaging server address */
char serverName[] = "http://android.googleapis.com";
/** Google Cloud Messaging host */
String hostName = "android.googleapis.com";
/** WiFiClient class to communicate with GCM server */

const int httpPort = 80;
WiFiClient gcmClient;
/** Reason of failure of received command */
String failReason = "unknown";

/** Array to hold the registered Android device IDs (max 5 devices, extend if needed)*/
#define MAX_DEVICE_NUM 1
String regAndroidIds[MAX_DEVICE_NUM];
/** Number of registered devices */
byte regDevNum = 1; // CHANGED TO TEST
/**
   writeRegIds
   writes regAndroidIds[] to file gcm.txt as JSON object
   returns true if successful, false if file error
*/
boolean writeRegIds() {
  //============================================
  Serial.println("1");
   #ifdef DEBUG_OUT
   Serial.println("===========================================");
   Serial.println("writeRegIds");
   Serial.println("===========================================");
   #endif
   
   // First check if the file system is mounted and working
   FSInfo fs_info;
   if (!SPIFFS.info(fs_info)) {
      // Problem with the file system
      #ifdef DEBUG_OUT
      Serial.println("File system error");
      #endif
      failReason = "File system error";
      return false;
   }

   // Open config file for writing.
   File devicesFile = SPIFFS.open("/gcm.txt", "w");
  Serial.println("Post Open for Write");
   if (!devicesFile) {
      #ifdef DEBUG_OUT
   
      Serial.println("Failed to open gcm.txt for writing");
      #endif
      failReason = "Failed to open gcm.txt for writing";
      return false;
   }
   // Create new device ids as JSON
   DynamicJsonBuffer jsonBuffer;

   // Prepare JSON object
   JsonObject& regIdJSON = jsonBuffer.createObject();
 
 Serial.println("Pre loop check for regDevNum");
 
   // Add existing devices to JSON object (if any)
   for (int i=0; i<regDevNum; i++) {
    Serial.println("Test");
    regAndroidIds[0] = "OneOfMyRegDeviceID"; // MANUALLY ENTERED THE DEVICE ID HERE REMOVING THE ORIGINAL LOOP TO TEST
      regIdJSON[String(0)] = regAndroidIds[0];
      Serial.println(regAndroidIds[0]);
      //regAndroidIds[i]
   }
   
   // Convert JSON object to String
   String jsonTxt;
   regIdJSON.printTo(jsonTxt);

   #ifdef DEBUG_OUT
   Serial.println("New list of registered IDs: " + jsonTxt);
   #endif
   
   // Save status to file
   devicesFile.println(jsonTxt);
   devicesFile.close();
   return true;
}
/**
   getRegisteredDevices
   reads registered device IDs from file gcm.txt
   saves found devices in global variable regAndroidIds[]
   sets global variable regDevNum to number of devices found
   returns true if successful, false if file error or JSON parse error occured
*/
boolean getRegisteredDevices() {
   //============================================
 
  Serial.println("2");
   #ifdef DEBUG_OUT
   Serial.println("===========================================");
   Serial.println("getRegisteredDevices");
  writeRegIds();
   Serial.println("===========================================");
   #endif
 
   // First check if the file system is mounted and working
   FSInfo fs_info;
   if (!SPIFFS.info(fs_info)) {
      // Problem with the file system
      #ifdef DEBUG_OUT
      Serial.println("File system error");
      #endif
      failReason = "File system error";
      return false;
   }
   // Then get registered devices from the files
   // open file for reading.
 
   File devicesFile = SPIFFS.open("/gcm.txt", "r");
 
   if (devicesFile) // Found file
   {
 
      // Read content from config file.
      String content = devicesFile.readString();
      devicesFile.close();
   
      // Convert file content into JSON object
      DynamicJsonBuffer jsonBuffer;
      JsonObject& regIdJSON = jsonBuffer.parseObject(content);
      if (regIdJSON.success()) // Found some entries
      {
         regDevNum = 0;
         for (int i=0; i<MAX_DEVICE_NUM; i++) {
            if (regIdJSON.containsKey(String(i))) { // Found an entry
               regAndroidIds[i] = regIdJSON[String(i)].asString();
               regDevNum++;
               #ifdef DEBUG_OUT
               Serial.println("Found: " + regAndroidIds[i]);
               #endif
            }
         }
         #ifdef DEBUG_OUT
         Serial.println("Found: " + String(regDevNum) + " devices");
         #endif
         return true;
      } else { // File content is not a JSON string
         #ifdef DEBUG_OUT
         Serial.println("File content is not a JSON string");
         #endif
         failReason = "File content is not a JSON string";
         return false;
      }
   } else { // File not found -  not an error, just no registered IDs yet
      regDevNum = 0;
      #ifdef DEBUG_OUT
      Serial.println("File does not exist");
      #endif
      failReason = "File does not exist";
      return true;
   }
}

/**
   addRegisteredDevice
   adds a new device to the file gcm.txt
   input String new device ID
   returns true if successful, false if a file error occured or ID is invalid
*/
boolean addRegisteredDevice(String newDeviceID) {
  //============================================
  Serial.println("3");
 
  Serial.println("TestBefore");
    Serial.println(regAndroidIds[0]);
   #ifdef DEBUG_OUT
   Serial.println("===========================================");
 
   Serial.println("addRegisteredDevice");
   Serial.println("===========================================");
   #endif
   // Basic check if newDeviceID is valid
   if (newDeviceID.length() != 140) {
      #ifdef DEBUG_OUT
      Serial.println("Invalid device id");
      #endif
      failReason = "Invalid device id";
      return false;
   }
   // First get registered devices from the files
   if (!getRegisteredDevices) {
      #ifdef DEBUG_OUT
      Serial.println("Error reading registered devices");
      #endif
      return false;
   }

   // Number of devices < MAX_DEVICE_NUM ???
   if (regDevNum == MAX_DEVICE_NUM) {
      #ifdef DEBUG_OUT
      Serial.println("Maximum number of devices registered");
      Serial.println("Delete another device before adding new one");
      #endif
      failReason = "Maximum number of devices registered";
      return false;
   }

   // Check if id is already in the list
   for (int i=0; i<regDevNum; i++) {
      if (regAndroidIds[i] == newDeviceID) {
         #ifdef DEBUG_OUT
         Serial.println("Devices already registered");
         #endif
         failReason = "Devices already registered";
         return false;
      }
   }

   // Add new ID to regAndroidIds[]
   regDevNum += 1;
   regAndroidIds[regDevNum-1] = newDeviceID;
   
   if (writeRegIds()) {
      #ifdef DEBUG_OUT
      Serial.println("Successful added id: " + newDeviceID);
      #endif
      // Refresh list with registered devices
      getRegisteredDevices();
      return true;
   } else {
      #ifdef DEBUG_OUT
      Serial.println("Failed to added id: " + newDeviceID);
      #endif
      // Refresh list with registered devices
      getRegisteredDevices();
      return false;
   }
}

/**
   delRegisteredDevice
   deletes all registration ida from the list
   returns true if successful, false if a file error occured
*/
boolean delRegisteredDevice() {
  //============================================
  Serial.println("4");
   #ifdef DEBUG_OUT Serial.println("===========================================");
   Serial.println("delRegisteredDevice");
   Serial.println("===========================================");
   #endif

   // First get registered devices from the files
   if (!getRegisteredDevices) {
      #ifdef DEBUG_OUT
      Serial.println("Error reading registered devices");
      #endif
      return false;
   }

   #ifdef DEBUG_OUT
   Serial.println("Trying to delete all ids");
   #endif
   if (SPIFFS.remove("/gcm.txt")) {
      #ifdef DEBUG_OUT
      Serial.println("All registered device ids deleted");
      #endif
      regDevNum = 0;
      return true;
   } else {
      #ifdef DEBUG_OUT
      Serial.println("Error while deleting registration file");
      #endif
      failReason = "Error while deleting registration file";
      return false;
   }
   return false;
}

/**
   delRegisteredDevice
   deletes a registration id from the list
   delRegId => registration id to be deleted. delAll must be false & delRegIndex must be 9999!!!!
   returns true if successful, false if a file error occured or ID is invalid or not registered
*/
boolean delRegisteredDevice(String delRegId) {
   //============================================
  Serial.println("5");
   int delRegIndex;
   #ifdef DEBUG_OUT Serial.println("===========================================");
   Serial.println("delRegisteredDevice");
   Serial.println("===========================================");
   #endif

   // First get registered devices from the files
   if (!getRegisteredDevices) {
      #ifdef DEBUG_OUT
      Serial.println("Error reading registered devices");
      #endif
      return false;
   }

   #ifdef DEBUG_OUT
   Serial.println("Trying to delete id: " + delRegId);
   #endif
   // Search for id entry
   boolean foundIt = false;
   for (int i=0; i<regDevNum; i++) {
      if (regAndroidIds[i] == delRegId) {
         foundIt = true;
         delRegIndex = i;
         break;
      }
   }
   if (foundIt) {
      // delete id entry
      regAndroidIds[delRegIndex] = "";
      for (int i=delRegIndex; i<regDevNum-1; i++) {
         // Shift other ids
         regAndroidIds[i] = regAndroidIds[i+1];
      }
      regDevNum -= 1;
      if (!writeRegIds()) {
         #ifdef DEBUG_OUT
         Serial.println("Could not save registered ids");
         #endif
         return false;
      } else {
         #ifdef DEBUG_OUT
         Serial.println("Successful deleted id: " + delRegId);
         #endif
         return true;
      }
   } else {
      #ifdef DEBUG_OUT
      Serial.println("Could not find registration id " + delRegId);
      #endif
      failReason = "Could not find registration id " + delRegId;
      return false;
   }
   return false;
}

/**
   delRegisteredDevice
   deletes a registration id from the list
   delRegIndex => index of id to be deleted
   returns true if successful, false if a file error occured or index is invalid
*/
boolean delRegisteredDevice(int delRegIndex) {
   //============================================
  Serial.println("6");
   #ifdef DEBUG_OUT Serial.println("===========================================");
   Serial.println("delRegisteredDevice");
   Serial.println("===========================================");
   #endif

   // First get registered devices from the files
   if (!getRegisteredDevices) {
      #ifdef DEBUG_OUT
      Serial.println("Error reading registered devices");
      #endif
      return false;
   }

   #ifdef DEBUG_OUT
   Serial.println("Trying to delete id with index: " + String(delRegIndex));
   #endif
   // delete id entry
   String delRegId = regAndroidIds[delRegIndex];
   regAndroidIds[delRegIndex] = "";
   for (int i=delRegIndex; i<regDevNum-1; i++) {
      // Shift other ids
      regAndroidIds[i] = regAndroidIds[i+1];
   }
   regDevNum -= 1;
   if (!writeRegIds()) {
      #ifdef DEBUG_OUT
      Serial.println("Could not save registered ids");
      #endif
      return false;
   } else {
      #ifdef DEBUG_OUT
      Serial.println("Successful deleted id: " + delRegId);
      #endif
      return true;
   }
   return false;
}

/**
   gcmSendOut
   sends message to https://android.googleapis.com/gcm/send to
      request a push notification to registered Android devices
   data - String with the Json object containing the reg IDs and data
   returns true if successful, false if an error occured
*/
boolean gcmSendOut(String data) {
  //============================================
  Serial.println("7");
   gcmClient.stop(); // Just to be sure
   #ifdef DEBUG_OUT
   Serial.print("Connecting to ");
   Serial.println(serverName);
   #endif
   String resultJSON; // For later use
   Serial.println("Pre connect server");

 
   if (gcmClient.connect(serverName, httpPort)) {
    Serial.println("Post connect server");
      #ifdef DEBUG_OUT
      Serial.println("Connected to GCM server");
      #endif
      
      String postStr = "POST /gcm/send HTTP/1.1\r\n";
      postStr += "Host: " + hostName + "\r\n";
      postStr += "Accept: */";
      postStr += "*\r\n";
      postStr += "Authorization: key=" + API_key + "\r\n"; // Here the application specific API key is inserted
      postStr += "Content-Type: application/json\r\n";
      postStr += "Content-Length: ";
      postStr += String(data.length());
      postStr += "\r\n\r\n";
      postStr += data; // Here the Json object with the IDs and data is inserted
      postStr += "\r\n\r\n";
      
      #ifdef DEBUG_OUT
      Serial.print("This is the Request to ");
      Serial.print(serverName);
      Serial.println(" :");
      Serial.println(postStr);
      #endif
      gcmClient.println(postStr); // Here we send the complete POST request to the GCM server
   
      // Get response from GCM server
      #ifdef DEBUG_OUT
      Serial.println("Response from GCM server:");
      #endif
      String inString = "";
      while (gcmClient.available())
      {
         char inChar = gcmClient.read();
         inString += (char)inChar;
      }
      if (inString.indexOf("200 OK") >= 0) {
         int startOfJSON = inString.indexOf("{\"multicast_id");
         int endOfJSON = inString.indexOf("}]}");
         resultJSON = inString.substring(startOfJSON,endOfJSON+3);
         #ifdef DEBUG_OUT
         Serial.println("Found JSON result: " + resultJSON);
         #endif
         failReason = "success";
      } else {
         #ifdef DEBUG_OUT
         Serial.println("Didn't find 200 OK");
         #endif
         failReason = "Sending not successful";
      }
      gcmClient.stop();
   } else {
      #ifdef DEBUG_OUT
      Serial.println("Connection to GCM server failed!");
      #endif
      failReason = "Connection to GCM server failed!";
   }

   if (failReason != "success") {
      failReason = resultJSON;
      return false;
   } else {
      failReason = resultJSON;
      return true;
   }
}

/**
   gcmSendMsg
   prepares the JSON object holding the registration IDs and data
   calls gcmSendOut to forward the request to the GCM server
   pushMessageIds - Json array with the keys (aka names) of the messages
   pushMessages - Json array with the messages
      a message can be any type of variable:
      boolean, char, integer, long, float, string, ...
   returns true if successful, false if an error occured
*/
boolean gcmSendMsg(JsonArray& pushMessageIds, JsonArray& pushMessages) {
   //============================================
  Serial.println("8");
   #ifdef DEBUG_OUT
   Serial.println("===========================================");
   Serial.println("gcmSendMsg - JsonArrays");
   Serial.println("===========================================");
   #endif
   
   // Update list of registered devices
   getRegisteredDevices();

   if (regDevNum == 0) { // Any devices already registered?
      #ifdef DEBUG_OUT
      Serial.println("No registered devices");
      #endif
      failReason = "No registered devices";
      return false;
   }
   
   if (pushMessageIds.size() != pushMessages.size()) {
      #ifdef DEBUG_OUT
      Serial.println("Different number of keys and messages");
      #endif
      failReason = "Different number of keys and messages";
      return false;
   }
   
   int numData = pushMessageIds.size();

   String data;
   // Create JSON object with registration_ids and data
   if (numData != 0) {
      DynamicJsonBuffer jsonBuffer;
      DynamicJsonBuffer jsonDataBuffer;

      // Prepare JSON object
      JsonObject& msgJSON = jsonBuffer.createObject();
      // Add registration ids to JsonArray regIdArray in the JsonObject msgJSON
      JsonArray& regIdArray = msgJSON.createNestedArray("registration_ids");
      for (int i=0; i<regDevNum; i++) {
         regIdArray.add(regAndroidIds[i]);
      }
      // Add message keys and messages to JsonObject dataArray
      JsonObject& dataArray = jsonDataBuffer.createObject();
      for (int i=0; i<numData; i++) {
         String keyStr = pushMessageIds.get(i);
         dataArray[keyStr] = pushMessages.get(i);
      }
      // Add JsonObject dataArray to JsonObject msgJSON
      msgJSON["data"] = dataArray;
      msgJSON.printTo(data);
   } else { // No data to send
      #ifdef DEBUG_OUT
      Serial.println("No data to send");
      #endif
      failReason = "No data to send";
      return false;
   }
   
   return gcmSendOut(data);
}

/**
   gcmSendMsg
   prepares the JSON object holding the registration IDs and data
   calls gcmSendOut to forward the request to the GCM server
   pushMessages - Json object with the data for the push notification
   returns true if successful, false if an error occured
*/
boolean gcmSendMsg(JsonObject& pushMessages) {
   //============================================
  Serial.println("9");
   #ifdef DEBUG_OUT
   Serial.println("===========================================");
   Serial.println("gcmSendMsg - JsonObject");
   Serial.println("===========================================");
   #endif
   
   // Update list of registered devices
   getRegisteredDevices();

   if (regDevNum == 0) { // Any devices already registered?
      #ifdef DEBUG_OUT
      Serial.println("No registered devices");
      #endif
      failReason = "No registered devices";
      return false;
   }
   
   String data;
   // Create JSON object with registration_ids and data
   DynamicJsonBuffer jsonBuffer;
   DynamicJsonBuffer jsonDataBuffer;

   // Prepare JSON object
   JsonObject& msgJSON = jsonBuffer.createObject();
   // Add registration ids to JsonArray regIdArray in the JsonObject msgJSON
   JsonArray& regIdArray = msgJSON.createNestedArray("registration_ids");
   for (int i=0; i<regDevNum; i++) {
      regIdArray.add(regAndroidIds[i]);
   }
   // Add JsonObject pushMessages to JsonObject msgJSON
   msgJSON["data"] = pushMessages;
   msgJSON.printTo(data);
   
   return gcmSendOut(data);
}


2. gcm_esp_test.ino
Code: Select all/**
   Google Cloud Messaging tutorial
   part 2
   -> web server for receiving registrations from Android devices
      receive commands to maintain registration storage
      receive command to request push notification
   -> setup routine
   => main loop

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   To access the web server from outside your local LAN you need
   to setup a url and prepare your router/modem to make this IP
   accessible from the Internet
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/

/* Includes from libraties */
//#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <Ticker.h>

//   /** SSID of local WiFi network */
   const char* ssid = "MySSID";
//   /** Password for local WiFi network */
   const char* password = "MySSIDPassword";
 
/* REMARK: I use fixed IP address for the ESP8266 module, not the DHCP function */
/** IP address of this module */
IPAddress ipAddr(xxx,xxx,x,x); // REPLACE WITH THE IP ADDRESS YOU WANT TO APPLY
/** Gateway address of WiFi access point */
IPAddress ipGateWay(xxx, xxx, x, x); // REPLACE WITH THE GATEWAY ADDRESS OF YOUR WIFI AP
/** Network mask of the local lan */
IPAddress ipSubNet(255, 255, 255, 0); // SHOULD WORK WITH MOST WIFI LANs

/** WiFiServer class to create simple web server */
WiFiServer server(80);

/** Timer for flashing blue communication LED */
Ticker comFlasher;
/** Timer for sending a push request to GCM every minute */
Ticker pushTrigger;
/** Flag for push request */
boolean doPush = false;

/** Blue LED on GPIO2 for communication activities (valid only for Adadfruit HUZZAH ESP8266 breakout) */
#define comLED 2

/** Just for testing, counter to be send as message */
int msgCnt = 0;

/* ===CODE_STARTS_HERE========================================== */
/**
   blueLedFlash
   called by Ticker comFlasher
   change status of led on each call
*/
void blueLedFlash() {
   int state = digitalRead(comLED);
   digitalWrite(comLED, !state);
}

/**
   triggerGCM
   called by Ticker pushTrigger
   sets flag doPush to true for handling in loop()
   will initiate a call to gcmSendMsg() from loop()
*/
void triggerGCM() {
//============================================
  Serial.println("B");
   doPush = true;

}


/**
   webServer
   receives commands from web client or Android device
   returns result as JSON string to the client
      "result":"success" ==> command successful
      "result":"timeout" ==> communication between client and server was interrupted
      "result":"invalid" ==> unknown command or invalid Android ID
      "result":"failed" ==> command unsuccessful because e.g. ID storage full, file error
      
   ===================
   Available commands:
   ===================
   -- Register a new id
      <url>/?regid=<android registration id> with length 140 letter, no leading/trailing <">
   -- List registered ids
      <url>/?l
   -- Delete all registered ids
      <url>/?da
   -- Delete specific registered id by 140 letter registration id
      <url>/?di=<android registration id> with length 140 letter, no leading/trailing <">
   -- Delete specific registered index
      <url>/?dx=<index>
   -- Send broadcast message to all registered devices
      <url>/?s={"msgkeys":["key1","key2"],"msgs":["msg1","msg2"]}
   =========
   Examples:
   =========
 
   192.168.0.148/?l
      returns
      {"result":"success","0":"***ANDROID_REG_ID***","num":1}
   192.168.0.148/?regid=APA91bHq3iaH0UqYadNegxi5lP0Li0lvumQvvKJS7GxtT9P0zkU-...-S6EOpbS
      returns
      {"result":"success","0":"***ANDROID_REG_ID***","num":1}
   192.168.0.148/?da
      returns
      {"result":"success"}
   192.168.0.148/?s={"msgkeys":["message","timestamp"],"msgs":["Hello world","Christmas 2015"]}
      sends {"message":"Hello world","timestamp":"Christmas 2015"} to all registered devices
      returns      {"result":"success","response":"{\"multicast_id\":6404311408057644811,\"success\":3,\"failure\":0,\"canonical_ids\":0,\"results\":[{\"message_id\":\"0:1453965670295623%adf4b72ff9fd7ecd\"},{\"message_id\":\"0:1453965670295621%adf4b72ff9fd7ecd\"},{\"message_id\":\"0:1453965670295907%cbe2ca3ff9fd7ecd\"}]}"}
*/
void webServer(WiFiClient httpClient) {
   //============================================
  Serial.println("C");
   #ifdef DEBUG_OUT Serial.println("===========================================");
   Serial.println("webServer");
   Serial.println("===========================================");
   #endif
   comFlasher.attach(0.5, blueLedFlash);
   String s = "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json\r\n\r\n";
   int waitTimeOut = 0;

   DynamicJsonBuffer jsonBuffer;
   
   // Prepare json object for the response
   JsonObject& root = jsonBuffer.createObject();

   // Wait until the client sends some data
   while (!httpClient.available()) {
      delay(1);
      waitTimeOut++;
      if (waitTimeOut > 3000) { // If no response for 3 seconds return
         #ifdef DEBUG_OUT
         Serial.println("Timeout while waiting for data from client");
         #endif
         root["result"] = "timeout";
         root["reason"] = "Timeout while waiting for data from client";
         String jsonString;
         root.printTo(jsonString);
         s += jsonString;
         httpClient.print(s);
         httpClient.flush();
         httpClient.stop();
         comFlasher.detach();
         digitalWrite(comLED, HIGH); // Turn off LED
         return;
      }
   }

   root["result"] = "success";
   
   // Read the first line of the request
   String req = httpClient.readStringUntil('\r');
   #ifdef DEBUG_OUT
   Serial.println("Received: "+req);
   #endif
   req = req.substring(req.indexOf("/"),req.length()-9);
  Serial.println(req);
  Serial.println("Nice");
   #ifdef DEBUG_OUT
   Serial.println("Trimmed command = "+req);
   #endif
   // Registration of new device
   if (req.substring(0, 8) == "/?regid=") {
      String regID = req.substring(8,req.length());
   
      //Serial.println(regID);
      #ifdef DEBUG_OUT Serial.println("RegID: "+regID);
      Serial.println("Length: "+String(regID.length()));
      #endif
      // Check if length of ID is correct
      if (regID.length() != 140) {
         #ifdef DEBUG_OUT
         Serial.println("Length of ID is wrong");
         #endif
         root["result"] = "invalid";
         root["reason"] = "Length of ID is wrong";
      } else {
         // Try to save ID
         if (!addRegisteredDevice(regID)) {
            #ifdef DEBUG_OUT
            Serial.println("Failed to save ID");
            #endif
            root["result"] = "failed";
            root["reason"] = failReason;
         } else {
            #ifdef DEBUG_OUT
            Serial.println("Successful saved ID");
            #endif
            root["result"] = "success";
            getRegisteredDevices();
            for (int i=0; i<regDevNum; i++) {
               root[String(i)] = regAndroidIds[i];
            }
            root["num"] = regDevNum;
         }
      }
   // Send list of registered devices
   } else if (req.substring(0, 3) == "/?l"){
      if (getRegisteredDevices()) {
         if (regDevNum != 0) { // Any devices already registered?
            for (int i=0; i<regDevNum; i++) {
               root[String(i)] = regAndroidIds[i];
            }
         }
         root["num"] = regDevNum;
         root["result"] = "success";
      } else {
         root["result"] = "failed";
         root["reason"] = failReason;
      }
   // Delete one or all registered device
   } else if (req.substring(0, 3) == "/?d"){
      String delReq = req.substring(3,4);
      if (delReq == "a") { // Delete all registered devices
         if (delRegisteredDevice(true)) {
            root["result"] = "success";
         } else {
            root["result"] = "failed";
            root["reason"] = failReason;
         }
      } else if (delReq == "i") {
         String delRegId = req.substring(5,146);
         delRegId.trim();
         if (delRegisteredDevice(delRegId)) {
            root["result"] = "success";
         } else {
            root["result"] = "failed";
            root["reason"] = failReason;
         }
      } else if (delReq == "x") {
         int delRegIndex = req.substring(5,req.length()).toInt();
         if ((delRegIndex < 0) || (delRegIndex > MAX_DEVICE_NUM-1)) {
            root["result"] = "invalid";
            root["reason"] = "Index out of range";
         } else {
            if (delRegisteredDevice(delRegIndex)) {
               root["result"] = "success";
            } else {
               root["result"] = "failed";
               root["reason"] = failReason;
            }
         }
      }
      // Send list of registered devices
      if (getRegisteredDevices()) {
         if (regDevNum != 0) { // Any devices already registered?
            for (int i=0; i<regDevNum; i++) {
               root[String(i)] = regAndroidIds[i];
            }
         }
         root["num"] = regDevNum;
      }
   // Send broadcast message to all registered devices
   // Message must be a string in valid JSON format
   // e.g. {"msgkeys":["key1","key2"],"msgs":["msg1","msg2"]}
   } else if (req.substring(0, 3) == "/?s"){
      String jsonMsgs = req.substring(4,req.length());
      jsonMsgs.trim();
      jsonMsgs.replace("%22","\""); // " might have been replaced with %22 by the browser
      jsonMsgs.replace("%20"," "); // <space> might have been replaced with %22 by the browser
      jsonMsgs.replace("%27","'"); // ' might have been replaced with %22 by the browser
      #ifdef DEBUG_OUT
      Serial.println("Received = " + jsonMsgs);
      #endif
      // Convert message into JSON object
      DynamicJsonBuffer jsonBuffer;
      JsonObject& regJSON = jsonBuffer.parseObject(jsonMsgs);
      if (regJSON.success()) {// Found some entries
         root["result"] = "invalid";
         if (regJSON.containsKey("msgkeys")) {
            if (regJSON.containsKey("msgs")) {
               JsonArray& msgKeysJSON = regJSON["msgkeys"];
               JsonArray& msgsJSON = regJSON["msgs"];
               if (gcmSendMsg(msgKeysJSON, msgsJSON)) {
                  root["result"] = "success";
               } else {
                  root["response"] = failReason;
               }
            } else {
               root["reason"] = "JSON key msgs is missing";
            }
         } else {
            root["reason"] = "JSON key msgkeys is missing";
         }
      } else {
         root["result"] = "invalid";
         root["reason"] = "Invalid JSON message";
      }
   } else {
      root["result"] = "invalid";
      root["reason"] = "Invalid command";
   }
   
     String jsonString;
     root.printTo(jsonString);
     s += jsonString;
     httpClient.print(s);
     httpClient.flush();
     httpClient.stop();

   comFlasher.detach();
   digitalWrite(comLED, HIGH); // Turn off LED
}

/**
   setup
   Initialize application
   called once after reboot
*/
void setup() {
  //============================================
  Serial.println("D");
   pinMode(comLED, OUTPUT); // Communication LED blue
   digitalWrite(comLED, HIGH); // Turn off LED
   #ifdef DEBUG_OUT
   Serial.begin(115200);
   Serial.setDebugOutput(false);
   Serial.println("");
   Serial.println("====================");
   Serial.println("ESP8266 GCM test");
   #endif
   comFlasher.attach(0.5, blueLedFlash);
   WiFi.disconnect();
   WiFi.mode(WIFI_STA);
   WiFi.config(ipAddr, ipGateWay, ipSubNet);
   WiFi.begin(ssid, password);
   #ifdef DEBUG_OUT
   Serial.print("Waiting for WiFi connection ");
   #endif
   int connectTimeout = 0;
   while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      #ifdef DEBUG_OUT
      Serial.print(".");
      #endif
      connectTimeout++;
      if (connectTimeout > 60) { //Wait for 30 seconds (60 x 500 milliseconds) to reconnect
         pinMode(16, OUTPUT); // Connected to RST pin
         digitalWrite(16,LOW); // Initiate reset
         ESP.reset();
      }
   }
   comFlasher.detach();
   digitalWrite(comLED, HIGH); // Turn off LED

   #ifdef DEBUG_OUT
   Serial.println("");
   Serial.print("Connected to ");
   Serial.println(ssid);
   Serial.print("IP address: ");
   Serial.println(WiFi.localIP());

   byte mac[6];
   WiFi.macAddress(mac);
   String localMac = String(mac[0], HEX) + ":";
   localMac += String(mac[1], HEX) + ":";
   localMac += String(mac[2], HEX) + ":";
   localMac += String(mac[3], HEX) + ":";
   localMac += String(mac[4], HEX) + ":";
   localMac += String(mac[5], HEX);

   Serial.print("MAC address: ");
   Serial.println(localMac);

   Serial.print("Sketch size: ");
   Serial.print (ESP.getSketchSize());
   Serial.print(" - Free size: ");
   Serial.println(ESP.getFreeSketchSpace());
   Serial.println("====================");
   #endif

   // Initialize file system.
   if (!SPIFFS.begin())
   {
      #ifdef DEBUG_OUT
      Serial.println("Failed to mount file system");
      #endif
   }

   // Start the web server to serve incoming requests
   server.begin();
   
   // Start the timer to push a message every minute
   pushTrigger.attach(60, triggerGCM);
   
   // Send first push notification
   // Create messages & keys as JSON arrays
   DynamicJsonBuffer jsonBufferKeys;
   DynamicJsonBuffer jsonBufferMsgs;
   JsonArray& msgKeysJSON = jsonBufferKeys.createArray();
   JsonArray& msgsJSON = jsonBufferMsgs.createArray();
   char buf[4];
   char msgOne[24] = "Test message number ";
   itoa(msgCnt,buf,10);
   strcat(msgOne,buf);
   msgKeysJSON.add("message");
   msgKeysJSON.add("timestamp");
   msgsJSON.add(msgOne);
   msgsJSON.add(buf);
   gcmSendMsg(msgKeysJSON, msgsJSON);
   msgCnt++;
}

/**
   loop
   main program loop
   wait for connection to web server
   for testing purpose sends every minute a GCM notification to
      registered Android devices
*/
void loop() {
 
   // Handle new client request on HTTP server if available
   WiFiClient client = server.available();
   if (client) {
      webServer(client);
   }
   
   if (doPush) {
  //============================================
  Serial.println("F");
      comFlasher.attach(0.5, blueLedFlash);

      doPush = false;
      // Create messages & keys as JSON arrays
      DynamicJsonBuffer jsonBufferKeys;
      DynamicJsonBuffer jsonBufferMsgs;
      JsonArray& msgKeysJSON = jsonBufferKeys.createArray();
      JsonArray& msgsJSON = jsonBufferMsgs.createArray();
      char buf[4];
      char msgOne[24] = "Test message number ";
      itoa(msgCnt,buf,10);
      strcat(msgOne,buf);
      msgKeysJSON.add("message");
      msgKeysJSON.add("timestamp");
      msgsJSON.add(msgOne);
      msgsJSON.add(buf);
      gcmSendMsg(msgKeysJSON, msgsJSON);
      msgCnt++;
      comFlasher.detach();
      digitalWrite(comLED, HIGH); // Turn off LED
   }
}


Current Status:
It says connecting to android.googleapis.com but later goes in the else loop. Not sure why I cannot connect?
My serial output is as below:
....
...
Connecting to https://android.googleapis.com
Pre connect server
Connection to GCM server failed!

Can anyone please help? I think I am almost close to get everything working. Just need some help.
Thank you.