HTTPSRedirect String Comparison does not match

Hi,

I am using the HTTPSRedirect library from electronics guy: GitHub - electronicsguy/ESP8266: ESP8266 Projects

Code works properly, except when I try to compare the incoming string (labeled ‘str’) to a string that I have declared in my code (labeled ‘purchase’). The idea is that when I receive a payment, it will automatically create a new row of data on my google spreadsheet, which will in turn create a ‘flag’ telling the Arduino to open a solenoid valve.

To create this ‘flag’ I’m having Arduino read from cell D1 in the spreadsheet. When data populates in the cell, the arduino will receive it, compare it and open the solenoid. I’ve been working on this for several weeks, pouring over the forums and not too sure if this is the best way to create this ‘flag’. All ideas are welcome and I want to learn more to improve my skills.

Problem: When I print both strings to the monitor, they look the same. I’m not sure why they’re not being seen as equal.

The google spreadsheet is Here: https://docs.google.com/spreadsheets/d/1YM9BCTry012iBSLGEhEku56hQ0LSp3-BjXh_mer1dTg/edit?usp=sharing

Serial Output here:

Output from Google Sheet: Beer Purchased
Output from ‘purchase’ string: Beer Purchased
--------------------Error:Beer Purchase string is not a match

My Arduino code is Here Full code is attached, I reached the character limit:

/*  
  // fetch spreadsheet data
  client->GET(url, host);

  // fetch spreadsheet data
  client->GET(url2, host);
  
   // fetch spreadsheet data
  client->GET(url3, host);

  
}

void loop() {
  //-----------------------------This section reads from a single google cell to display its contents on the LCD screen------------------------------
//Check the current time to start the ldr timer AND for the Google cell check
unsigned long currentMillis=millis();
//Subtract the current time from the previous time, then check if it has passed the interval time
if(currentMillis - previousMillisCell>= intervalCell) {
//If interval time is met, reset current timer
  previousMillisCell=currentMillis;

  
  static int error_count = 0;
  static int connect_count = 0;
  const unsigned int MAX_CONNECT = 20;
  static bool flag = false;

//Read Data from cell E1 and display on screen
 
  if (client->GET(url2, host)){
   ++connect_count;
   String str = client->getResponseBody();
 Serial.print("Who's beer is this?:':");
 Serial.print(str);
//Refresh the LCD before displaying the most current cell contents   
  lcd.clear(); 
 //The following was written by Goet:https://forum.arduino.cc/index.php?topic=216486.0 to center the contects on the LCD screen
  int pinnedRow = 0; // LCDHEIGHT / 2;
  String pinnedText = str;
  int l = pinnedText.length();
  lcd.setCursor(l % 2 == 0 ? LCDWIDTH / 2 - (l / 2) : LCDWIDTH / 2 - (l / 2) - 1, pinnedRow);
 pinnedText= pinnedText.substring(0, pinnedText.length() - 2);
 lcd.print (pinnedText);

//Read Data from cell D1, if it matched the string "Beer Purchased", then open the solenoid for x seconds (or turn off back light for testing purposes)
 
if (client->GET(url3, host)){
   ++connect_count;
 //assign the outpult string ofthe readD3 Google appps function to a string called 'flag'
   String str= client->getResponseBody();
   Serial.print("Output from Google Sheet: ");
   Serial.print(str);
   
  }
      else{
    ++error_count;
    DPRINT("Error-count while connecting: ");
    Serial.print("First Error while connecting");
    DPRINTLN(error_count);
  }
  
String purchase = "Beer Purchased";
Serial.print("Output from 'purchase' string: ");
Serial.print(purchase);

if(str == purchase){
  
 //Print the "Beer Purchased" flag to the serial.
  Serial.print ("Beer Purchased");
  lcd.noBacklight();
  delay (4000);
 
  }       
       else{
    ++error_count;
    DPRINT("Error-count while connecting: ");
    Serial.println("--------------------Error:Beer Purchase string is not a match");
    DPRINTLN(error_count);
  }

/*Look to see if cell D1 says 'Beer Purchased'
if(purchaseFlag =="Beer Purchased"){
  
 //Print the "Beer Purchased" flag to the serial.
 Serial.print(flag);
}
  else{
    ++error_count;
    DPRINT("Error while reading D1");
    DPRINT(error_count);
    Serial.print("No beers purchased yet");
  }
*/
//May want to send the command to clear D1 from Arduino, instead of the apps script.
  
   // In my testing on a ESP-01, a delay of less than 1500 resulted 
  // in a crash and reboot after about 50 loop runs.


} 
                   
}
}

CoinOp Code.txt (7.78 KB)

1 Like

If two strings look the same, but compare different, you either have

  1. spaces at the end
  2. a CR and/or a LF on one of the strings which doesn't compare

Code works properly, except when I try to compare the incoming string (labeled 'str') to a string that I have declared in my code (labeled 'purchase').

A String is NOT a string.

   String str = client->getResponseBody();
 Serial.print("Who's beer is this?:':");
 Serial.print(str);
//Refresh the LCD before displaying the most current cell contents   
  lcd.clear(); 
 //The following was written by Goet:https://forum.arduino.cc/index.php?topic=216486.0 to center the contects on the LCD screen
  int pinnedRow = 0; // LCDHEIGHT / 2;
  String pinnedText = str;
  int l = pinnedText.length();
  lcd.setCursor(l % 2 == 0 ? LCDWIDTH / 2 - (l / 2) : LCDWIDTH / 2 - (l / 2) - 1, pinnedRow);
 pinnedText= pinnedText.substring(0, pinnedText.length() - 2);
 lcd.print (pinnedText);

//Read Data from cell D1, if it matched the string "Beer Purchased", then open the solenoid for x seconds (or turn off back light for testing purposes)
 
if (client->GET(url3, host)){
   ++connect_count;
 //assign the outpult string ofthe readD3 Google appps function to a string called 'flag'
   String str= client->getResponseBody();
   Serial.print("Output from Google Sheet: ");
   Serial.print(str);
   
  }
      else{
    ++error_count;
    DPRINT("Error-count while connecting: ");
    Serial.print("First Error while connecting");
    DPRINTLN(error_count);
  }
  
String purchase = "Beer Purchased";
Serial.print("Output from 'purchase' string: ");
Serial.print(purchase);

if(str == purchase){

Which str do you think you are comparing to purchase? Dollars to donuts it is NOT the one you think is being compared.

blh64:
If two strings look the same, but compare different, you either have

  1. spaces at the end
  2. a CR and/or a LF on one of the strings which doesn’t compare

Is there a way to print spaces, CR, or LF’s to the serial monitor? I think this may be the issue but I can’t figure out how to print the output of str so I can see what’s going on.

PaulS:
Which str do you think you are comparing to purchase? Dollars to donuts it is NOT the one you think is being compared.

I printed both str and purchased to the serial monitor to verify that these were the strings I was looking to compare and they appear the same, but as blh64 mentioned I may not be seeing an extra space, LF or CR.

Is there a way to print spaces, CR, or LF's to the serial monitor? I think this may be the issue but I can't figure out how to print the output of str so I can see what's going on.

Serial.print("Some String: [");
Serial.print(someString);
Serial.println("]");

Thanks PaulS, I think what I meant was, how can I see if there is a CR, LF, or extra space being printed on my string named str?

tlujan0001:
Thanks PaulS, I think what I meant was, how can I see if there is a CR, LF, or extra space being printed on my string named str?

When you print the string, print it jammed up tight against delimiters.

[This is my String]
means that there are no non-printing characters in the String.

[This is my String
]
means that there ARE non-printing characters in the String.

trim() will get rid of them.

Thank you, PaulS. Here is what I did per your suggestions:

Added a delimiter to each string to see if either had extra spaces, CR, or LF’s…

String str= client->getResponseBody();
   Serial.print("Output from Google Sheet: [");
   Serial.print(str);
   Serial.print("]");

and it looks like there was a CR printing because this came out of the serial monitor:

Output from Google Sheet: [Beer Purchased
]Output from ‘purchase’ string: [Beer Purchased]
--------------------Error:Beer Purchase string is not a match

So I added str.trim(); just before printing it:

String str= client->getResponseBody();
   str.trim();
   Serial.print("Output from Google Sheet: [");
   Serial.print(str);
   Serial.print("]");

But they still are not equal somehow…this is how they are printing to the serial monitor:

Output from Google Sheet: [Beer Purchased]Output from ‘purchase’ string: [Beer Purchased]--------------------Error:Beer Purchase string is not a match

I think it would behoove you to understand the difference between print() and println().

I think it would behoove you to understand that it is important, when you have changed your code, to post the revised code.

Error:Beer Purchase string is not a match

I'd much rather see

Error: [Beer Purchased] is not equal to [Beer Purchased].

Then, we KNOW that you have printed the correct thing at the correct time. If we see anything else on that line, or that data takes more than one line to display, a clue-by-four is coming, and we need to duck.

Thanks Paul, to me it sounds like your speaking in riddles. Is this necessary in helping me learn this new language?

a clue-by-four is coming, and we need to duck.

I printed both “str” and “purchased” to the serial monitor already as mentioned in the previous post. So I didn’t think re-printing it in the error message would make a difference. I’ll try your suggestion and look again.

I think it would behoove you to understand the difference between print() and println().

My understanding of print() vs println() is that the latter will print the string on the next line. I haven’t used println() in the comparison, so what is missing?

I think it would behoove you to understand that it is important, when you have changed your code, to post the revised code.

I posted the section of code that I changed, what is wrong with this?

My understanding of print() vs println() is that the latter will print the string on the next line. I haven’t used println() in the comparison, so what is missing?

print() prints just the data.
println() prints the data and then a carriage return and a line feed. It does not print the data on the next line.

I posted the section of code that I changed, what is wrong with this?

The context is missing. In the last code you posted, you still have two variables named str. This has been pointed out to be a potential problem.

Printing the contents of one str, and using the other in the comparison, and finding that they are not equal, and then printing “Well, shit, they don’t match” doesn’t get you anywhere.

Compare this:

String alpha = "Alpha dog eats first";

// Some stuff

String alpha = "The puny dog eats last";

// Some more stuff

String whatIsWanted = "Alpha dog eats first";

if(alpha == whatIsWanted)
{
}
else
{
   Serial.println("They don't match");
}

to this:

String alpha = "Alpha dog eats first";

// Some stuff

String alpha = "The puny dog eats last";

// Some more stuff

String whatIsWanted = "Alpha dog eats first";

if(alpha == whatIsWanted)
{
}
else
{
   Serial.println("[");
   Serial.print(alpha);
   Serial.print("] does not match [");
   Serial.print(whatIsWanted);
   Serial.println("]");
}

If you see “They don’t match”, can you figure out why? If you see “[The puny dog eats last] doesn’t match [Alpha dog eats first]”, are you more, or less, likely to go “Oh, shit, I see the problem…”?

I was able to get it working, thanks to the guidance of PaulS. The problem was that I needed to add ‘getResponseBody();’ outside of the ‘if’ statement. The data was not remaining in the string once the statement completed. I have some basic questions of why it is behaving this way:

1.I tried to change the name of the string to ‘flag’ but received an error messege “‘flag’ was not declared in scope”. Why can’t I change this to anything other than ‘str’?

  1. I am reading from another cell using the GET request “client->GET(url2, host);” and assigning it to the same name ‘str’. How am I getting the output of url3 and not url 2? My guess is that I’m just reassigning the data I receive from the spreadsheet to ‘str’.

3.Why do I need to get the data again using ‘getresponseBody();’ if it was declared in the ‘if’ statement just above it?

Here is the full code:

/*  HTTPS on ESP8266 with follow redirects, chunked encoding support
 *  Version 2.1
 *  Author: Sujay Phadke
 *  Github: @electronicsguy
 *  Copyright (C) 2017 Sujay Phadke <electronicsguy123@gmail.com>
 *  All rights reserved.
 *
 *  Example Arduino program
 */
#include <LiquidCrystal_I2C.h>
#include <ESP8266WiFi.h>
#include <DebugMacros.h>
#include <HTTPSRedirect.h>

#include <SPI.h>
#include <Wire.h>
#define LCDWIDTH 16
#define LCDHEIGHT 2

/*
 * SDA to nodeMCU D4
 * SCL to nodeMCU D3
 */



// for stack analytics
extern "C" {
#include <cont.h>
  extern cont_t g_cont;
}

// Fill ssid and password with your network credentials
const char* ssid = "SSID";
const char* password = "PASSWORD";

const char* host = "script.google.com";
// Replace with your own script id to make server side changes
const char *GScriptId = "Gscript ID Goes HERE";

const int httpsPort = 443;

// echo | openssl s_client -connect script.google.com:443 |& openssl x509 -fingerprint -noout
const char* fingerprint = "";

// Write to Google Spreadsheet
String url = String("/macros/s/") + GScriptId + "/exec?value=Hello";
// Read from Google Spreadsheet: Beer Owner
String url2 = String("/macros/s/") + GScriptId + "/exec?readE1";
// Read from Google Spreadsheet: Beer Purchased Flag
String url3 = String("/macros/s/") + GScriptId + "/exec?readD1";

String payload_base =  "{\"command\": \"appendRow\", \
                    \"sheet_name\": \"Sheet1\", \
                    \"values\:";
String payload = "";

HTTPSRedirect* client = nullptr;
// used to store the values of free stack and heap
// before the HTTPSRedirect object is instantiated
// so that they can be written to Google sheets
// upon instantiation

// Construct an LCD object and pass it the I2C address, width (in characters) and height (in characters). Depending on the
// Actual device, the IC2 address may change.
// Wemos D2 to LCD SDA
// Wemos D1 to LCD SCL

//Define LDR pin and create timer variable
const int ldrPin = A0;
unsigned long previousMillis= 0;
//How often do we check back on the LDR state
unsigned long interval=1000;

//Create timer variable for checking Google sheet
unsigned long previousMillisCell= 0;
unsigned long intervalCell=4000;

LiquidCrystal_I2C lcd(0x27, 16, 2);//Ox27 OR 0x3F

void setup() {
  Serial.begin(115200);
  Serial.flush();
  Serial.setDebugOutput(false);

pinMode(ldrPin, INPUT);

//Wire.begin(2,0); //Uncomment for Node MCU only
//lcd.begin(16, 2); //Uncomment for Node MCU only
lcd.init(); // initialize the lcd, WEMOS
lcd.init();
lcd.backlight(); // Enable or Turn On the backlight

 
//Establish Wifi Connection
  Serial.println();
  Serial.print("Connecting to wifi: ");
  Serial.println(ssid);
  // flush() is needed to print the above (connecting...) message reliably, 
  // in case the wireless connection doesn't go through
  Serial.flush();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
//Display connection status on LCD
  lcd.setCursor(0,0);
  lcd.print("Connected to: ");
  lcd.setCursor(0,1);
  lcd.print(ssid);
  delay(2000);
lcd.clear();

  // Use HTTPSRedirect class to create a new TLS connection
  client = new HTTPSRedirect(httpsPort);
  client->setPrintResponseBody(false);
  client->setContentTypeHeader("application/json");
  
  Serial.print("Connected to ");
  Serial.println(host);


  // Try to connect for a maximum of 5 times
  bool flag = false;
  for (int i=0; i<5; i++){
    int retval = client->connect(host, httpsPort);
    if (retval == 1) {
       flag = true;
       break;
    }
    else
      Serial.println("Connection failed. Retrying...");
  }

  if (!flag){
    Serial.print("Could not connect to server: ");
    Serial.println(host);
    Serial.println("Exiting...");
    return;
  }
  
  if (client->verify(fingerprint, host)) {
    Serial.println("Certificate match.");
  } else {
    Serial.println("Certificate mis-match");
  }

  // Note: setup() must finish within approx. 1s, or the the watchdog timer
  // will reset the chip. Hence don't put too many requests in setup()
  // ref: https://github.com/esp8266/Arduino/issues/34
  
  Serial.println(" Write into cell 'A1'");
  Serial.println("=========================");

  // fetch spreadsheet data
  client->GET(url, host);

  // fetch spreadsheet data
  client->GET(url2, host);
  
   // fetch spreadsheet data
  client->GET(url3, host);



  
}

void loop() {
  //-----------------------------This section reads from a single google cell to display its contents on the LCD screen------------------------------
//Check the current time to start the ldr timer AND for the Google cell check
unsigned long currentMillis=millis();
//Subtract the current time from the previous time, then check if it has passed the interval time
if(currentMillis - previousMillisCell>= intervalCell) {
//If interval time is met, reset current timer
  previousMillisCell=currentMillis;

  
  static int error_count = 0;
  static int connect_count = 0;
  const unsigned int MAX_CONNECT = 20;
  static bool flag = false;

//Read Data from cell E1 and display on screen
 
  if (client->GET(url2, host)){
   ++connect_count;
   String str = client->getResponseBody();
 Serial.print("Who's beer is this?:");
 Serial.print(str);
//Refresh the LCD before displaying the most current cell contents   
  lcd.clear(); 
 //The following was written by Goet:https://forum.arduino.cc/index.php?topic=216486.0 to center the contects on the LCD screen
  int pinnedRow = 0; // LCDHEIGHT / 2;
  String pinnedText = str;
  int l = pinnedText.length();
  lcd.setCursor(l % 2 == 0 ? LCDWIDTH / 2 - (l / 2) : LCDWIDTH / 2 - (l / 2) - 1, pinnedRow);
 pinnedText= pinnedText.substring(0, pinnedText.length() - 2);
 lcd.print (pinnedText);

//Read Data from cell D1, if it matched the string "Beer Purchased", then open the solenoid for x seconds (or turn off back light for testing purposes)
 
if (client->GET(url3, host)){
   ++connect_count;
 //assign the output string of the readD3 Google appps function to a string called 'str'
   String paid= client->getResponseBody();
   
  }
      else{
    ++error_count;
    DPRINT("Error-count while connecting: ");
    Serial.print("First Error while connecting");
    DPRINTLN(error_count);
  }

//create a string to compare the output of the google sheet to  
String purchase = "Beer Purchased";
//Grab the output of cell D1 on the Google sheet to use in the comparison, then trim of the extra carriage return

    str= client->getResponseBody();
    str.trim();


if(str == purchase){
 //Print the "Beer Purchased" flag to the serial.
  Serial.print ("Beer Purchased");
  lcd.noBacklight();
  delay (4000);
 
  }       
       else{
    ++error_count;
    DPRINT("Error-count while connecting: ");
    Serial.print("Error: [");
    Serial.print(str);
    Serial.print("] is not equal to [");
    Serial.print(purchase);
    Serial.print("]")
    DPRINTLN(error_count);
  }

//May want to send the command to clear D1 from Arduino, instead of the apps script.
  
   // In my testing on a ESP-01, a delay of less than 1500 resulted 
  // in a crash and reboot after about 50 loop runs.


} 
                   
}
}

1.I tried to change the name of the string to 'flag' but received an error messege "'flag' was not declared in scope". Why can't I change this to anything other than 'str'?

You could have, if you change the variable declaration and every use of the variable name.

if (client->GET(url3, host)){
   ++connect_count;
 //assign the output string of the readD3 Google appps function to a string called 'str'
   String paid= client->getResponseBody();
  
  }

The variable named paid exists until the } is encountered, which happens REALLY, REALLY soon after it is assigned a value. You might as well not be calling the GET() method with url3.

  String paidBy = "Nobody";
  if (client->GET(url3, host))
  {
     ++connect_count;
     paidBy = client->getResponseBody();
  }
  Serial.print("Who paid for my beer?");
  Serial.print(paidBy);
  Serial.println(" paid for the beer!");

  if(paidBy == "Nobody")
  {
     // Hey, you owe me $8.00 for the beer
  }

Would be the proper way to write that snippet.

3.Why do I need to get the data again using 'getresponseBody();' if it was declared in the 'if' statement just above it?

Specifically, which line numbers are you referring to?

The previous info may give you a clue.