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 Commented Sep 26, 2020 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();)? Commented Sep 26, 2020 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? Commented Sep 26, 2020 at 7:54

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.