How can I include a body while sending a POST request using HTTP AT commands with a SIM7000A module and an Arduino? - c++

I'm crossposting this from where I posted it on the Arduino forum in hopes that maybe someone here has an answer. I am working on a project that involves sending POST requests to a Twilio function using an Arduino Uno and a SIMCOM SIM7000A breakout board using AT commands. So far with the Uno, I can only POST an empty request that contains headers but no body. The following code is a test sketch where I am POSTing to a RequestBin repository.
#include <AltSoftSerial.h>
unsigned char data = 0;
AltSoftSerial SIM7000;
char incomingChar;
void setup() {
Serial.begin(9600);
SIM7000.begin(19200);
// put your setup code here, to run once:
SIM7000.print("AT+CMGF=1\r"); //put in text mode
delay(100);
SIM7000.print("AT+CGDCONT=1\"IP\",\"super\"\r"); //create profile. "super" is APN for twilio super sim
delay(1000);
SIM7000.print("AT+COPS=1,2,\"310410\"\r"); //log on to AT&T network
delay(5000);
SIM7000.print("AT+SAPBR=3,1,\"APN\",\"super\"\r"); //create SAPBR profile. same APN.
delay(300);
SIM7000.print("AT+SAPBR=1,1\r");
delay(2000);
Serial.println("Setup complete. Module should be online and fast-blinking\n from successful SAPBR profile setup.\n Entering loop. Send \"CHECK\" to test POST");
}
void loop() {
SIM7000.print("AT+CMGL\r");
if (SIM7000.available() > 0) {
incomingChar = SIM7000.read();
if (incomingChar == 'C') {
delay(10);
Serial.print(incomingChar);
incomingChar = SIM7000.read();
if (incomingChar == 'H') {
delay(10);
Serial.print(incomingChar);
incomingChar = SIM7000.read();
if (incomingChar == 'E') {
delay(10);
Serial.print(incomingChar);
incomingChar = SIM7000.read();
if (incomingChar == 'C') {
delay(10);
Serial.print(incomingChar);
incomingChar = SIM7000.read();
if (incomingChar == 'K') {
delay(10);
Serial.print(incomingChar);
incomingChar = "";
Serial.println(F("\nGOOD CHECK"));
Serial.println(F("SENDING POST REQUEST NOW")) ;
sendText();
Serial.println("POST SENT");
return;
}
}
}
}
}
}
incomingChar = "";
return;
}
void sendText()
{
SIM7000.print("AT+HTTPINIT\r");
delay(1000);
getResponse();
SIM7000.print("AT+HTTPPARA=\"CID\",1\r");
delay(1000);
getResponse();
SIM7000.print("AT+HTTPPARA=\"URL\",\"http://engt62k9mgbgo.x.pipedream.net\"\r");
delay(1000);
getResponse();
SIM7000.print("AT+HTTPPARA=\"CONTENT\",\"text/plain\"\r");
delay(1000);
getResponse();
SIM7000.print("AT+HTTPDATA=100,5000\r\n");
delay(100);
getResponse();
SIM7000.print("\"TEST MESSAGE\"\r\n");
SIM7000.print("\r\n");
delay(5000);
getResponse();
SIM7000.print("AT+HTTPACTION=1\r");
delay(1000);
getResponse();
SIM7000.print("AT+HTTPTERM\r");
getResponse();
}
void getResponse()
{
if (SIM7000.available())
{
while (SIM7000.available())
{
data = SIM7000.read();
Serial.write(data);
}
data = 0;
}
}
//NOV 3 2020, note: need to include AT command AT+CMGD=0,4 for routinely deleting messages
//message storage limited and not automatically overwritten
I've included the output on the Serial monitor below.
Output on Serial Monitor
I'm thinking that the problem lies between
SIM7000.print("AT+HTTPDATA=100,5000\r\n");
and
SIM7000.print("AT+HTTPACTION=1\r");
You can see on the output where it prompts for DOWNLOAD, but the "TEST MESSAGE" that I try to insert here doesn't go. I've also attached a screenshot of the RequestBin output to show that it's showing up as an empty POST with nothing but headers and a content length of 0. Output in RequestBin
When I've done similar POST requests using the same SIM7000A module with the same AT commands on PuTTY via USB, all I have to do is enter my text during the time specified in the AT+HTTPDATA command and hit enter. Whatever I enter during that time as it says "DOWNLOAD" shows up as the body of my POST. But I have as of yet been unable to do the same using the Uno.
Any help you can offer is much appreciated.

First of all, you must to send CR NL char after all AT commands...
SIM7000.print("AT+HTTPDATA=100,5000\r\n");
Note: \r and \n = CR and NL respectively.
Second, try the steps below:
// SEND HTTP PROCESS
SIM7000.println("AT+HTTPINIT\r\n");
delay(1500);
Serial.println(SIM7000.readString());
SIM7000.println("AT+HTTPPARA=\"CID\",1\r\n");
delay(1500);
Serial.println(SIM7000.readString());
char httpSend[105] = "[URL]";
SIM7000.println(httpSend + String("\r\n"));
delay(1500);
Serial.println(SIM7000.readString());
SIM7000.println("AT+HTTPSSL=1\r\n"); // THIS LINE FOR SSL URL
delay(1500);
Serial.println(SIM7000.readString());
SIM7000.println("AT+HTTPACTION=0\r\n"); //GET REQUEST = 0 | POST REQUEST = 1
delay(7000);
Serial.println(SIM7000.readString());
SIM7000.println("AT+HTTPREAD\r\n");
delay(1500);
Serial.println(SIM7000.readString());
SIM7000.println("AT+HTTPTERM\r\n");
delay(1500);
Serial.println(SIM7000.readString());

Try adding ctrl-z Character (decimal 26) to the end of the data buffer you are sending after seeing DOWNLOAD.

Related

How to use RTCM data to achieve RTK?

I'm using this example from the Sparkfun Arduino Library
/*
Use ESP32 WiFi to get RTCM data from RTK2Go (caster) as a Client
By: SparkFun Electronics / Nathan Seidle
Date: November 18th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to obtain RTCM data from a NTRIP Caster over WiFi
and push it over I2C to a ZED-F9x.
It's confusing, but the Arduino is acting as a 'client' to a 'caster'. In this case we will
use RTK2Go.com as our caster because it is free. See the NTRIPServer example to see how
to push RTCM data to the caster.
You will need to have a valid mountpoint available. To see available mountpoints go here: http://rtk2go.com:2101/
This is a proof of concept to show how to connect to a caster via HTTP. Using WiFi for a rover
is generally a bad idea because of limited WiFi range in the field.
For more information about NTRIP Clients and the differences between Rev1 and Rev2 of the protocol
please see: https://www.use-snip.com/kb/knowledge-base/ntrip-rev1-versus-rev2-formats/
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
RTK Surveyor: https://www.sparkfun.com/products/18443
RTK Express: https://www.sparkfun.com/products/18442
Hardware Connections:
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Open the serial monitor at 115200 baud to see the output
*/
#include <WiFi.h>
#include "secrets.h"
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//The ESP32 core has a built in base64 library but not every platform does
//We'll use an external lib if necessary.
#if defined(ARDUINO_ARCH_ESP32)
#include "base64.h" //Built-in ESP32 library
#else
#include <Base64.h> //nfriendly library from https://github.com/adamvr/arduino-base64, will work with any platform
#endif
//Global variables
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReceivedRTCM_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
Serial.println(F("NTRIP testing"));
Wire.begin(); //Start I2C
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //Be sure RTCM3 input is enabled. UBX + RTCM3 is not a valid state.
myGNSS.setNavigationFrequency(1); //Set output in Hz.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.print(F("WiFi connected with IP: "));
Serial.println(WiFi.localIP());
while (Serial.available()) Serial.read();
}
void loop()
{
if (Serial.available())
{
beginClient();
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
}
Serial.println(F("Press any key to start NTRIP Client."));
delay(1000);
}
//Connect to NTRIP Caster, receive RTCM, and push to ZED module over I2C
void beginClient()
{
WiFiClient ntripClient;
long rtcmCount = 0;
Serial.println(F("Subscribing to Caster. Press key to stop"));
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush
while (Serial.available() == 0)
{
//Connect if we are not already. Limit to 5s between attempts.
if (ntripClient.connected() == false)
{
Serial.print(F("Opening socket to "));
Serial.println(casterHost);
if (ntripClient.connect(casterHost, casterPort) == false) //Attempt connection
{
Serial.println(F("Connection to caster failed"));
return;
}
else
{
Serial.print(F("Connected to "));
Serial.print(casterHost);
Serial.print(F(": "));
Serial.println(casterPort);
Serial.print(F("Requesting NTRIP Data from mount point "));
Serial.println(mountPoint);
const int SERVER_BUFFER_SIZE = 512;
char serverRequest[SERVER_BUFFER_SIZE];
snprintf(serverRequest, SERVER_BUFFER_SIZE, "GET /%s HTTP/1.0\r\nUser-Agent: NTRIP SparkFun u-blox Client v1.0\r\n",
mountPoint);
char credentials[512];
if (strlen(casterUser) == 0)
{
strncpy(credentials, "Accept: */*\r\nConnection: close\r\n", sizeof(credentials));
}
else
{
//Pass base64 encoded user:pw
char userCredentials[sizeof(casterUser) + sizeof(casterUserPW) + 1]; //The ':' takes up a spot
snprintf(userCredentials, sizeof(userCredentials), "%s:%s", casterUser, casterUserPW);
Serial.print(F("Sending credentials: "));
Serial.println(userCredentials);
#if defined(ARDUINO_ARCH_ESP32)
//Encode with ESP32 built-in library
base64 b;
String strEncodedCredentials = b.encode(userCredentials);
char encodedCredentials[strEncodedCredentials.length() + 1];
strEncodedCredentials.toCharArray(encodedCredentials, sizeof(encodedCredentials)); //Convert String to char array
snprintf(credentials, sizeof(credentials), "Authorization: Basic %s\r\n", encodedCredentials);
#else
//Encode with nfriendly library
int encodedLen = base64_enc_len(strlen(userCredentials));
char encodedCredentials[encodedLen]; //Create array large enough to house encoded data
base64_encode(encodedCredentials, userCredentials, strlen(userCredentials)); //Note: Input array is consumed
#endif
}
strncat(serverRequest, credentials, SERVER_BUFFER_SIZE);
strncat(serverRequest, "\r\n", SERVER_BUFFER_SIZE);
Serial.print(F("serverRequest size: "));
Serial.print(strlen(serverRequest));
Serial.print(F(" of "));
Serial.print(sizeof(serverRequest));
Serial.println(F(" bytes available"));
Serial.println(F("Sending server request:"));
Serial.println(serverRequest);
ntripClient.write(serverRequest, strlen(serverRequest));
//Wait for response
unsigned long timeout = millis();
while (ntripClient.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return;
}
delay(10);
}
//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (ntripClient.available())
{
if (responseSpot == sizeof(response) - 1) break;
response[responseSpot++] = ntripClient.read();
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
connectionSuccess = true;
if (strstr(response, "401") > 0) //Look for '401 Unauthorized'
{
Serial.println(F("Hey - your credentials look bad! Check you caster username and password."));
connectionSuccess = false;
}
}
response[responseSpot] = '\0';
Serial.print(F("Caster responded with: "));
Serial.println(response);
if (connectionSuccess == false)
{
Serial.print(F("Failed to connect to "));
Serial.print(casterHost);
Serial.print(F(": "));
Serial.println(response);
return;
}
else
{
Serial.print(F("Connected to "));
Serial.println(casterHost);
lastReceivedRTCM_ms = millis(); //Reset timeout
}
} //End attempt to connect
} //End connected == false
if (ntripClient.connected() == true)
{
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
rtcmCount = 0;
//Print any available RTCM data
while (ntripClient.available())
{
//Serial.write(ntripClient.read()); //Pipe to serial port is fine but beware, it's a lot of binary data
rtcmData[rtcmCount++] = ntripClient.read();
if (rtcmCount == sizeof(rtcmData)) break;
}
if (rtcmCount > 0)
{
lastReceivedRTCM_ms = millis();
//Push RTCM to GNSS module over I2C
myGNSS.pushRawData(rtcmData, rtcmCount, false);
Serial.print(F("RTCM pushed to ZED: "));
Serial.println(rtcmCount);
}
}
//Close socket if we don't have new data for 10s
if (millis() - lastReceivedRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println(F("RTCM timeout. Disconnecting..."));
if (ntripClient.connected() == true)
ntripClient.stop();
return;
}
delay(10);
}
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
ntripClient.stop();
}
on an ESP32 Thing Plus C with a ZED-F9P and it's working fine, but it only outputs RTCM data. How do I apply the RTCM data to the GPS data and achieve RTK? My goal is to have the ESP32 Thing Plus C output RTK Latitude and Longitude to the serial monitor.
Example output:
RTCM pushed to ZED: 163
RTCM pushed to ZED: 311
RTCM pushed to ZED: 1694
RTCM pushed to ZED: 1332
Any ideas would be appeciated! Thanks
Answered by PaulZC on Sparkfun Forum
Hi Jacob,
It sounds like everything is working OK. But, correct, there is
nothing in that example to actually print out the position.
Please try Example17. It is better-structured and uses callbacks to:
display your position; and push NMEA GGA data to the server. Some
NTRIP servers require the GGA data, others don't. If the GGA data
causes problems, you can comment this line to disable the push:
https://github.com/sparkfun/SparkFun_u- ... ck.ino#L81
Have fun! Paul

ESP32 Bluetooth connection status

I am running into some problems finding a solution when it comes to performing some form of Bluetooth connection check for my project that will allow me to have a connection status light.
My project consists of creating a Bluetooth speaker that has Led Strips controlled over Bluetooth serial (an app will be made to handle this) and audio stream over Bluetooth from a single ESP32.
I have found plenty of examples and had success with performing an spp callback event, however, of course this only works if I connect to the Bluetooth serial side of things through my 'Serial Bluetooth Terminal' app on my phone. If I just go into my phone Bluetooth list and connect to the audio side of things, nothing is registered, which isn't very useful for a Bluetooth speaker!
Basically I really need some help finding a way of registering that a device has connected to the Bluetooth audio so that I can have some form of indication light to tell the user that they are successfully connected to the speaker to play music.
Below is my code:
#include <btAudio.h> //<-------this is the library that I am using to handle Bluetooth audio to an external I2s DAC
#include "BluetoothSerial.h"
#include <FastLED.h>
TaskHandle_t Task1;
//POWER/BT-LIGHT-SETUP----------------------------------------
int powerPinR = 4;
int powerPinG = 16;
int powerPinB = 17;
bool BTisConnected;
//FAST-LED-STUFF----------------------------------------------
CRGB leds[NUM_STRIPS][NUM_LEDS];
CRGB leds_temp[NUM_STRIPS][NUM_LEDS/2];
//BLUETOOTH-SETUP---------------------------------------------
btAudio audio = btAudio("");
BluetoothSerial SerialBT;
//CONNECTION-CHECK--------------------------------------------
void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t*param){
if(event == ESP_SPP_SRV_OPEN_EVT){
Serial.println("Client Connected");
BTisConnected = true;
}
else {
BTisConnected = false;
}
}
//------------------------------------------------------------
void setup() {
//CORE-1-INITIALISE
xTaskCreatePinnedToCore(
codeForTask1, /* Task function. */
"Task_1", /* name of task. */
1000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* Core */
//POWER/BLUETOOTH-CONNECTION-LIGHT-SETUP
pinMode(powerPinR, OUTPUT);
pinMode(powerPinG, OUTPUT);
pinMode(powerPinB, OUTPUT);
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, HIGH);
digitalWrite (powerPinB, HIGH);
//COOLDOWN-DELAY
delay(3000);
//AUDIO-INITIALISE
audio.begin();
int bck = 26;
int ws = 27;
int dout = 25;
audio.I2S(bck, dout, ws);
//LED-STRIP-SETUP-&-CLEAR-ALL
FastLED.addLeds<WS2812B,STRIP1PIN,GRB>(leds[0], NUM_LEDS);
FastLED.addLeds<WS2812B,STRIP2PIN,GRB>(leds[1], NUM_LEDS);
FastLED.clear();
FastLED.show();
//SERIAL-INITIALISE-&-CLIENT-CONNECTION-CHECK
Serial.begin(115200);
SerialBT.begin("Pilot"); //<-----BLUETOOTH NAME
SerialBT.register_callback(callback); //<-- SerialBT connection check works perfectly, but nothing for audio connection! :(
}
//CORE-0-VOID-LOOP--------------------------------------------
void codeForTask1( void * parameter )
{
for (;;) {
manageData();
delay(10);
}
}
//CORE-1-VOID-LOOP--------------------------------------------
void loop() {
BTconnectionCheck();
playScene();
}
//MANAGE-INCOMING-BLUETOOTH-SERIAL-DATA-----------------------------------------------
void manageData() {
//READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT **
char rawData[100] = "";
char keyword[] = "Mydata=";
if (SerialBT.available() > 0) {//new data in
size_t byteCount = SerialBT.readBytesUntil('\n', rawData, sizeof(rawData) - 1); //read in data to buffer
rawData[byteCount] = NULL;//put an end character on the data
const char delimiter[] = ",";
char parsedStrings[5][8]; //first number = how many bits of data - 2nd number = max size of eeach data
int dataCount = 0;
int dataPosition = 0;
char *token = strtok(&rawData[dataPosition], delimiter);//look for first piece of data after keyword until comma
if (token != NULL && strlen(token) < sizeof(parsedStrings[0])) {
strncpy(parsedStrings[0], token, sizeof(parsedStrings[0]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[0], NULL);
}
for (int i = 1; i < 5; i++) {
token = strtok(NULL, delimiter);
if (token != NULL && strlen(token) < sizeof(parsedStrings[i])) {
strncpy(parsedStrings[i], token, sizeof(parsedStrings[i]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[i], NULL);
}
}
if (dataCount == 5) {
scene = atoi (parsedStrings[0]);
hue = atoi(parsedStrings[1]);
saturation = atoi(parsedStrings[2]);
brightness = atoi(parsedStrings[3]);
eventInterval = atol (parsedStrings[4]);
}
}
}
//BLUETOOTH-CONNECTION-CHECK---------------------------------------------------------
void BTconnectionCheck(){
SerialBT.register_callback(callback);
if (BTisConnected == true){
bluetoothConnected();
}
else {
bluetoothSearch();
}
}
void bluetoothSearch(){
digitalWrite (powerPinR, LOW);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
void bluetoothConnected(){
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
I have cut lots of the code to do with the LEDs out but its still quite long, If it would help to have a more condensed version then I will chop it down further. Or if it helps to have the full code then I can also post it.
Any help would be greatly appreciated as I am well and truly stuck with this one and its a pretty important part of the project.
Thanks in advance!

Google cloud MQTT with Esp32 Reusing JWT error

I am trying to send fake temperature data from an ESP32 to Google Cloud with Arduino IDE and using this library https://github.com/GoogleCloudPlatform/google-cloud-iot-arduino. I created a registry and a device on google iot core. On my side I manually put the csa certificate on the ESP32 and correctly set all parameters and private key string in 'ciotc_config.h'. When I try to connect I get in the Serial Monitor the following output repeting itself:
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8
Setup.....
Starting wifi
Connecting to WiFi
Connected
Waiting on time sync...
Esp32-mqtt:
void setupWifi() {
Serial.println("Starting wifi");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
}
Serial.println("Connected");
configTime(0, 0, ntp_primary, ntp_secondary);
Serial.println("Waiting on time sync...");
while (time(nullptr) < 1510644967) {
delay(10);
}
}
void connectWifi() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
}
I made a change in the main.cpp just because I will not be working with those sensors:
unsigned long lastMillis = 0;
void loop() {
mqtt->loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqttClient->connected()) {
connect();
}
if (millis() - lastMillis > 60000) {
Serial.println("Publishing value");
lastMillis = millis();
float temp = 33;
float hum = 50;
StaticJsonDocument<100> doc;
doc["temp"] = temp;
doc["humidity"] = hum;
serializeJson(doc, buffer);
//publishTelemetry(mqttClient, "/sensors", getDefaultSensor());
publishTelemetry( buffer);
}
}
Image from PUB:
I guess it is just a debug information. It could be in the line where you write the JWT tag information.
I wrote a tutorial about how to connect the ESP32 to Google Cloud IoT with full source code that is very similar to your code but It didn't repeat that info. You can give a look https://www.survivingwithandroid.com/cloud-iot-core-esp32/ and you can reuse the code. Let me know if I can help you somehow.
It doesn't look like you're ever successfully connecting.
In your output, I see connecting... so it's in the mqttConnect() call, but it never outputs connected! so it's stuck in the while loop where it's calling getJwt()
Now, why it's not outputting the mqtt errors may mean your errors are related to something else, and the mqtt client is totally fine, which is why you aren't seeing any other output. As a debugging check, I'd put a Serial.println("fubar") in the mqttConnect() call above the delay(1000) and see if you get other output there, pointing at some other connection error other than an mqtt connection problem.

Google iot MQTT - ESP32 Connects the first time and only reconnects after 30m

I'm working with google Iot cloud with ESP32, I am sending fake values just to make a test with the MQTT data PUB/SUB, Apparently I'm succeeding in publishing the values, sometimes, I can't reconnect to google iot.
I don't know why it keeps checking wifi...publising and doest check for the JWT key.
I have noticed that if I connect once to the google iot and then I unplug the esp32 from my pc (disconnect no power), and plug it back again and try to connect, I will enter in this "checking wifi" for about 30m, until I can connect back to google iot. How can fix this? I beleived there was something to deal with this:
// Time (seconds) to expire token += 20 minutes for drift
const int jwt_exp_secs = 3600; // Maximum 24H (3600*24)
When I manage to get a good response that send info to the servers, i get this+:
entry 0x400806b8
Setup.....
Starting wifi
Connecting to WiFi
Connected
Waiting on time sync...
checking wifi...
connecting...Refreshing JWT
connected
Library connected!
incoming: /devices/esp32-device/config -
incoming: /devices/esp32-device/config -
Publishing value
Publishing value
Publishing value
Publishing value
Publishing value
There is times that I get a bad response for about 30m, using the same code, it seems to be sending constant data, which shouldn't be constant.(wasn't suppose to happen):
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8
Setup.....
Starting wifi
Connecting to WiFi
Connected
Waiting on time sync...
checking wifi...Publishing value
checking wifi...checking wifi...checking wifi...Publishing value
(Just keeps repeating)
This is the main connection to MQTT code, with the attempts to fix problems, but didn't work:
// This file contains static methods for API requests using Wifi / MQTT
#ifndef __ESP32_MQTT_H__
#define __ESP32_MQTT_H__
#include <Client.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <MQTT.h>
#include <CloudIoTCore.h>
#include <CloudIoTCoreMqtt.h>
#include "ciotc_config.h" // Update this file with your configuration
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
// Initialize WiFi and MQTT for this board
Client *netClient;
CloudIoTCoreDevice *device;
CloudIoTCoreMqtt *mqtt;
MQTTClient *mqttClient;
unsigned long iat = 0;
String jwt;
String getDefaultSensor() {
return "Wifi: " + String(WiFi.RSSI()) + "db";
}
String getJwt() {
Serial.println("Entered JWT");
delay(5000);
iat = time(nullptr);
Serial.println("Refreshing JWT");
jwt = device->createJWT(iat, jwt_exp_secs);
return jwt;
}
void setupWifi() {
Serial.println("Starting wifi");
Serial.print("WIFI status = ");
Serial.println(WiFi.getMode());
WiFi.disconnect(true);
delay(3000);
WiFi.mode(WIFI_STA);
delay(3000);
Serial.print("WIFI status = ");
Serial.println(WiFi.getMode());
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
}
Serial.println("Connected");
delay(5000);
configTime(0, 0, ntp_primary, ntp_secondary);
Serial.println("Waiting on time sync...");
while (time(nullptr) < 1510644967) {
delay(10);
}
}
void connectWifi() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
}
delay(5000);
}
bool publishTelemetry(String data) {
return mqtt->publishTelemetry(data);
}
bool publishTelemetry(const char* data, int length) {
return mqtt->publishTelemetry(data, length);
}
bool publishTelemetry(String subfolder, String data) {
return mqtt->publishTelemetry(subfolder, data);
}
bool publishTelemetry(String subfolder, const char* data, int length) {
return mqtt->publishTelemetry(subfolder, data, length);
}
void connect() {
connectWifi();
mqtt->mqttConnect();
delay(5000);
}
void setupCloudIoT() {
device = new CloudIoTCoreDevice(
project_id, location, registry_id, device_id,
private_key_str);
setupWifi();
netClient = new WiFiClientSecure();
mqttClient = new MQTTClient(512);
mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
mqtt->setUseLts(true);
mqtt->startMQTT();
delay(5000);
}
#endif //__ESP32_MQTT_H__
This is the main.cpp:
#include <Arduino.h>
#include <WiFiClientSecure.h>
#include "esp32-mqtt.h"
#include <ArduinoJson.h>
#define led 14
char buffer[100];
float counter = 0;
float counter1 = 0;
void setup() {
Serial.begin(115200);
Serial.println("Setup.....");
pinMode(led, OUTPUT);
setupCloudIoT();
}
unsigned long lastMillis = 0;
void loop() {
mqtt->loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqttClient->connected()) {
connect();
}
counter++;
counter1++;
if (millis() - lastMillis > 1000) {
Serial.println("Publishing value");
lastMillis = millis();
float temp = counter;
float hum = counter1;
StaticJsonDocument<100> doc;
doc["temp"] = temp;
doc["humidity"] = hum;
serializeJson(doc, buffer);
publishTelemetry(buffer);
}
}
Does someone know if there is any other module that doesn't have this same issue?
The issue you face is IMHO not a problem of your code or the MQTT-lib you use. There seems to be a problem in the ESP32 core package (1.04 has it still). See this collection of issues from github and some proposed work around, which in the end delay the problem but do not solve it.
Issue with MQTT collection of problems from 2018 till today
These are open issues regarding WiFi re/connection problems
A test case for provoking an error is linked from one of the post.I use for identifying ESP32 specific problems the identical programm on an esp8266 with MQTT connection and there it runs for months.The ESP32 people have the bad habit to leave issues uncommented open for month hopeing the stale bot closes them. So I just cited the open issues, if you search for closed issues you'll find some more) closed by stale bot and not by solution!

Recieved String to useable variable in Arduino

I'm trying to use data sent via Bluetooth from a mobile app to the Arduino. There will be 2 strings received dependent on the function required.
First function: When the string "ledon" or "ledoff" received turn on or turn off an led.
Second Function: from the app I get the data a user has typed into 2 boxes, one a text box the other a password box, this is received by the Arduino as one string with comma's as a delimiter so the string can be separated into it's component parts, which in this case are an "ssid name" and a "network key". These details I will be intending to write to an onboard sd card so that the wifi module will be able to logon to the network that the ssid and network key are relevant too.
So far I can get the led light to do as it should, I can also get the string read, separated by the delimiter and printed out to the serial monitor. However when I try to combine the two codes the led function fails to turn on or off the led light although the correct command is printed into the serial monitor. I have researched how to solve this trying each requirement as a standalone function and calling them in the loop section, which individually they work but when called together again the led fails to come on.
This is the code i'm presently using:
const int ledPin = 11;
String readString;
void setup() {
Serial.begin(9600);
pinMode (ledPin, OUTPUT);
}
void loop() {
while (Serial.available()) {
delay(3);
char c = Serial.read();
readString += c;
}
//turns led on or off
if (readString.length() >0) {
Serial.println(readString);
if (readString == "ledon")
{
digitalWrite (ledPin, HIGH);
}
if (readString == "ledoff")
{
digitalWrite (ledPin, LOW);
}
readString="";
//seperates the string into 2 lines using the delimiter ","
String first = Serial.readStringUntil(',');
Serial.read(); //next character is comma, so skip it using this
String second = Serial.readStringUntil(',');
Serial.read();
Serial.println(first);
Serial.println(second);
readString="";
}
}
If I comment out the string part of the code the led turns on and off fine, if I try and run the code as is the code prints everything you would expect but the led doesn't come on.
I'm pretty new to Arduino,c and c++ and I cannot seem to figure this out so any help would be great.
The app I'm using to control this is being built in Mit's App Inventor 2
I have finally resolved this.
I decided to look at other logical steps to find a solution.
I considered the issue could be having different strings that did different things which may be conflicting in some way.
In my research I found reference to the fact that the Bluetooth module HC-05 has 2 pins that in my case were not being utilised, the key pin and the state pin, in this stack overflow discussion Tell when Bluetooth module connects on Arduino and decided this logic of using the "State pin" to signify Bluetooth connection would negate the possibility of any conflicts within the String logic.
Once I had figured out the best way to place and order the "where" statements I managed to get the functionality at this point in my project which then allows me to move on to the next step in the development.
The code I have now arrived at:
const int ledPin1 = 11;
const int ledPin2 = 4;
String readString;
boolean BTconnected = false;
void setup() {
Serial.begin(9600);
pinMode (ledPin1, OUTPUT);
pinMode (ledPin2, INPUT);
}
void loop() {
while (!BTconnected)
{
if ( digitalRead(ledPin2)==HIGH) { BTconnected = true;};
}
digitalWrite(ledPin1, HIGH);
Serial.println("HC-05 is now connected");
Serial.println("");
while (BTconnected)
{
if ( digitalRead(ledPin2)==LOW) { BTconnected = false;
digitalWrite(ledPin1, LOW);
Serial.println("HC-05 is now disconnected");
Serial.println("");
};
while (Serial.available())
{
delay(3);
char c = Serial.read();
readString += c;
}
if (readString.length() >0) {
//Serial.println(readString);
//readString="";
String first = Serial.readStringUntil(',');
Serial.read(); //next character is comma, so skip it using this
Serial.println(first);
//readString="";
String second = Serial.readStringUntil(',');
Serial.read();
Serial.println(second);
Serial.println("");
//readString="";
}
}
}