Please help! Why is the Arduino IoT Cloud not sending data to Google Sheets?

"I am from Thailand, and I am working on a project that I need to submit to my university, with a deadline on February 9th. I need the data, such as servo1, distancePercent, and kilogram, to be sent to an Apps Script that will insert it into a Google Sheet. I have edited it repeatedly, and the URL is correct and set to be accessible by everyone. I am feeling hopeless. I really need help."

This is my Arduino Iot Cloud Code.

#include "arduino_secrets.h"
#include "thingProperties.h"
#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

const int trigPin = 5; // GPIO5
const int echoPin = 4; // GPIO4

Servo myservo1;
int distancePercent = 0;
bool lastServoState = false;
unsigned long lastReadTime = 0;
const unsigned long readInterval = 500; // 0.5 seconds
const int maxDistance = 34; // Maximum distance
const int minDistance = 8;  // Minimum distance
const float maxKilogram = 7.0; // 100% = 7 kg

void setup() {
  Serial.begin(115200);
  delay(1000);
 
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  WiFi.persistent(true);     // Disable saving Wi-Fi to Flash
  WiFi.mode(WIFI_STA);        // Set mode to Station mode
  WiFi.setSleepMode(WIFI_NONE_SLEEP); // Disable power saving mode

  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  myservo1.attach(14);
  myservo1.write(0);

  configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  setenv("TZ", "ICT-7", 1);  // Set timezone to ICT
  tzset();  // Update timezone info
}  

void loop() {
  ArduinoCloud.update(); // Check the IoT Cloud status
  handleServoControl();
  handleSensorUpdate();
}

void handleServoControl() {
  // Check the status of servo1, schedule, schedule2, and schedule3
  bool currentServoState = servo1 || schedule.isActive() || schedule2.isActive() || schedule3.isActive();

  // Control servo movement
  myservo1.write(currentServoState ? 70 : 0);

  // Check for servo state change and send notification
  if (currentServoState != lastServoState) {
    notifyServoState(currentServoState);
    lastServoState = currentServoState;
  }
}

void handleSensorUpdate() {
  if (millis() - lastReadTime > readInterval) {
    lastReadTime = millis();
    updateSensorDistance();
  }
}

void updateSensorDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH);
  int distance = duration * 0.034 / 2;

  if (distance < minDistance) {
    distancePercent = 100;
  } else if (distance <= maxDistance) {
    distancePercent = map(distance, minDistance, maxDistance, 100, 0);
  } else {
    distancePercent = 0;
  }

  // Calculate food weight as a decimal
  kilogram = (distancePercent * maxKilogram * 1000.0) / 100.0;

  Serial.print("Distance Percent: ");
  Serial.println(distancePercent);
  Serial.print("Kilogram (float): ");
  Serial.println(kilogram, 2); // Display two decimal points

  if (distancePercent != dogFood) {
    dogFood = distancePercent;

    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.print(" cm | Percentage: ");
    Serial.print(distancePercent);
    Serial.print(" % | Kilogram: ");
    Serial.print(kilogram);  // Display weight in decimal format
    Serial.println(" kg");
  }
}

// Function to send data to Google Apps Script
void sendDataToGoogleSheet(String servoState, int distancePercent, float kilogram) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    // Construct URL to send data to Google Apps Script with parameters
    String url = "https://script.google.com/macros/s/XXXXXXX/exec?"; // i have my url, I will add it later.
    url += "servo1=" + servoState + "&distancePercent=" + String(distancePercent) + "&kilogram=" + String(kilogram, 2);
    Serial.println("Sending data to Google Sheet...");
    http.begin(url.c_str()); // Specify the URL and certificate
    int httpCode = http.GET();
    String payload;
    if (httpCode > 0) { // Check for the returning code
      payload = http.getString();
      Serial.println(httpCode);
      Serial.println(payload);
    } else {
      Serial.println("Error occurred and failed to send");
    }
    http.end();
  }
}

String getFormattedDate() {
  time_t now = time(nullptr);  // Get current time
  struct tm *timeinfo = localtime(&now);  // Convert time to structure
  char buffer[30];
  strftime(buffer, sizeof(buffer), "%d-%m-%Y", timeinfo);  // Format date
  return String(buffer);
}

String getFormattedTime() {
  time_t now = time(nullptr);  // Get current time
  struct tm *timeinfo = localtime(&now);  // Convert time to structure
  char buffer[30];
  strftime(buffer, sizeof(buffer), "%H:%M:%S", timeinfo);  // Format time
  return String(buffer);
}

void notifyServoState(bool currentState) {
  String header = "====================\n";
  String footer = "\n====================";
  String date = String("📅 Date: ") + getFormattedDate();
  String time = String("⏰ Time: ") + getFormattedTime();
  String message;

  if (currentState) {
    message = "💡 Status: Feeding\n" + date + "\n" + time;
  } else {
    message = "🛑 Status: Feeding Stopped\n" + date + "\n" + time;
  }

  String alert = header + message + footer;
  Serial.println(alert);
}

void onServo1Change() {
  myservo1.write(servo1 ? 70 : 0);
  notifyServoState(servo1);
}

void onDogFoodChange() {
  Serial.print("DogFood Changed to: ");
  Serial.println(dogFood);
}

void onScheduleChange() {
  Serial.println("Schedule Changed");
}

void onAlertChange() {
  Serial.println("Alert Changed");
}

void onSchedule2Change()  {
  Serial.println("Schedule2 Changed");
}

void onSchedule3Change()  {
  Serial.println("Schedule3 Changed");
}

void onKilogramChange() {
  Serial.println("Kilogram value has changed!");
  // Add any processing you want when the kilogram changes
}

===========================================================
and my AppScript Code

function doGet(e) { 
  Logger.log(JSON.stringify(e));
  var result = 'Ok';
  if (!e.parameter || Object.keys(e.parameter).length === 0) {
    result = 'No Parameters';
  } else {
    var sheet_id = 'XXXXXXXX'; // I have Spreadsheet ID, i will add it later.
    var sheet = SpreadsheetApp.openById(sheet_id).getActiveSheet();
    var newRow = sheet.getLastRow() + 1;
    var rowData = [];
    var Curr_Date = new Date();
    rowData[0] = Curr_Date; // Date in column A
    var Curr_Time = Utilities.formatDate(Curr_Date, "Asia/Bangkok", 'HH:mm:ss');
    rowData[1] = Curr_Time; // Time in column B

    for (var param in e.parameter) {
      Logger.log('In for loop, param=' + param);
      var value = stripQuotes(e.parameter[param]);
      Logger.log(param + ':' + e.parameter[param]);

      switch (param) {
        case 'servo1':
          if (value === "ON") {
            rowData[2] = "Dispensing Food"; // Write "Dispensing Food" in column C
            result = 'Dispensing Food written to column C';
          } else if (value === "OFF") {
            rowData[2] = "Stopped Dispensing Food"; // Write "Stopped Dispensing Food" in column C
            result = 'Stopped Dispensing Food written to column C';
          } else {
            result = 'Invalid value received (should be ON or OFF)';
          }
          break;

        case 'distancePercent':
          rowData[3] = value; // Write distancePercent value to column D
          result = 'distancePercent written to column D'; 
          break;

        case 'kilogram':
          rowData[4] = value; // Write kilogram value to column E
          result = 'kilogram written to column E'; 
          break;

        default:
          Logger.log('Unsupported parameter: ' + param);
      }
    }

    Logger.log(JSON.stringify(rowData));
    var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
    newRange.setValues([rowData]);
  }

  return ContentService.createTextOutput(result);
}

function stripQuotes(value) {
  return value.replace(/^["']|['"]$/g, "");
}

In your sendDataToGoogleSheet function, the servo1 parameter should be sent as "ON" or "OFF" to match the conditions in your Apps Script. Update the code as follows:

void sendDataToGoogleSheet(bool servoState, int distancePercent, float kilogram) {
    if (WiFi.status() == WL_CONNECTED) {
        HTTPClient http;

        // Format servoState as "ON" or "OFF"
        String servoStateStr = servoState ? "ON" : "OFF";

        String url = "https://script.google.com/macros/s/XXXXXXX/exec?";
        url += "servo1=" + servoStateStr + "&distancePercent=" + String(distancePercent) + "&kilogram=" + String(kilogram, 2);
        Serial.println("Sending data to Google Sheet...");
        http.begin(url.c_str());

        int httpCode = http.GET();
        String payload;
        if (httpCode > 0) {
            payload = http.getString();
            Serial.println(httpCode);
            Serial.println(payload);
        } else {
            Serial.println("Error occurred and failed to send");
        }
        http.end();
    } else {
        Serial.println("WiFi is not connected!");
    }
}

1 Like

Format your code and paste it into a code block.

1 Like

Thank you for your kindness. Your code works perfectly. I’ve updated the code to the board and tested it, but I still get the same result. So, I’m wondering if connecting Google Sheets with Arduino IoT Cloud requires IFTTT webhooks? Or maybe I’m still missing something...

Thank you for your advice. :slightly_smiling_face:

Hello, I was giving a look at your code sketch, it's not clear to me where the sendDataToGoogleSheet should be called... I saw the definition but not the invocation....

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.