1

I'm trying to create SMS alarm using Twilio, Firebase and Arduino IDE. Using sensors I am measuring the temperature. If the temperature is higher than a specified value (ESP reads that value from Firebase Realtime Database), a SMS should be sent using twilio. I am also storing the measures in Firebase Realtime Database. The code worked well, until I tried to retrieve data from Firebase one more time and set data two more times. I believe that I'm running out of heap. I have only 10k heap left and cannot send SMS via Twilio. It only prints: connecting to api.twilio.com, but I don't receive the message.

Here's my code:

#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#include "OneWire.h"
#include "DallasTemperature.h"
#include "twilio.hpp"
#include <ESP8266WebServer.h>
#include <WiFiManager.h>

#define FIREBASE_HOST "***.firebaseio.com" 
#define FIREBASE_AUTH "****"
#define WIFI_SSID "*****"
#define WIFI_PASSWORD "****"

const char fingerprint[] = "BC B0 1A 32 80 5D E6 E4 A2 29 66 2B 08 C8 E0 4C 45 29 3F D0";
const char* account_sid = "******";
const char* auth_token = "*******";

String to_number    = "+*****";
String from_number = "+*****";
String message_body    = "Hello from Twilio and the ESP8266!";

// The 'authorized number' to text the ESP8266 for our example
String master_number    = "+******";

// Optional - a url to an image.  See 'MediaUrl' here:
// https://www.twilio.com/docs/api/rest/sending-messages
String media_url = "";

// Global twilio objects
Twilio *twilio;
ESP8266WebServer twilio_server(8000);

//  Optional software serial debugging
#if USE_SOFTWARE_SERIAL == 1
#include <SoftwareSerial.h>
// You'll need to set pin numbers to match your setup if you
// do use Software Serial
extern SoftwareSerial swSer(14, 4, false, 256);
#else
#define swSer Serial
#endif



#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float temp1 = 0;

FirebaseData *firebaseData1 = new FirebaseData();
FirebaseData *firebaseData2 = new FirebaseData();
FirebaseData *firebaseData3 = new FirebaseData();
FirebaseData firebaseData;
FirebaseData firebaseData4;
FirebaseJson tms;
FirebaseJsonArray arr;

unsigned long sendDataPrevMillis = 0;

String path = "/Test/Stream";

int count = 0;
int sms = 0;
String c;
int b;

bool deallocated = false;

void printResult(FirebaseData &data);
void printResult(StreamData &data);

void streamCallback(StreamData data)
{

  Serial.println("Stream Data1 available...");
  Serial.println("STREAM PATH: " + data.streamPath());
  Serial.println("EVENT PATH: " + data.dataPath());
  Serial.println("DATA TYPE: " + data.dataType());
  Serial.println("EVENT TYPE: " + data.eventType());
  Serial.print("VALUE: ");
  printResult(data);
  Serial.println();
}

void streamTimeoutCallback(bool timeout)
{
  if (timeout)
  {
    Serial.println();
    Serial.println("Stream timeout, resume streaming...");
    Serial.println();
  }
}

void setup()
{

  Serial.begin(115200);

    WiFiManager wm;
    bool res;
    res = wm.autoConnect("AutoConnectAP","password"); // password protected ap

    if(!res) {
        Serial.println("Failed to connect");
        // ESP.restart();
    } 
    else {  
        Serial.println("connected...yeey :)");
    }

twilio = new Twilio(account_sid, auth_token, fingerprint);
  sensors.begin();
twilio_server.begin();

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  Firebase.reconnectWiFi(true);

  //Set the size of WiFi rx/tx buffers in the case where we want to work with large data.
  firebaseData1->setBSSLBufferSize(1024, 1024);

  //Set the size of HTTP response buffers in the case where we want to work with large data.
  firebaseData1->setResponseSize(1024);

  //Set the size of WiFi rx/tx buffers in the case where we want to work with large data.
  firebaseData2->setBSSLBufferSize(1024, 1024);

  //Set the size of HTTP response buffers in the case where we want to work with large data.
  firebaseData2->setResponseSize(1024);

  if (!Firebase.beginStream(*firebaseData1, path))
  {
    Serial.println("------------------------------------");
    Serial.println("Can't begin stream connection...");
    Serial.println("REASON: " + firebaseData1->errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  Firebase.setStreamCallback(*firebaseData1, streamCallback, streamTimeoutCallback);
}

void loop()
{
  if (millis() - sendDataPrevMillis > 5000)
  {
    sendDataPrevMillis = millis();

sensors.requestTemperatures();
  temp1 = sensors.getTempCByIndex(0);
  Serial.print("");

tms.set(".sv", "timestamp");


 if (Firebase.getString(firebaseData, "002/alarm")) {

    if (firebaseData.dataType() == "string") {
      Serial.println(firebaseData.stringData());
    }

  } else {
    Serial.println(firebaseData.errorReason());
  }
int myInt = firebaseData.stringData().toInt();

if (temp1 < myInt) {
  if(Firebase.setInt(*firebaseData3, "/serial/sms", sms))
  {
      Serial.println("PASSED");
      Serial.println("PATH: " + firebaseData3->dataPath());
      Serial.println("TYPE: " + firebaseData3->dataType());
      Serial.print("VALUE: ");
      printResult(*firebaseData3);
      Serial.println("------------------------------------");
      Serial.println();
    }
    else
    {
      Serial.println("FAILED");
      Serial.println("REASON: " + firebaseData3->errorReason());
      Serial.println("------------------------------------");
      Serial.println();
    }
}

   if (Firebase.getInt(firebaseData4, "/serial/sms")) {

    if (firebaseData4.dataType() == "int") {
      Serial.println(firebaseData4.intData());
    }

  } else {
    Serial.println(firebaseData4.errorReason());
  }

if (temp1 > myInt) {
  if(firebaseData4.intData() < 1){
    sms++;
  String response;
      bool success = twilio->send_message(
                       to_number,
                       from_number,
                       message_body,
                       response,
                       media_url
                     );
    if(Firebase.setInt(*firebaseData3, "/serial/sms", sms))
  {
      Serial.println("PASSED");
      Serial.println("PATH: " + firebaseData3->dataPath());
      Serial.println("TYPE: " + firebaseData3->dataType());
      Serial.print("VALUE: ");
      printResult(*firebaseData3);
      Serial.println("------------------------------------");
      Serial.println();
    }
    else
    {
      Serial.println("FAILED");
      Serial.println("REASON: " + firebaseData3->errorReason());
      Serial.println("------------------------------------");
      Serial.println();
    }
}
}

    Serial.println(ESP.getFreeHeap());

    delay(0);

    count++;

    Serial.println("------------------------------------");
    Serial.println("Set Int...");

        arr.clear();
        arr.set("/[0]", temp1);
        arr.set("/[1]", tms);


    if (Firebase.push(*firebaseData2, path + "/Int", arr))
    {
      Serial.println("PASSED");
      Serial.println("PATH: " + firebaseData2->dataPath());
      Serial.println("TYPE: " + firebaseData2->dataType());
      Serial.print("VALUE: ");
      printResult(*firebaseData2);
      Serial.println("------------------------------------");
      Serial.println();
    }
    else
    {
      Serial.println("FAILED");
      Serial.println("REASON: " + firebaseData2->errorReason());
      Serial.println("------------------------------------");
      Serial.println();
    }


    if (count == 1)
    {
      Serial.println("Deallocate the Firebase Data objects after 3 times Firebasse call");
      
      //Need to stop the stream to prevent the readStream and callback to be called after objects deallocation
      Firebase.endStream(*firebaseData1);
      Firebase.removeStreamCallback(*firebaseData1);
      
      //Deallocate
      delete firebaseData1;
      delete firebaseData2;
  
      firebaseData1 = nullptr;
      firebaseData2 = nullptr;
      count = 0;
    }
  }

}


//Helper function for printing the response/received data
void printResult(FirebaseData &data)
{

  if (data.dataType() == "int")
    Serial.println(data.intData());
  else if (data.dataType() == "float")
    Serial.println(data.floatData(), 5);
  else if (data.dataType() == "double")
    printf("%.9lf\n", data.doubleData());
  else if (data.dataType() == "boolean")
    Serial.println(data.boolData() == 1 ? "true" : "false");
  else if (data.dataType() == "string")
    Serial.println(data.stringData());
  else if (data.dataType() == "json")
  {
    Serial.println();
    FirebaseJson &json = data.jsonObject();
    //Print all object data
    Serial.println("Pretty printed JSON data:");
    String jsonStr;
    json.toString(jsonStr, true);
    Serial.println(jsonStr);
    Serial.println();
    Serial.println("Iterate JSON data:");
    Serial.println();
    size_t len = json.iteratorBegin();
    String key, value = "";
    int type = 0;
    for (size_t i = 0; i < len; i++)
    {
      json.iteratorGet(i, type, key, value);
      Serial.print(i);
      Serial.print(", ");
      Serial.print("Type: ");
      Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array");
      if (type == FirebaseJson::JSON_OBJECT)
      {
        Serial.print(", Key: ");
        Serial.print(key);
      }
      Serial.print(", Value: ");
      Serial.println(value);
    }
    json.iteratorEnd();
  }
  else if (data.dataType() == "array")
  {
    Serial.println();
    //get array data from FirebaseData using FirebaseJsonArray object
    FirebaseJsonArray &arr = data.jsonArray();
    //Print all array values
    Serial.println("Pretty printed Array:");
    String arrStr;
    arr.toString(arrStr, true);
    Serial.println(arrStr);
    Serial.println();
    Serial.println("Iterate array values:");
    Serial.println();
    for (size_t i = 0; i < arr.size(); i++)
    {
      Serial.print(i);
      Serial.print(", Value: ");

      FirebaseJsonData &jsonData = data.jsonData();
      //Get the result data from FirebaseJsonArray object
      arr.get(jsonData, i);
      if (jsonData.typeNum == FirebaseJson::JSON_BOOL)
        Serial.println(jsonData.boolValue ? "true" : "false");
      else if (jsonData.typeNum == FirebaseJson::JSON_INT)
        Serial.println(jsonData.intValue);
      else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT)
        Serial.println(jsonData.floatValue);
      else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE)
        printf("%.9lf\n", jsonData.doubleValue);
      else if (jsonData.typeNum == FirebaseJson::JSON_STRING ||
               jsonData.typeNum == FirebaseJson::JSON_NULL ||
               jsonData.typeNum == FirebaseJson::JSON_OBJECT ||
               jsonData.typeNum == FirebaseJson::JSON_ARRAY)
        Serial.println(jsonData.stringValue);
    }
  }
  else
  {
    Serial.println(data.payload());
  }
}

//Helper function for printing the response/received stream data
void printResult(StreamData &data)
{

  if (data.dataType() == "int")
    Serial.println(data.intData());
  else if (data.dataType() == "float")
    Serial.println(data.floatData(), 5);
  else if (data.dataType() == "double")
    printf("%.9lf\n", data.doubleData());
  else if (data.dataType() == "boolean")
    Serial.println(data.boolData() == 1 ? "true" : "false");
  else if (data.dataType() == "string" || data.dataType() == "null")
    Serial.println(data.stringData());
  else if (data.dataType() == "json")
  {
    Serial.println();
    FirebaseJson *json = data.jsonObjectPtr();
    //Print all object data
    Serial.println("Pretty printed JSON data:");
    String jsonStr;
    json->toString(jsonStr, true);
    Serial.println(jsonStr);
    Serial.println();
    Serial.println("Iterate JSON data:");
    Serial.println();
    size_t len = json->iteratorBegin();
    String key, value = "";
    int type = 0;
    for (size_t i = 0; i < len; i++)
    {
      json->iteratorGet(i, type, key, value);
      Serial.print(i);
      Serial.print(", ");
      Serial.print("Type: ");
      Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array");
      if (type == FirebaseJson::JSON_OBJECT)
      {
        Serial.print(", Key: ");
        Serial.print(key);
      }
      Serial.print(", Value: ");
      Serial.println(value);
    }
    json->iteratorEnd();
  }
  else if (data.dataType() == "array")
  {
    Serial.println();
    //get array data from FirebaseData using FirebaseJsonArray object
    FirebaseJsonArray *arr = data.jsonArrayPtr();
    //Print all array values
    Serial.println("Pretty printed Array:");
    String arrStr;
    arr->toString(arrStr, true);
    Serial.println(arrStr);
    Serial.println();
    Serial.println("Iterate array values:");
    Serial.println();

    for (size_t i = 0; i < arr->size(); i++)
    {
      Serial.print(i);
      Serial.print(", Value: ");

      FirebaseJsonData *jsonData = data.jsonDataPtr();
      //Get the result data from FirebaseJsonArray object
      arr->get(*jsonData, i);
      if (jsonData->typeNum == FirebaseJson::JSON_BOOL)
        Serial.println(jsonData->boolValue ? "true" : "false");
      else if (jsonData->typeNum == FirebaseJson::JSON_INT)
        Serial.println(jsonData->intValue);
      else if (jsonData->typeNum == FirebaseJson::JSON_FLOAT)
        Serial.println(jsonData->floatValue);
      else if (jsonData->typeNum == FirebaseJson::JSON_DOUBLE)
        printf("%.9lf\n", jsonData->doubleValue);
      else if (jsonData->typeNum == FirebaseJson::JSON_STRING ||
               jsonData->typeNum == FirebaseJson::JSON_NULL ||
               jsonData->typeNum == FirebaseJson::JSON_OBJECT ||
               jsonData->typeNum == FirebaseJson::JSON_ARRAY)
        Serial.println(jsonData->stringValue);
    }
  }
}

I deallocate the Firebase Data objects after every loop, however, I believe, I still don't have enough heap. Do you have any suggestions how to optimize the code and gain more memory?

Any help would be appreciated!

3
  • 1
    why do you use dynamic allocation? it fragments the heap and there is nothing to defragment it
    – Juraj
    Sep 26 '20 at 5:46
  • Hi Juraj, thanks for your reply. I'm doing this for my school project and I'm new to Arduino, so I don't know much about dynamic allocation. Do you mean that there is something wrong with the way I create new Firebase variables (this part of the code: FirebaseData *firebaseData1 = new FirebaseData();)?
    – Nina
    Sep 26 '20 at 7:11
  • FirebaseData firebaseData1; should be good as global variable, but I don't know the Firebase library. how do they do this in the examples of the library?
    – Juraj
    Sep 26 '20 at 7:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.