text:
Adeept Arduino Mega 2560 isn't recognized
So recently, I purchased an Arduino Mega 2560 Kit from Amazon, which was customized from this company called Adeept. But when I tried to plug it into my computer, it didn't recognize it. This means my device manager didn't change in any way, shape, or form. The Arduino IDE that I fully downloaded couldn't upload code, and I also tried using different USB cords, and I tried using another computer as well, but it still didn't work.
Is there a driver that I need to upload or something else that I'm missing?
Thank you for your time :)

ask Adeept ... BTW, if windows does not detect it, then trying Arduino IDE is an exercise in futility


text:
What's the pinout of the Gravity MOSFET power controller board?
I found https://wiki.dfrobot.com/Gravity__MOSFET_Power_Controller_SKU__DFR0457 this board for a non-Arduino project and it does not list the pinout of the JST-PH 2.0 header but it does show it connected to an Arduino so I was hoping people familiar with the Arduino could figure out based on that.

What's hard to understand about that wiring diagram?

It's right here. P1 is the "Gravity" connector. Pin 1 is the control signal (connected to an LED and an optical isolator that switches the MOSFET), Pin 2 is Vcc, Pin 3 is GND.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
PROGMEM: do I have to copy data from flash to RAM for reading?
I have got some difficulties understanding the memory management.
Arduino documentation says, it is possible to keep constants like strings or whatever I don't want to change during runtime in program memory. I think of it as embedded somewhere in the code segment, which must be fairly possible inside a von-Neumann-architecture. I want to make use from that to make my UI menu on a LCD possible.
But I'm bewildered by those instructions to just read and print data from program memory:
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
    Serial.println( buffer );

Why on earth do I have to copy the damn content to RAM before accessing it? And if this is true, what happens to all the code then? Is it also loaded to RAM before execution? How is the code (32kiB) handled then with only 2kiB RAM? Where are those little goblins carrying floppy disks?
And even more interesting: What happens to literal constants like in this expression:
a = 5*(10+7)

are 5, 10 and 7 really copied to RAM before loading them into registers? I just can't believe that.

A global variable is loaded into memory, and is never released from it. The code above only copies the data to memory when needed, and releases it when done. Also note that the code above only reads one byte from the string_table array. That array might be 20KB, and would never fit in memory (even temporarily). You can however load just one index using the above method.

@Gerben: This is a real drawback on global variables, I did not take this into account yet. I get some headache now. And the code snippet was just an example from the documentation. I refrained to program sth. myself before having clarification about the concepts. But I've got some insight now. Thanks!

I found the documentation somewhat confusing when I first read it. Try looking at some real life examples too (like e.g. a library).

AVR is a modified Harvard architecture family, so code is stored in flash only, whereas data exists primarily in RAM when being manipulated.
With that in mind, let's address your questions.

Why on earth do I have to copy the damn content to RAM before accessing it?

You don't need to per se, but by default code assumes that data is in RAM unless the code is modified to specifically look in flash for it (such as with strcpy_P()).

And if this is true, what happens to all the code then? Is it also loaded to RAM before execution?

Nope. Harvard architecture. See the Wikipedia page for the full details.

How is the code (32kiB) handled then with only 2kiB RAM?

The preamble generated by the compiler copies the data that should be modifiable/modified into SRAM before running the actual program.

Where are those little goblins carrying floppy disks?

Dunno. But if you happen to see them then there's nothing I can do to help.

... are 5, 10 and 7 really copied to RAM before loading them into registers?

Nah. The compiler evaluates the expression at compile time. Whatever else happens depends on the lines of code around it.

Ok, I did not know AVR was harvard. But I'm familiar with that concept. The goblins aside, I think I know when to use those copy functions now. I have to restrict use of PROGMEM to data which is rarely used to save CPU cycles.

Or modify your code to use it directly from flash.

But how would this code look like? let's say I have several arrays of uint8_t representing strings I want to put onto a LCD display via SPI. const uint8_t test1[5]= { 0x54, 0x65, 0x73, 0x74, 0x31 }; const uint8_t bla[9]= { 0x62, 0x6c, 0x61, 0x62, 0x6c, 0x61, 0x62, 0x6c, 0x62 }; const uint8_t Menu[4]= { 0x3d, 0x65, 0x6e, 0x75}; how do I bring this data to flash and later on into the SPI.transfer() function, which takes one uint8_t per call.

http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

This is how Print::print prints from program memory in the Arduino library:
size_t Print::print(const __FlashStringHelper *ifsh)
{
  const char PROGMEM *p = (const char PROGMEM *)ifsh;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

__FlashStringHelper* is an empty class that allows for overloaded functions like print to differentiate a pointer to program memory from one to normal memory, as both are seen as const char* by the compiler (see https://stackoverflow.com/questions/16597437/arduino-f-what-does-it-actually-do)
So you could overload the print function for your LCD display so that it takes a __FlashStringHelper* argument, lets call it LCD::print, and then use lcd.print(F("this is a string in progmem"));' to call it.F()` is a macro that ensures the string is in program memory.
To predefine the string  (to be compatible with built-in Arduino print) I have used:
const char firmware_version_s[] PROGMEM = {"1.0.2"};
__FlashStringHelper* firmware_version = (__FlashStringHelper*) firmware_version_s;
...
Serial.println(firmware_version);

I think an alternative would be something like
size_t LCD::print_from_flash(const char *pgms)
{
  const char PROGMEM *p = (const char PROGMEM *) pgms;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

which would avoid the __FlashStringHelper cast.

Arduino documentation says, it is possible to keep constants like strings or whatever I don't want to change during runtime in program memory.

All constants are initially in program memory. Where else would they be when the power is off?

I think of it as embedded somewhere in the code segment, which must be fairly possible inside a von-Neumann-architecture.

It's actually Harvard architecture.

Why on earth do I have to copy the damn content to RAM before accessing it?

You don't. In fact there is a hardware instruction (LPM - Load Program Memory) which moves data directly from program memory into a register.
I have an example of this technique in Arduino Uno output to VGA monitor. In that code there is a bitmapped font stored in program memory. It is read from that on-the-fly and copied to the output like this:
  // blit pixel data to screen
  while (i--)
    UDR0 = pgm_read_byte (linePtr + (* messagePtr++));

A disassembly of those lines shows (in part):
  f1a:  e4 91           lpm r30, Z+
  f1c:  e0 93 c6 00     sts 0x00C6, r30

You can see that a byte of program memory was copied into R30, and then immediately stored into the USART register UDR0. No RAM involved.

However there is a complexity. For normal strings the compiler expects to find data in RAM not PROGMEM. They are different address spaces, and therefore 0x200 in RAM is something different from 0x200 in PROGMEM. Thus the compiler goes to the trouble of copying constants (like strings) into RAM at program startup, so it doesn't have to worry about knowing the difference later on.

How is the code (32kiB) handled then with only 2kiB RAM?

Good question. You won't get away with having more than 2 KB of constant strings, because there won't be room to copy them all.
That's why people who are writing things like menus and other wordy stuff, take extra steps to give the strings the PROGMEM attribute, which disables them being copied into RAM.

But I'm bewildered by those instructions to just read and print data from program memory:

If you add the PROGMEM attribute you have to take steps to let the compiler know that these strings are in a different address space. Making a complete (temporary) copy is one way. Or just print directly from PROGMEM, a byte at a time. An example of that is:
// Print a string from Program Memory directly to save RAM
void printProgStr (const char * str)
{
  char c;
  if (!str)
    return;
  while ((c = pgm_read_byte(str++)))
    Serial.print (c);
} // end of printProgStr

If you pass this function a pointer to a string in PROGMEM, it does the "special read" (pgm_read_byte) to pull the data from PROGMEM rather than RAM, and the prints it. Note that this takes one additional clock cycle, per byte.

And even more interesting: What happens to literal constants like in this expression a = 5*(10+7) are 5, 10 and 7 really copied to RAM before loading them into registers? I just can't believe that.

No, because they don't have to be. That would compile into a "load literal into register" instruction. That instruction is already in PROGMEM, so the literal is now dealt with. No need to copy it to RAM and then read it back.

I have a lengthy description of these things on the page Putting constant data into program memory (PROGMEM). That has example code for setting up strings, and arrays of strings, reasonably easily.
It also mentions the F() macro which is an easy way of simply printing from PROGMEM:
Serial.println (F("Hello, world"));

A bit of preprocessor complexity lets that compile into a helper function which pulls the bytes in the string from PROGMEM a byte at a time. No intermediate use of RAM is required.
It is easy enough to use that technique for things other than Serial (eg. your LCD) by deriving the LCD printing from the Print class.
As an example, in one of the LCD libraries I wrote, I did exactly that:
class I2C_graphical_LCD_display : public Print
{
...
    size_t write(uint8_t c);
};

The key point here is to derive from Print, and override the "write" function. Now your overridden function does whatever it needs to output a character. Since it is derived from Print you can now use the F() macro. eg.
lcd.println (F("Hello, world"));

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
ESP8266, Twilio doesn't send SMS
I've been 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 add the part where it also pushed measurements (temperatures) to Firebase Realtime Database. It even prints in serial that it is connecting to Twilio api, however, I never receive the message.
Here's my code:
#/*
 * Twilio SMS and MMS on ESP8266 Example.
 */
 #include "FirebaseArduino.h"
#include "OneWire.h"
#include "DallasTemperature.h"
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266WebServer.h>
#include <sstream>
#include <iostream>
#include "twilio.hpp"

// Use software serial for debugging?
#define USE_SOFTWARE_SERIAL 0

// Print debug messages over serial?
#define USE_SERIAL 1

// Your network SSID and password
const char* ssid="SSID";
const char* password = "PASSWORD";

// Find the api.twilio.com SHA1 fingerprint, this one was valid as
// of July 2020. This will change, please see
// https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-esp8266-cpp
// to see how to update the fingerprint.
const char fingerprint[] = "BC B0 1A 32 80 5D E6 E4 A2 29 66 2B 08 C8 E0 4C 45 29 3F D0";

// Twilio account specific details, from https://twilio.com/console
// Please see the article:
// https://www.twilio.com/docs/guides/receive-and-reply-sms-and-mms-messages-esp8266-c-and-ngrok

// If this device is deployed in the field you should only deploy a revocable
// key. This code is only suitable for prototyping or if you retain physical
// control of the installation.
const char* account_sid = "SID";
const char* auth_token = "TOKEN";

// Details for the SMS we'll send with Twilio.  Should be a number you own
// (check the console, link above).
String to_number    = "+55555";
String from_number = "+66666";
String message_body    = "Hello from Twilio and the ESP8266!";

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

// 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

String b;
int c;
#define FIREBASE_HOST "firebaseio.com"
#define FIREBASE_AUTH ""

#define ONE_WIRE_BUS 4
/********************************************************************/
// Setup a oneWire instance to communicate with any OneWire devices
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
/********************************************************************/
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

float temp1 = 0;

/*
 * Setup function for ESP8266 Twilio Example.
 *
 * Here we connect to a friendly wireless network, set the time, instantiate
 * our twilio object, optionally set up software serial, then send a SMS
 * or MMS message.
 */
void setup() {
        WiFi.begin(ssid, password);
        twilio = new Twilio(account_sid, auth_token, fingerprint);

        #if USE_SERIAL == 1
        swSer.begin(115200);
        while (WiFi.status() != WL_CONNECTED) {
                delay(1000);
                swSer.print(".");
        }
        swSer.println("");
        swSer.println("Connected to WiFi, IP address: ");
        swSer.println(WiFi.localIP());
        #else
        while (WiFi.status() != WL_CONNECTED) delay(1000);
        #endif

        // Response will be filled with connection info and Twilio API responses
        // from this initial SMS send.

        twilio_server.begin();

        // Use LED_BUILTIN to find the LED pin and set the GPIO to output
        pinMode(LED_BUILTIN, OUTPUT);

         sensors.begin();
         Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);

}

/*
 *  In our main loop, we listen for connections from Twilio in handleClient().
 */
void loop() {
  b = Firebase.getString("002/alarm");
  c = b.toInt();
  Serial.print(c);

   sensors.requestTemperatures();
   temp1 = sensors.getTempCByIndex(0);
   StaticJsonBuffer<256> jsonBuffer;
JsonObject& timeStampObject = jsonBuffer.createObject();
timeStampObject[".sv"] = "timestamp";

JsonObject& root = jsonBuffer.createObject();
JsonArray& timestamp = root.createNestedArray("timestamp");
timestamp.add(timeStampObject);
JsonArray& temperature = root.createNestedArray("temperature");
temperature.add(temp1);

Firebase.push("Sensors/001", root);
   if (temp1 > c) {
        String response;
        bool success = twilio->send_message(
                to_number,
                from_number,
                message_body,
                response,
                media_url
        );
   }

          delay(20000);
}

Thanks in advance!

reduce your code to the minimum code that still exhibits the problem ... remove the firebase and the temperature sonsor code ... send only a fixed text SMS

Hi, thanks for your reply! This is the minimum code. If I remove the part in the loop where it pushes the values to Firebase and it only sends a fixed SMS, when the value (temperature) is too high then the SMS gets send. However, I would also need it to push the values to Firebase. Is it possible that NodeMCU Amica V2 is not powerful enough to do that all in one loop?

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Unable to allocate memory
I'm trying to send a SMS and read data from Firebase with my NodeMCU Amica V2. The  code works fine when I either only send a SMS or only read data from Firebase. However, when I combine this two codes SMS isn't sent. This is the error I get:
+ Connected.
+ Post an HTTP send SMS request.
+ Connection is closed.
+ Response:

31.0630+ Using fingerprint 'BC B0 1A 32 80 5D E6 E4 A2 29 66 2B 08 C8 E0 4C 45 29 3F D0'
+ Connecting to api.twilio.com
- Connection failed.
Last SSL error was:
Unable to allocate memory for SSL structures and buffers.
ERRCODE: -1000

And here is my code:
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <base64.h>
#include "OneWire.h"
#include "DallasTemperature.h"
#include <ArduinoJson.h>
#include <string>
using namespace std;
#include <sstream>
#include <iostream>
#include "FirebaseArduino.h"

// Your network SSID and password
const char* ssid = "*****";
const char* password = "*****";

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

// Find the api.twilio.com SHA1 fingerprint using,
//  echo | openssl s_client -connect api.twilio.com:443 | openssl x509 -fingerprint
const char fingerprint[] = "BC B0 1A 32 80 5D E6 E4 A2 29 66 2B 08 C8 E0 4C 45 29 3F D0";

#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

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

float temp1 = 0;
//float temp2 = 0;
String b;
int c;

String urlencode(String str) {
  String encodedString = "";
  char c;
  char code0;
  char code1;
  char code2;
  for (int i = 0; i < str.length(); i++) {
    c = str.charAt(i);
    if (c == ' ') {
      encodedString += '+';
    } else if (isalnum(c)) {
      encodedString += c;
    } else {
      code1 = (c & 0xf) + '0';
      if ((c & 0xf) > 9) {
        code1 = (c & 0xf) - 10 + 'A';
      }
      c = (c >> 4) & 0xf;
      code0 = c + '0';
      if (c > 9) {
        code0 = c - 10 + 'A';
      }
      code2 = '\0';
      encodedString += '%';
      encodedString += code0;
      encodedString += code1;
    }
    yield();
  }
  return encodedString;
}

String get_auth_header(const String& user, const String& password) {
  size_t toencodeLen = user.length() + password.length() + 2;
  char toencode[toencodeLen];
  memset(toencode, 0, toencodeLen);
  snprintf(toencode, toencodeLen, "%s:%s", user.c_str(), password.c_str());
  String encoded = base64::encode((uint8_t*)toencode, toencodeLen - 1);
  String encoded_string = String(encoded);
  std::string::size_type i = 0;
  // Strip newlines (after every 72 characters in spec)
  while (i < encoded_string.length()) {
    i = encoded_string.indexOf('\n', i);
    if (i == -1) {
      break;
    }
    encoded_string.remove(i, 1);
  }
  return "Authorization: Basic " + encoded_string;
}

void setup() {
  Serial.begin(115200); // 115200 or 9600
  delay(1000);        // Give the serial connection time to start before the first print.
  Serial.println(""); // Newline after garbage characters.
  Serial.println(F("+++ Setup."));

  // ----------------------------------------------------
  Serial.println("+ Connect to WiFi. ");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("+ Connected to WiFi, IP address: ");
  Serial.println(WiFi.localIP());

// ----------------------------------------------------
sensors.begin();
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop() {
      sensors.requestTemperatures();
  temp1 = sensors.getTempCByIndex(0);
  Serial.print(temp1);
  b = Firebase.getString("002/alarm");
    c = b.toInt();
    Serial.print(c);
      if (temp1 > c) {
      // Use WiFiClientSecure to create a TLS 1.2 connection.
  //  Note, using a cert fingerprint is required.
  WiFiClientSecure client;
  client.setFingerprint(fingerprint);
  Serial.printf("+ Using fingerprint '%s'\n", fingerprint);
  const char* host = "api.twilio.com";
  const int   httpsPort = 443;
  Serial.print("+ Connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("- Connection failed.");
    char buf[200];
                int err = client.getLastSSLError(buf, 199);

                buf[199] = '\0';

                Serial.println("Last SSL error was:");

                Serial.println(buf);

                Serial.print("ERRCODE: ");
                Serial.println(err);
///* END snippet from pushdata-io project */
//              return false;
  }
  Serial.println("+ Connected.");
    Serial.println("+ Post an HTTP send SMS request.");
  String post_data = "To=" + urlencode(to_number)
                     + "&From=" + urlencode(from_number)
                     + "&Body=" + urlencode(message_body);
  String auth_header = get_auth_header(account_sid, auth_token);
  String http_request = "POST /2010-04-01/Accounts/" + String(account_sid) + "/Messages HTTP/1.1\r\n"
                        + auth_header + "\r\n"
                        + "Host: " + host + "\r\n"
                        + "Cache-control: no-cache\r\n"
                        + "User-Agent: ESP8266 Twilio Example\r\n"
                        + "Content-Type: application/x-www-form-urlencoded\r\n"
                        + "Content-Length: " + post_data.length() + "\r\n"
                        + "Connection: close\r\n"
                        + "\r\n"
                        + post_data
                        + "\r\n";
  client.println(http_request);
  // Read the response.
  String response = "";
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    response += (line);
    response += ("\r\n");
  }
  Serial.println("+ Connection is closed.");
  Serial.println("+ Response:");
  Serial.println(response);
      }
  delay(5000);
}

Does that mean that the NodeMCU doesn't have enough memory? I also tried changing delay() to milis(), but that didn't solve the problem.
Any help would be appreciated!

There should be enough memory, but all that String concatenation you're doing isn't going to help matters.

Thanks for your reply. Do you have any suggestions on how to modify the code? Sorry, I'm new to Arduino.

Just print each line or part of line separately. You don't need to have it all in one string.

So if I understand you correcly, I should use empty println(" ") between each println() that has a value.


text:
ESP8266 NodeMCU running out of heap
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!

why do you use dynamic allocation? it fragments the heap and there is nothing to defragment it

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();)?

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?


text:
Can't send Twilio SMS using Nodemcu esp8266
I am using Twilio for sending SMS in my project. I am measuring temperatures and if the temperature is too high, an SMS is sent. In my code I also have a read and a push to Firebase Realtime Database. In this case (where there is only one read and one push) everything works fine and the message is sent. However, after adding another set to Firebase the SMS is not sent. The error I get is  "Last SSL error was: Unable to allocate memory for SSL structures and buffers". I also added the command, which prints the free heap just before the message is sent and it prints that I still have 24000 free heap. In other cases, where I did not set values to Firebase, my free heap was also 24000 and the message was sent properly. Do you have any suggestions how to solve this problem?
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 "***"
#define FIREBASE_AUTH "***"
const char* account_sid = "***";
const char* auth_token = "***";
FirebaseData firebaseData1;
FirebaseData firebaseData2;
FirebaseJson tms;
FirebaseJsonArray arr;
String path = "/Test/Stream";
int sms = 0;
String c;
int b;

#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";
String to_number    = "***";
String from_number = "***";
String message_body    = "Hello from Twilio and the ESP8266!";
String master_number    = "***";
String media_url = "";
Twilio *twilio;
ESP8266WebServer twilio_server(8000);
const char* host = "api.twilio.com";
const int   httpsPort = 443;
WiFiClientSecure client;

#if USE_SOFTWARE_SERIAL == 1
#include <SoftwareSerial.h>
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;

unsigned long sendDataPrevMillis = 0;

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");
  if (!res) {
    Serial.println("Failed to connect");
  }
  else {
    Serial.println("connected");
  }
  twilio = new Twilio(account_sid, auth_token, fingerprint);
  twilio_server.begin();
  sensors.begin();
  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  Firebase.reconnectWiFi(true);

  firebaseData1.setBSSLBufferSize(1024, 1024);
  firebaseData1.setResponseSize(1024);
  firebaseData2.setBSSLBufferSize(1024, 1024);
  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");
    Serial.print("FIRST HEAP");
    Serial.println(ESP.getFreeHeap());
    firebaseData2.pauseFirebase(false);

    if (Firebase.getString(firebaseData2, "002/alarm")) {
      if (firebaseData2.dataType() == "string") {
        Serial.println(firebaseData2.stringData());
      }
    } else {
      Serial.println(firebaseData2.errorReason());
    }

    int myInt = firebaseData2.stringData().toInt();
    firebaseData2.clear();

    Serial.println("HEAP BEFORE SET");
    Serial.println(ESP.getFreeHeap());
    if (temp1 < myInt) {
      if (Firebase.setInt(firebaseData2, "/serial/sms", sms))
      {
        printResult(firebaseData2);
      }
      else {
        Serial.print(firebaseData2.errorReason());
      }
    }
    firebaseData2.clear();

    if (temp1 > myInt) {
      firebaseData2.clear();
      Serial.print("HEAP BEFORE SENDING MESSAGE");
      Serial.println(ESP.getFreeHeap());
      String response;
      bool success = twilio->send_message(
                       to_number,
                       from_number,
                       message_body,
                       response,
                       media_url
                     );
     if (!client.connect(host, httpsPort)) {
    Serial.println("- Connection failed.");
    char buf[200];
                int err = client.getLastSSLError(buf, 199);

                buf[199] = '\0';

                Serial.println("Last SSL error was:");

                Serial.println(buf);

                Serial.print("ERRCODE: ");
                Serial.println(err);
     }
    }
    else {
      firebaseData2.clear();
    }
    Serial.print("HEAP BEFORE PUSH");
    Serial.println(ESP.getFreeHeap());
    delay(0);
    arr.clear();
    arr.set("/[0]", temp1);
    arr.set("/[1]", tms);
    firebaseData2.pauseFirebase(false);
    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();
    }
    firebaseData2.pauseFirebase(true);
    firebaseData1.pauseFirebase(true);
    firebaseData1.clear();
    firebaseData2.clear();
    Serial.print("LAST HEAP");
    Serial.println(ESP.getFreeHeap());
  }
}

//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);
    }
  }
}

Thanks for your help in advance!


text:
Setting float to two decimal places
I'm trying to set my temperature measurements to two decimal places. Currently what I get are six decimal places.
Here is my code:
#include "math.h"

...

(in loop)
temp1 = sensors.getTempCByIndex(0);
     temp1 = roundf(temp1*100)/100;

Once I push temp1 to Firebase realtime database there are sic decimals, such as 26.059999. I'm using dsb20 sensor for temperature measurements.
What could be wrong?
Thanks for your help in advance!

Is temp1 a float or a double? How do you transmit it to Firebase?

@EdgarBonet temp1 is defined as a float. This is how I am pushing it to Firebase (using the esp32Firebase library:   arr.set("/[0]", temp1);     arr.set("/[1]", tms);     Firebase.push(firebaseData2, "Devices/602", arr)

Did you try using a double?

In addition to Majenkos answer:
A float cannot take any decimal number. It has a limited change and a limited resolution in that range you could say. So if often happens, that the flat (rounded) value is not a valid float. This is the case for 26.05. There is no valid float value, that is exactly 26.05. So the nearest valid float value is chosen. The following code would always print 26.059999:
float i = 26.05;
Serial.println(i);

since the variable i contains the float number 26.059999 (nearest valid float value to 26.06). That is the reason, why mostly the rounding of floats is only done directly with the outputting/printing. In that stage the number is not longer bound to the limitations of the float type (since it is internally not again saved in that type).

Thanks for your reply. The problem is that I need to use the number for further calculations and also to push it to Firebase Realtime Database. Therefore, is there a similar solution without serial print?

As Majenko wrote you can use the int datatype. But it is unclear to me, why you really need to reduce to 2 decimal places in your database. If you are doing further calculations with that data the extra digits will not hurt. Or are you then just displaying that data form the database? Then the best way would be to round in that displaying program. Or you could send the data to firebase as a string. Then you can do the same rounding as with Serial.print() while constructing the string. Though I don't see the use in that.

one can convert to n decimals with the String Class
float num = 3.14159
String str1 = String(num, 1) // 3.1
String str2 = String(num, 2) // 3.14
String str3 = String(num, 3) // 3.141

float variables don't have a number of decimal places: that's how they get their name: "floating point" - the decimal point floats around as needed.
It's only when you output the value that it's rendered with a fixed (or limited) number of decimal places.  Using Serial.print() the second digit is the number of decimal points:
Serial.println(temp1, 6); // 26.059999
Serial.println(temp1, 2); // 26.06

Thanks for your reply @Majenko. The problem is that I need to use the number for further calculations and also to push it to Firebase Realtime Database. Therefore, is there a similar solution without serial print?

Use an integer but work with a multiple of your value. For two decimal places multiply it by 100, store it in an integer. When you then want to print it divide it by 100 again.

This is my code, but it still doesn't work:    float temp2 = sensors.getTempCByIndex(0);  int temp3 = roundf(temp2*100);  float temp1 = temp1/100;.


text:
How to get the value of a measurement transmitted by a BLE device?
I would like to use a BLE temperature sensor (such as the Inkbird IBS-TH1 Mini BLE Sensor), however, I want to be able to display the temperature measurements in my own website. To do this I am planning to have an ESP32, which would intercept the temperatures sensor's BLE messages (and then send them to Firebase Realtime Database via WiFi). I know how to use the ESP32 to find advertising devices, however, I am not sure how to receive the measurements the sensor is transmitting. I have seen libraries such as the ESPHome or ESP32-mqtt-room, but I was wondering whether there is a way to bypass them? Is it neccesary to use mqtt or mosquito? Or is it possible to achieve this using solely the Arduino BLE library?
Any help would be appreciated!


text:
How to push two values to the same key from Arduino to Firebase
I would like to push two values at the same time (to the same node) from arduino to firebase. I tried to create an array and push the array to firebase, however, that is not working.
Here are the two values that I'm pushing, but I would like to push them to the same unique key:
temp1 = sensors.getTempCByIndex(0);
 StaticJsonBuffer<50> jsonBuffer;
JsonObject& timeStampObject = jsonBuffer.createObject();
timeStampObject[".sv"] = "timestamp";

Firebase.push("Sensors/20/temperatures/001", temp1);
Firebase.push("Sensors/20/temperatures/001", timeStampObject);

How it should look like in Firebase
Thanks in advance!

does firebase allow  what you are trying to do?

I believe so, because you can push an array of values to Firebase.

i think that you have to push properly formatted JSON data ... push only once

I tried pushing it only once using an array. However, I don't know how to add a json object to an array.

JsonObject::crateNestedArray() example may be able to help you.

@hcheung thanks for your help! It solved the problem. This is my code now:
StaticJsonBuffer<256> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add(timeStampObject);
array.add(temp1);
Firebase.push("Sensors", array);


text:
Arduino offline commands
I wanted to know if there is a way for my arduino to keep the last command I sent to it before I disconnected it from my computer. Thanks.

Huh? I think you need to provide a little more detail as to what you are trying to achieve? What do you mean by the last command? Can you provide an example of your work flow? What command, what does the command cause to happen, and what do you mean "keep the last command" before you disconnect. As your question stands, I think that the answer is to just use an external power supply (e.g. a 9 Volt power supply or a battery) plugged into the barrel power connector on the Arduino before you unplug the it from your computer.

what does this mean? ... disconnected it from my computer ... there is more than one possible meaning

You mean the last sketch (i.e. program) you uploaded? It's already kept in the Arduino.

It's even posssible to store something in the Arduino while switching power off and on again, using the EEPROM. (But that's more complicated).

Arduino always store the last sketch you have uploaded. Even if you disconnect your board and then replug it then it follow the same commands that you gave earlier.


text:
I have three load cells can I sum all the three into Arduino to be one output? If yes how?
I am doing stand thrust and I have three load cells to measure the force. I would like to know if I can sum them to gather into the Arduino or I should use a junction box.

Arithmetics is easier than mechanics and electronics. But perhaps that's just because I do not know load cells nor junction boxes.

Do you really want to sum them (the total of the forces applied to each), or do you really want to average them (the average load applied across the whole surface)...? The answer is "yes" in both cases, but you will have to build the right kind of circuit to perform the operation you want - and that will take multiple op-amps to do the job. Simpler to connect each direct with a HX711 each and do maths in code.


text:
Transfer analog value via Bluetooth HC-05 (master) to second HC-05 (slave)
II have setup a UNO and a HC-05 Bluetooth module as a 'Slave', and a NANO and an HC-05 Bluetooth module as 'Master', I believe the comm's work ok as I am receiving values and text, but the analog IN via a pot on the 'Master' (NANO) reads fine on the master Serial Screen, but does not read the same on the Slave (UNO)serial screen,the values received are changing from accurate to inaccurate on during data transfer.
I was hoping for a continuous accurate stream as the pot will be replaced with a 'load cell' and I need to capture weight readings and display them on a time base, I used bluetooth as the load cell and 'Slave' will be approx 5m apart. I would appreciate any help and I can send the sketch if you wish?
Regards, Gordon

do you have a question?

and I can send the sketch if you wish? -- It's not a wish - it's a requirement. There's no chance we can have even the slightest clue what is going on unless you show us your sketch (and by "show" I mean edit your question and include the text of the sketch in the question - not a photo, not a link, the text - and format it correctly with three back-ticks on the line before and three on the line after).


text:
I cannot upload any code to my arduino nano
Arduino: 1.8.13 (Windows Store 1.8.42.0) (Windows 10), Board: "Arduino Nano, ATmega328P"
Sketch uses 934 bytes (3%) of program storage space. Maximum is 30720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x49
An error occurred while uploading the sketch
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x49
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x49
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Do you have the right COM port selected? Is your Nano a cheap chinese clone that may not even have the bootloader installed (I have had that before...)? Has it ever worked, or is this your first attempt with this board?

Does this answer your question? "avrdude: stk500_getsync(): not in sync: resp=0x00," aka Some Dude Named Avr Won't Let Me Upload My Program

First try the "Old bootloader" answer

The old boot loader fixed it for me. A lot of the Chinese boards I used have that issue.

For me selecting the ATmega328P (Old Bootloader) from the Tools --> Processor menu in the Arduino IDE solved the problem.
See: https://gyorgybalassy.wordpress.com/2020/10/16/arduino-programmer-is-not-responding-not-in-sync-error/

I had the same problem with an Arduino Micro. When the upload starts, press once the reset button.


text:
How to calibrate an accelerometer?
I'm confused about a few points on how to best calibrate an accelerometer, whose data will be used in an orientation sensor fusion algorithm.
As a summary, the most common approaches I've seen take measurements in 6 different orientations (1G in +x, -x, +y, -y, +z, -z), to then arrive at a max, min measured value. Offsets are then calculated as averages: (max - min)/2. And then a scaling factor is calculated. There's a few aspects of this that I'm unclear about, and was hoping it's okay to ask in a single question, since they are related.
1) the examples calculate the average as written above, rather than sum all vals / N vals. Isn't that approach more error-prone?
2) should the offset per axis be calculated once for each orientation, and then summed?
3) what's the best approach to calculate scale bias?
Example 1 (pseudo-code):
chordlengthX = (max - min)/2
chordlengthY = (max - min)/2
chordlengthZ = (max - min)/2

avg_rad = (chordlengthX + chordlengthY + chordlengthZ)/3

scaleX = avg_rad/chordlengthX

calibratedX = (x - offset)*scaleX

Example 2:
rawrange = max - min
refrange = refmax - refmin // 1G??

calibratedX = (((x - min)*refrange)/rawrange) +refmin

Something else altogether (as you can probably tell I need to revise my maths)?
4) if my surface is not completely level, I cannot trust my measurements since my 1G reference is not accurate?

Most accelerometers are usable out of the box.  (It is the magnetometers that are difficult to use w/o calibration.)
That said, example 1 looks good until the last line.  You need an x-offset which is simply the difference between the x-maximum and x-minimum.
Consider how the coordinates of the X, Y and Z values of an accelerometer would appear if plotted in 3D space.  One that is perfectly aligned would appear spherical.  But if one of the sensors is more sensitive than the others, the 3D plot might take on an egg shape.  You have corrected for this in the first 5 lines of example 1.
Now, if one of the sensors is not centered the 3D plot would be shifted off the 0,0,0 point of the 3D plot.  You can correct for that by finding the  x-offset, y-offset and z-offset.
You should not need to find the value for 1G.  You should not need to find a perfectly flat surface. To calibrate you need to rotate the accelerometer smoothly about its center.  Take care not to expose the accelerometer to greater than 1G during calibration.  Rotate the accelerometer in a random fashion until you are satisfied that all 3 sensors have experienced their most negative and most positive values.

Thank you for taking the time to answer. Apologies for being dumb, but still confused about a couple of points. What's the error in the last line of example 1? From my understanding of your explanation, it seems it should be correct. We subtract bias, and then multiply by the sensitivity? I'm probably missing something. Secondly, if the sensor is moving about the wouldn't the maximum and minimum just be the range from the datasheet, for example if I'm yanking it about quite quickly?

It would be good if you carefully selected your variable names.  Even in fake code.  It was easy to assume the 6 "max" & "min" values were actually "x-maximum", "x-minimum", "y-maximum", "y-minimum", ect.  But I did not know what "x" was in the last line of example 1.  If I needed to guess, I think the last line is an example of how to use the 2 calibration values you seek.  And might be written: "calibratedX = (x-raw - x-offset) * scaleX".  Take care to smoothly rotate the accelerometer during calibration. Do not expose it to > 1G by jerking it around. Again, calibration may not be necessary.

Thank you again for taking the time to help out. I really appreciate it. I'll test this tomorrow and see how it goes. :)


text:
Obtaining angular velocity from quaternion data (BNO055)
I'm able to get quaternion data from the BNO055 sensor, and would like to convert these to angular velocity for my project. I know you can pull the gyroscope directly for the data, but from what I understand using quaternions and converting those is more robust?
I found a function that does this in a Adafruit repository for the sensor. However, I'm not sure what the Delta time variable should be equal to, in relation to the sample frequency. Could anyone advise?
Here is the function code:
  Vector<3> toAngularVelocity(double dt) const {
    Vector<3> ret;
    Quaternion one(1.0, 0.0, 0.0, 0.0);
    Quaternion delta = one - *this;
    Quaternion r = (delta / dt);
    r = r * 2;
    r = r * one;

    ret.x() = r.x();
    ret.y() = r.y();
    ret.z() = r.z();
    return ret;
  }

And the link

Thank you for your time everyone. I really appreciate it.

I do not know how to interpret the data given by that sensor, but from
reading the code, the meaning of dt is pretty clear.
The function you show assumes that the sensor started in the reference
orientation (quaternion one), then rotated at a constant angular
velocity until it reached the current orientation (quaternion *this),
and this rotation happened over a time dt.
Then dt is the time required for moving from the reference orientation
to the orientation described by the quaternion *this. You should
probably check out the sensor's datasheet for more details on how the
orientations are provided.

Hi again Edgar and thanks for your response. I'll check and update the question.


text:
How to write nonblocking code, for polling sensor at 100 Hz
I'm using this piece of code to try to poll an IMU sensor at 100 Hz (for a AHRS sensor fusion library).
void loop(void)
{
  // nonblocking code variables
  static uint32_t last_ms;
  uint32_t ms;
  // delay between samples
  ms = millis();
  if (ms - last_ms < 10) return;
  last_ms = ms;

  sensor_data (); //...

My 1st question is should I be declaring last_ms as a global variable instead of static?
Also, should this code be at the beginning or end of loop? My understanding is we are basically checking how long the previous loop took. And if it took less than 10 ms (100 Hz) we do nothing. But doesn't that mean that we might still get deviation from 100 Hz due to the time it takes to complete loop (about 2-5ms in my case), so effectively it's 10 ms + loop complete time?
Sorry if this is a stupid question.

see the BlinkWithoutDelay example. I guess it is easy to modify it from 1 Hz to 100Hz

If you want to run something at 100Hz you probably want to use a timer interrupt rather than fiddling with delay values.

I will experiment with that thank you

static/global; meh, same thing really.  2. it should be 100Hz since you restart the clock before running the task, so it won't jitter unles the task takes longer than 10ms, but if that's the case there's no way it will ever work anyway.

Can you configure this particular device to use interrupts rather than polling?

it's the BMX160 from Bosch, and I think so. I will experiment with that, but wanted to understand logic of this also.

should I be declaring last_ms as a global variable instead of
static?

Local static is better, as it limits the scope of the variable to just
where it is needed. Consider making it global only if the code is part
of a tutorial meant for beginners which may be confused by the keyword
static.

should this code be at the beginning or end of loop?

The conditional early return only makes sense if loop() has nothing
more to do once the sensor data is handled, thus this should go at the
very end of loop(). However, if loop() does more than just handle
this data, I think it would be cleaner to avoid the early return: either
put this in a separate function (which can return early), or condition
the handling of the sensor on ms - last_ms >= 10.

My understanding is we are basically checking how long the previous
loop took.

No. The test is looking at how much time has elapsed since the previous
time last_ms was updated, which could be many loop() iterations ago.

But doesn't that mean that we might still get deviation from 100 Hz
due to the time it takes to complete loop (about 2-5ms in my case), so
effectively it's 10 ms + loop complete time?

Indeed. With this logic, 10 ms is the minimum time between calls
to sensor_data(). If you want to ensure an accurate average polling
time, you should update last_ms by adding 10. You will still have
sole jitter though.
A small note about millis(): since the value is updated every
1.024 ms, it occasionally has to jump by two units at once, and has
therefore 1 ms of jitter. For a period as short as 10 ms, I
would rather use micros(). For example:
const uint32_t POLLING_PERIOD = 10000;  // 1e4 us = 10 ms

// Call this from loop()
void handle_sensor()
{
    static uint32_t last_us;
    if (micros() - last_us < POLLING_PERIOD) return;
    last_us += POLLING_PERIOD;
    sensor_data();
    // ...
}

Edit: About why last_us has to be incremented by a constant
amount, consider this alternative:
void handle_sensor()
{
    static uint32_t last_us;
    uint32_t now = micros()
    if (now - last_us < POLLING_PERIOD) return;
    last_us = now;
    sensor_data();
    // ...
}

The code following the if ... return; line will be executed when the
tested condition is false, i.e. when now - last_us >= POLLING_PERIOD.
It may happen that we sometimes have strict equality (now - last_us == POLLING_PERIOD) but, since any code execution takes time, sometimes
now - last_us will be strictly larger than POLLING_PERIOD. Every
time this happens last_us will be incremented by more than
POLLING_PERIOD. This means that the small timing errors accumulate.
If, instead, last_us is updated by adding a constant amount, we still
have timing errors (because of the time needed to execute any code), but
they are not cumulative. In other words, we have jitter, but the
average polling frequency is right.

Thank you very much for the detailed answer Edgar. Good to see that you're still helping out newbies on here. I'll try the updated code using micros. To check I understood, we are using micros to avoid jitters. Still a bit confused on the difference between adding the polling period to our comparison variable, instead of comparing Millis to Millis. I feel I'm missing something, because to me it looks like they both achieve the same thing which is: wait until 10 ms have passed and only then start processing data.. Although you imply there is a difference.

Thank you for the edit, I understand now.

The time range your sensor code will be executed is 10ms to 10ms + the execution time of the first part of the loop (until the return) and the execution time outside of loop(). These additional times don't always apply, but in the worst case you can have up to that additional delay (because it means you are checking the millis() value only so often).
The mentioned additional delay is rather short (microseconds realm). Your sensor code is only executed, when the time is reached. As long as you don't disable interrupts, the Timer0 interrupt will continue to count further for millis(), so its value will increase independently from the execution time of your sensor code.
That is as long as the sensor code also doesn't take longer than 10ms (or a bit less, accounting for some overhead). As your sensor code only takes up to 5ms (according to your question), you should be safe here.
If millis() is accurate enough for you I cannot say. Thats up to your exact requirements. For more accurate timing an own timer interrupt would be better, though that also limits you with what you can do. Inside an interrupt you cannot execute code, that relies on interrupts (like communication over Serial or I2C). Depending on your sensors using your above code is already enough and should work good.

should I be declaring last_ms as a global variable instead of static?

There is no definitive answer to that, but generally it is good to limit the scope of variables to the minimum needed (to avoid possible conflicts). last_ms is not needed anywhere else, so creating it locally and static is a good way to do it. Memory wise it doesn't really make a difference.

Hi Chris, thank you for another detailed answer.


text:
How do I check if my board is connected to the internet?
Let me get this straight, I'm trying to see my ESP32 is connected to the internet or not, not Wi-Fi, as at times the board is able to connect to Wi-Fi, but not able to contact any servers, due to router issues.
I want to check, if the board is connected the internet or not, how do I do this?
What I have so far:-
char ssid[] = "Youreally";
char pass[] = "WannaKnow";

void setup(){
WiFi.begin(ssid, pass);
Serial.begin(115200);
}

void loop(){
  if (WiFi.status() != WL_CONNECTED) {
  Serial.println("Connected");
  }
}

ping a known server

I usually ping 8.8.8.8 - Google's DNS servers.

@Majenko What is the maximum frequency allowed for those

and where can I find information about this

No idea. It's a massive cluster of globally distributed servers, and a few pings would disappear amongst the huge amount of DNS traffic.

So, I can contact it frequently without getting banned

Depends what you term "frequently". Once every few minutes or so is no problem.

What does "freaquently" mean for you? Once a second, once per hour? Isn't it enough to check right after the wifi setup? Whatever service you use on the internet would give you an error once it is not reachable...

To make Pinging easier FabGL has a ping example and an ICMP class.

@Majenko Maybe around 5 seconds

5 seconds is way too often, and short polling is not needed for low-lag detection. Just connect to any public websocket server, pass a callback to onEvent, listening for WStype_DISCONNECTED event type, upon which you can be 90% sure the internet is out. I would then use an http request to try to download my own website's robots.txt to confirm. No pinging, no policy violations or ISP consternation.

As you would be having some sort of connectivity except WiFi you could check that on regular basis in your loop, for instance when using MQTT I would check:
if (!mqttClient->connected())

and then based on the result I would test:
if (WiFi.status() != WL_CONNECTED)

so I can handle the relevant layer.


text:
Control laser diode from digital pin
I have a 200mw laser module that came with a 3v 1A power supply. I want to control it from a digital pin on an arduino uno.
Can I use a simple voltage divider like this or is there some consideration to current I'd need to take into account? The laser module was quite expensive so I'm hesitant to try it out.

simulate this circuit – Schematic created using CircuitLab

the arduino is not able to supply the necessary current ... other than that, your question is not related to the arduino, so it is off topic here

Your solution does not work, mainly because GPIOs are not intended to source current higher than a few mA. If you want the laser diode to emit a reasonable amount of power, you need to drive it with a transistor. A MOSFET-based low-side-switch would probably be the easiest solution. But note that you still need to limit the current, e.g. by using a series resistor.
Even better would be to use a constant current driver (you can use any led driver with appropriate rating).
If the power supply that came with the laser diode is a constant current source, it might be possible to switch its output directly (without resistor), but that depends on how it behaves when it is open-circuited.


text:
What kind of distance sensor are optimal to measure distances to surfaces at an angle to the sensor?
I want to try measuring the orientation of an object by measuring the distance between a "flat" surface to the surface of the rotated object. The problem I assume is that if the surface being measured is at an angle to the distance sensors, the beamed lights from laser or infrared proximity sensors, for example, would be reflected at an angle and not return to the sensors at all.

Would this actually happen, or am I misunderstanding some properties of these sensors? Which sensors would work in this kind of application, and which sensors would not work for sure (I read from another post that ultrasonic sensors would definitely not work in this case)?
(Added a crude sketch of the problem I think is going to happen)

What type of surface does the object have? Is it rough or reflective?

I'm looking to try to measure the orientation of a truck-trailer surface, so I imagine it would be a smooth surface of painted sheet metal. I'm not sure how reflective this would be considered, but something like: https://ryder.com/used-trucks/-/media/Project/UsedTrucks/UVS/Images/Vehicles/Types/Truck-Types---Trailers/truck_types_dry_trailer_image.jpg?h=468&w=624

You can try a TOF (time of flight) laser distance sensor. That normally works, when the surface is not too reflecting for the laser light

A laser distance sensor will work when the surface is not like  a mirror. The more power you use the better the sensor will work (but be careful about laser safety). An ultrasonic sensor on the other hand is less affected by the reflectivity of the surface, but sees a very wide signal if the surface is not perpendicular. This probably won't give you usable measurements.

Honestly, I don't think anyone here can give you a definitive answer. The results depend on many variables in your whole application setup. I would suggest just testing it. For this the only really viable options (besides some mechanical solution) are ultrasonic or laser TOF. I would start with ultrasonic, since these are really cheap. If you don't get good results with them, try a TOF sensor.

Using ultrasonic sensors would be a very sensible solution in your use case.
I am currently working on a similar project with a company in Denmark, where the objective is to detect cars on parking spaces. For this task, I used two of these ultrasonic sensors from DFRobot for the prototype:
https://www.dfrobot.com/product-1935.html
They were very easy and simple to setup on an Arduino UNO and worked perfectly fine even when two were sensing at once.
Though I have to mention, that they need a serial connection each, but this can be worked around using a multiplexer or a developer board with more serial connections.
I also found that the ultrasonic sensors work better than time of flight sensors in outdoor conditions. They are very robust and wont be as affected by dirt for instance.
A little speck on the lens of a ToF sensor and it will be rendered useless.
Ultrasonic sensors are also widely used in the car industry for parking aid solutions where they have to detect lots of different surfaces and be very precise in doing so.
Ultrasonic sensors are great. And yes, they can interfere with each other, but as long as you dont put them on top of one another, it should not be an issue.
You should be able to detect the distance to a trailer in two different places using ultrasonic sensors as long as the trailer is within the sensors range.

Hey, thanks for the response! I've read online that ultrasonic sensors don't work with angled surfaces (around 5 degrees off perpendicular). What has been your experience with this? Would the readings give completely wrong numbers, or simply numbers that are close, but with a larger margin of error? Or has this not been a problem at all in your experience? Thanks!

It will depend on what sensors you'll choose. You can easily find sensors with more play than 5 degrees. I found that the one i linked will work until around 12-14 degrees, but if this is not enough, you could perhaps use two sensors attached to stepper motors at each of the trailer and let them spin around sensing at different angles. Alternatively, you could construct some kind of parabolic array. This will require a few more sensor though.


text:
Does natural outdoors wind affect the readings of an ultrasonic sensor significantly?
I am thinking of using an ultrasonic sensor outdoors, and am wondering if the presence of wind (say up to 20km/h) would significantly impact the accuracy of the readings, or would this not be a large concern?
Thanks.

why would "natural" and "outdoors" make a difference? ... it is air movement ... run some tests using a hair dryer

Ah that's true, I added outdoor to give an idea of the wind speeds I'm considering. Your idea with using a hair dryer is pretty good, I'll give that a shot, thanks!

google ultrasonic anemometer

you did not say what you are measuring with the ultrasonic sensor, or how it is configured ... if it is a distance sensor module with the emitter and detector beside each other, then my gut feeling tells me that wind from directly in front, or directly in back would not make much difference ... any side to side air movement would increase the length of the sound travel .... i could easily be very wrong on this

As speed of sound is around 1235 km/h at 25°C, it' won't do so much difference for 20km/h (in the same direction as measurement) - it's under 2%

@KIIV i think that wind in same direction would not affect it much, because the sound propagation would speed up in one direction and slow down in the other direction

@jsotola true, completely forgot about that


text:
Grounding Arduino UNO with external voltage source
I was experimenting with external power supplies and noticed that the only way the Arduino can communicate with an externally powered sensor (through SPI) is when the GND pin under power AND the GND pin under AREF on the UNO is connected to the external ground?
From what I understand, both these pins are connected to the boards mutual ground (i.e. they are already internally connected)?
In the attached image both the orange and yellow wires were required and would not work individually.
I feel that either this shouldn't be the case or I am simply missing something and would appreciate an explanation.
Thanks!

Looks like orange is plugged into VIN to me...

you may be misunderstanding why a common ground is required when communicating with external devices

The circuit in the image shows the plan of the Arduino Uno, as you can see the GND pin under AREF and in the GND under the Power pin VCC are connected.
you can double-check this with a tester and figure it out.
so yes, they are internally connected.
now, in your breadboard you have connected GND to VIN, that's the problem, Vin is an input voltage that is regulated to supply 3.3V and 5V.

So remember to share grounds with external voltage supplies (DC-DC), that set the circuit to the same reference.

I would think connecting VIN to ground would cause the power supply to fail.

yes, sir,  it would.

...And it might even let out the "magic smoke" that makes electronics work.

haha almost! but the MOSFET down there doesn't let the "magic smoke" come out.


text:
My two slave SPI setup on arduino not working correctly
I am trying to connect a DPS310 and an ADXL345 to my Arduino using 4 wire SPI. When the individually tested (i.e. each has its own script), the output is correct, however when the scripts are combined the ADXL output is garbage, but the DPS functions.
What we expect to see:
Temperature = 24.14 *C
Pressure = 857.88 hPa
X: -4  Y: 4  Z: 29

What we actually see:
Temperature = 24.14 *C
Pressure = 857.88 hPa
X: 0  Y: 0  Z: 0    // and does not change when tilted

When the DPS310 line is commented out, the ADXL works fine (this line is indicated in script)
The whole script (with the faulty line indicated):
#include <SparkFun_ADXL345.h>
#include <Adafruit_DPS310.h>

// ADXL obj
#define ADXL345_CS   9 // SPI pin
ADXL345 ADXL = ADXL345_CS; // Instantiate obj with CS pin
int x = 0, y = 0, z = 0;

// DPS obj
#define DPS310_CS   10 // SPI pin
Adafruit_DPS310 dps; // Instantiate obj (pin is set in setup)
sensors_event_t temp_event, pressure_event;

void setup() {
   Serial.begin(115200);
   while (!Serial) delay(10);

   // ADXL SETUP
   digitalWrite(ADXL345_CS, LOW); // START COMM
   Serial.print("ADXL345: ");
   ADXL.powerOn();
   delay(50);
   ADXL.setRangeSetting(16);
   ADXL.setSpiBit(0);
   ADXL.set_bw(ADXL345_BW_12_5);
   ADXL.setInterrupt(0x84, true);
   ADXL.setAxisOffset(0, 0, 5);
   ADXL.readAccel(&x, &y, &z);
   if(x != -1 && y != -1 && z != -1) {
     Serial.println("[PASSED]");
   } else {
     Serial.println("[FAILED]");
   }
   digitalWrite(ADXL345_CS, HIGH); // END COMM

   // DPS SETUP
   digitalWrite(DPS310_CS, LOW); // START COMM
   Serial.print("DPS310: ");
   if (! dps.begin_SPI(DPS310_CS)) { /////////////////PROBLEM LIES HERE//////////////////
      Serial.println(" [FAILED]");
   }
   Serial.println(" [PASSED]");

   dps.configurePressure(DPS310_64HZ, DPS310_64SAMPLES);
   dps.configureTemperature(DPS310_64HZ, DPS310_64SAMPLES);
   digitalWrite(DPS310_CS, HIGH); // END COMM
}

void loop() {
    digitalWrite(ADXL345_CS, LOW);
    ADXL.readAccel(&x, &y, &z);
    digitalWrite(ADXL345_CS, HIGH);

    digitalWrite(DPS310_CS, LOW);
    dps.getEvents(&temp_event, &pressure_event);
    digitalWrite(DPS310_CS, HIGH);

    Serial.print("Temperature = ");
    Serial.print(temp_event.temperature);
    Serial.println(" *C");
    Serial.print("Pressure = ");
    Serial.print(pressure_event.pressure);
    Serial.println(" hPa");

    Serial.print("X: ");
    Serial.print(x);
    Serial.print("  Y: ");
    Serial.print(y);
    Serial.print("  Z: ");
    Serial.println(z);

    delay(50);
}

I think the fault might lie in the classes written for these devices, for instance maybe they were written for single SPI device or have different frequencies/modes? (I'm probably wrong though XD). I have not yet tried to setup the SPI for each device manually (programming commandment: do no reinvent the wheel), so any help would be greatly appreciated.

set CS pin of the second device HIGH before initializing the first device

@Juraj I just tried that and it failed. Even tried to put both HIGH as well as delay for 2s before initializing anything

The ADXL345 uses SPI_MODE3 and DPS310 the SPI_MODE0. The libraries for these devices don't use SPI transactions, but set the settings only in begin(), so they can't be used together.
Your options to solve this is either to put one sensor on software SPI or to put one or both sensors on I2C.
The ADXL345 can be used as I2C device. Its library supports I2C with the constructor when no parameters are provided. Does your module have an option to wire it to I2C?
The Adafruit library for DPS310 has built-in software SPI, so you can use it with any set of pins. And it too supports I2C.

I was afraid of that, any idea how I can modify the libraries to operate with each other? I tried to write a basic SPI script to do the transactions by following what the libraries did, however the libraries are far to complicated for me and so it was to no avail. Or should I rather try to implement my own independent SPI script (keeping in mind I'm very new to this)?

@newt, I enhanced the answer

Thanks, switched the ADXL to I2C and kept DPS in SPI mode and it worked!


text:
OTA over MQTT for ESP32
Before starting working, I am just researching around how can I achieve OTA over MQTT in ESP32 in using Arduino IDE.
The process I understand the esp listen to MQTT messages and then received that file over MQTT(not fully at once may be in chunks). And then stored that in flash at specific address. And then change boot loader configuration for executing new firmware.
Here I am confused how can I change boot loader configuration settings to execute the new firmware memory address ??
Any help is appreciated.
is there any out of box library available for this work? Please share reference. I can take reference from there.
Thanks

Everything is done for you using the Update library. Just feed it the right data.

@Majenko I am looking in to that will keep you posted. Thanks

@Majenko I hope Update library can be used with FreeRTOS as well.

the Update library is part of the esp32 Arduino boards support package by Espressif

I am not familiar with OTA for ESP32 but with SAMD21 using ArduinoOTA library and there the download is not done over MQTT but HTTPS.
Link to download is sent over MQTT but that's where it ends, download over HTTPS, verification of received data using checksum and bytes count and once InternalStorage.apply() executed it swaps the program downloaded with the older version and reboot.
EDIT:
As per Juraj request, I am adding the code as a guide you can use to get ideas. You can't run it as is, you would need to add variable declaration and wrap it in a function.
As updating wrong file will most likely brick your board, I would just add that before running this code I check the filename to make sure it is the correct BIN for the board downloading it, I am using constants like WIFI, GSM, and board name and expect to see them in the filename.
I also send the file length from the server as part of the MQTT update request and check it against my own bytes count and I am not relying on TCP to provide an error on corrupted data and do a my own checksum test.
#include <ArduinoOTA.h>  // https://github.com/jandrassy/ArduinoOTA

// Access the file
HttpClient client(*transport, upgradeServer, upgradePort);
client.get(upgradePath);

int statusCode = client.responseStatusCode();
  /*
   0   HTTP_SUCCESS
  -1  HTTP_ERROR_CONNECTION_FAILED  The end of the headers has been reached.  This consumes the '\n' Could not connect to the server
  -2  HTTP_ERROR_API                This call was made when the HttpClient class wasn't expecting it to be called.
                                    Usually indicates your code is using the class incorrectly
  -3  HTTP_ERROR_TIMED_OUT          Spent too long waiting for a reply
  -4  HTTP_ERROR_INVALID_RESPONSE   The response from the server is invalid, is it definitely an HTTP server?
  */

if (statusCode != 200) {
  client.stop();
  // here you can do something with statusCode like notifying over MQTT
}

long length = client.contentLength();
if (length == HttpClient::kNoContentLengthHeader) {
  client.stop();
  //Server didn't provide Content-length header, abort.
  return;
}

if (!InternalStorage.open(length)) {
  client.stop();
  // Not enough space to store the file, abort.
  return;
}

// Start update, length holds the file size in bytes

client.setTimeout(5000);
byte b;
bool ok;
long fileLength = length;
unsigned long otaStartMillis = millis();
int localChecksum = 0;

while (length > 0) {

  ok = client.readBytes(&b, 1);
  if (!ok) {
   // Abort, stopped after ((millis() - otaStartMillis)/1000) Sec
    return;
  }

  InternalStorage.write(b);
  int bValue = (int)b;
  localChecksum = localChecksum + bValue;

  length--;
}

InternalStorage.close();
client.stop();

if (localChecksum != remoteCkecksum) {
 // Checksum mismatch, abort.
  return;
}

if (length > 0) {
  // Timeout at byte length, abort.
  return;
}

InternalStorage.apply(); // this doesn't return, board should restart

Serial.println("Update failed"); //shown only if update failed

Another opportunity to thank Jurak for this library!

In my case, the ESP32 doesn't have access to public network. So I will prefer to send the file over MQTT from server side and client(ESP 32) will receive that and do the required things.

@Abhishekbhatia, how does the ESP32 do MQTT without access to the server?

@Juraj I mentioned that, In my use case ESP 32 doesn't have access to public network. It is connect to MQTT server hosted on edge device(They are on private network) . I just don't wanted to use http.

@Juraj would you suggest me which library is better to use for my use case ArduinoOTA or update ??

@Abhishekbhatia Update. because esp32 boards support package has a libray named ArduinoOTA. you would have to delete it to use the generic ArduinoOTA. The  generic ArduinoOTA only wraps the Update library. Generic ArduinoOTA is useful for esp32 with W5500 or enc28j60 Ethernet module.


text:
ArduinoJson library parsing error
I am trying to retrieve JSON mqtt message I received in ESP32.
void mqttMsgCallback(char* topic, byte* payload, unsigned int length) {
    payload[length] = '\0';
    String _message = String((char*)payload);
    String _topic = String(topic);
    if (_topic.equals("Sys.GetInfo/"+getMacAddr()) == 1)
    {
      Serial.println("Message arrived for sys.GetInfo");
      StaticJsonDocument <256> msg1;
      Serial.println(_message);
      deserializeJson(msg1,_message);
      String callbackTopic = msg1["callbackTopic"];
      Serial.println(callbackTopic);
    }
}

The issue is when I publish mosquitto_pub -t "Sys.GetInfo/2462ABFC2CD0" -m "{"callbackTopic" : "1234"}" it works well like callbackTopic as 1234.
but when I publish mosquitto_pub -t "Sys.GetInfo/2462ABFC2CD0" -m "{"callbackTopic" : "xyz"}"  it prints callbackTopic value as null.
Please point me if I an missing something.
Arduino version 1.8.15
ArduinoJson : 6.18.2
Borad : ESP32
Thanks

Check the return value of deserializeJson() to see if it can even parse it as valid JSON.  Maybe you need '{"callbackTopic" : "xyz"}' (single quotes round the outside) to preserve the quotes on the inside.

@Majenko it works when i publish like '{"callbackTopic" : "xyz"}'. Thanks
why the message with "" works when callbackTopic value is numeric

Probably because the value is numeric. 1234 is a valid "thing" - xyz isn't.  "xyz" is, though, and if your shell is stripping the " because it's not either escaped or encapsulated within single quotes, then it can't parse xyz as a valid "thing".

payload[length] = '\0'; how do you know there is a length + 1 position available?

Your shell is stripping the " from inside the string. If you run the command:
$ echo "{"callbackTopic" : "xyz"}"

you get:
{callbackTopic : xyz}

so you see all the quotes are stripped. xyz isn't something that ArduinoJSON can parse. But 1234 is, so with the quotes stripped it's still considered valid.
You need to ensure the quotes aren't removed. There's two ways of doing this: escaping them, or encapsulating the string in single quotes which gives a more "literal" interpretation of the contents than double quotes:
Escaping:
"{\"callbackTopic\" : \"xyz\"}"

Single quotes:
'{"callbackTopic" : "xyz"}'

Either of those when used as a parameter to a command work - like:
$ echo '{"callbackTopic" : "xyz"}'
{"callbackTopic" : "xyz"}

To parse an ArduinoJSON one simply needs to
  String JSONpayload = "some JSON here";
  StaticJsonDocument <512> geoLocationInfoJson;
  DeserializationError error = deserializeJson(geoLocationInfoJson, JSONpayload);
  if (error) {
    this->mserial->printStrln("Error deserializing JSON");
  }

To use the values within the StaticJsonDocument one first needs to
if ( geoLocationInfoJson.isNull() == true ){
  String dataStr="NULL geoLocation data.\n";
  Serial.print( dataStr);
  return true;
}

next, is required to verify if a key exists. If TRUE, then is mandatory first to get the desired value into a corresponding data type, like below, and only afterward work on it, for instance, send it as a BLE message string:
if(this->interface->geoLocationInfoJson.containsKey("lat")){
  float lat = this->interface->geoLocationInfoJson["lat"];
  dataStr += "Latitude: "+ String(lat,4) + "\n";
}
if(this->interface->geoLocationInfoJson.containsKey("lon")){
  float lon = this->interface->geoLocationInfoJson["lon"];
  dataStr += "Longitude: "+ String(lon,4) + "\n";
}

if(this->interface->geoLocationInfoJson.containsKey("regionName"))
  dataStr += String(this->interface->geoLocationInfoJson["regionName"].as<char*>()) + ", ";

The full code above is available on this GitHub repository:
https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries

what question does this answer?

The one of successfully parsing an arduinojson object. And access key, value pairs it holds

that is not the question asked on top of this page

Read between the lines ?

the existing accepted answer shows what the problem was

As I mentioned before. Read between the lines.