Trying to talk to Google Calendar

I’m trying to set up some basic home automation. I’ve started using the code from this site: GitHub - mattbornski/Arduino-GCal-Relays: Control relays on a schedule by polling Google Calendar

All I’ve done so far is put in my own IP, DNS, mac and calendar URL. Everything else is original except for a few debug serial.println commands.

It loops for a while saying it can’t connect. After about 5 minutes it stops looping and says its requesting the URL, it then moves onto the void parseResponse(byte relayStates) function. This is where it gets stuck. It’ll get to Serial.println(“Starting read…”);, then none of the if statements occur so it does the ‘else’ and increments lineIndex, it keeps doing this until it gets to 255, does the ‘Starting read…’ again, then increments lineIndex again and so on.

If I’m getting this far am I actually reading the calendar but getting no data or is something else fundamentally wrong?

Any clues on how to fix or am I better off starting from somewhere else with another bit of code?

Harware: Arduino Leonardo with Ethernet shield
Original code: Arduino-GCal-Relays/relaySketch.ino at master · mattbornski/Arduino-GCal-Relays · GitHub

My code (snipped)

#include <SPI.h>

#include <Ethernet.h>
#include <EthernetClient.h>
#include <Dhcp.h>

// Determine your private Google calendar feed URL and fill in here:
#define CALENDAR_FEED_URL "https://www.google.com/calendar/feeds/oe8vcgf736aa11ghtyss56sqo%40group.calendar.google.com/public/basic"
#define CALENDAR_FEED_URL_REQUEST_HEADERS "GET /" CALENDAR_FEED_URL " HTTP/1.1\n" "Host: proxy.bornski.com\n" "User-Agent: arduino-ethernet\n" "Connection: close\n"

byte myMac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress myIp(192, 168, 0, 19);
IPAddress myDns(192, 168, 0, 1);

EthernetClient client;
char server[] = "proxy.bornski.com";

unsigned long lastConnectionTime = 0;                  // last time you connected to the server, in milliseconds
static const unsigned long connectionInterval = 60000; // delay between updates, in milliseconds
unsigned long lastHeartbeatTime = 0;                   // last time you sent a heartbeat pulse, in milliseconds
static const unsigned long heartbeatInterval = 10000;  // delay between heartbeat pulses, in milliseconds

...

void parseResponse(byte relayStates[]) {
  // The server will close it's side of the connection when it is finished transferring data.
  while (client.connected()) {
    // It's possible that there is still data to come, but it is not yet ready to read.
    while (client.available()) {
      while (char c = client.read()) {
        //        Serial.print(c);
        if (c == '\n' || c == '\r' || lineIndex == 255) {
          
          Serial.println("Starting read...");
          line[lineIndex] = '\0';
          if (strstr(line, "END:VCALENDAR")) {
            Serial.println("END:VCALENDAR  found");
            // Reset state for next time
            now[0] = '\0';
            dtstart[0] = '\0';
            dtend[0] = '\0';
            line[0] = '\0';
            lineIndex = 0;

            return;
          } 
          else if (strstr(line, "Date:") == line) {
            
            Serial.println("Date  found");
            parseHttpDate(now, line + 6);
          } 
          else if (strstr(line, "BEGIN:VEVENT") == line) {            
            Serial.println("BEGIN:VEVENT  found");
            // New event.  Reset the per-event parsing state.
            dtstart[0] = '\0';
            dtend[0] = '\0';
            for (int i = 0; i < 4; i++) {
              zones[i] = false;
            }
          } 
          else if (strstr(line, "END:VEVENT") == line) {            
            Serial.println("END:VEVENT  found");
            // End of the event.  If the timestamps are right,
            // then OR any of the found zones into the desired
            // zone state.
            if (strcmp(dtstart, now) <= 0 && strcmp(dtend, now) >= 0) {
              for (int i = 0; i < 4; i++) {
                if (zones[i]) {
                  relayStates[i] = HIGH;                  
                  Serial.print("state ");
                  Serial.print(i);
                  Serial.println(" found. Setting HIGH");
                }
              }
            }

            // If we get a long calendar it can take us a while to parse it out.
            if ((millis() - lastHeartbeatTime) > heartbeatInterval) {
              heartbeat();
            }
          } 
          else if (strstr(line, "DTSTART:") == line) {
            Serial.println("DTSTART  found");
            strcpy(dtstart, line + 8);
          } 
          else if (strstr(line, "DTEND:") == line) {
            Serial.println("DTEND  found");
            strcpy(dtend, line + 6);
          } 
          else if (strstr(line, "SUMMARY:") == line) {
            Serial.println("SUMMARY  found");
            Serial.println("Found summary, parsing for zones...");
            Serial.println(line);
            // Parse summary line for any zones mentioned.
            for (int zcIndex = 0; zcIndex < sizeof(zoneControlKeywords) / sizeof(zoneControl); zcIndex++) {
              if (strstr(line, zoneControlKeywords[zcIndex].keyword) != NULL) {
                Serial.print("Setting zone ");
                Serial.println(zoneControlKeywords[zcIndex].relay);
                zones[zoneControlKeywords[zcIndex].relay] = true;
              }
            }
          }
          lineIndex = 0;
          line[lineIndex] = '\0';
        } 
        else {
          line[lineIndex++] = c;
          //Serial.print("Increment line index. Line = ");
          //Serial.println(lineIndex);
        }
      }
    }
  }
}

...

// this method makes a HTTP connection to the server:
boolean httpRequest() {
  Serial.println("Connecting to host");
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("Requesting URL");
    // send the HTTP GET request:
    client.println(CALENDAR_FEED_URL_REQUEST_HEADERS);

    // note the time that the connection was made:
    lastConnectionTime = millis();

    Serial.print("Request sent. Last connection - ");
    Serial.println(lastConnectionTime);
    return true;
  } 
  else {
    // if you couldn't make a connection:
    Serial.println("Connection failed");
    client.stop();

    return false;
  }
}
#define CALENDAR_FEED_URL "https://www.google.com/calendar/feeds/oe8vcgf736aa11ghtyss56sqo%40group.calendar.google.com/public/basic"

See that https? Nope. Not from the Arduino.

Have now had a bit of a play with the URL. Changing to http worked a bit a got some data back. I needed to switch to the .ics feed and now it is working, mostly!

New URL

#define CALENDAR_FEED_URL "http://www.google.com/calendar/ical/oeasdov736aasdfghefqtqo%40group.calendar.google.com/private-18bc8537248be69de6dc12829f2feafc/basic.ics"
#define CALENDAR_FEED_URL_REQUEST_HEADERS "GET /" CALENDAR_FEED_URL " HTTP/1.1\n" "Host: proxy.bornski.com\n" "User-Agent: arduino-ethernet\n" "Connection: close\n"

I've run it a few times now and I get good data back from the calendar and I can turn the channels on and off by adding/removing events so that's a good start. At least I'm talking to Google. The problem is after about 5 minutes I get a mix of good data and "ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ" back for one cycle and then it stops connecting altogether.

I doubt anyone is but if you are following this and wondering what is happening I've sort of given up. XD

It worked well for a few cycles of reads and it was pretty cool to be able to change an element in Google calendar on my phone and have a relay turn on or off (which could have been miles away but in reality was right next to me) but it eventually crashed every time. After a few more plays and consistent, if slightly variable, errors in the data from the calendar I emailed the original author and he said he got something similar and never fully resolved it. I considered putting in some error handling and a reset routine but it wasn't a good place to start from. Instead I'm using a Raspberry Pi for the networking and it works much better. I may still use the Arduino for some of the interfacing but I think in this instance the Pi wins.

Hello NickJB,

I am also looking to make my Arduino work with Google Calender, have you been able to make your code stable? Can you post your final code?