HTTP API request using SIM800L and Blynk

I am developing a weather station with an ESP32 and Blynk and everything is working fine. Now I am trying to use a SIM800L for remote areas and after some problems like having to put a step up to power it with 4 volts and some issues learning how to use it, it is working with Blynk. However I also need to get an API request using HTTP to get the local timezone to handle the correct local time in my GPS and although it is working fine on Wifi, I cannot put it to work on SIM800L despite numerous attempts and reading the docs.
Here is the relevant code, I have two functions to parse the API one for WiFi getTimeZoneOffset() and the other for SIM800L which I am using right now getTimeZoneOffsetSim800l()

Here is the console output

response=

ERROR

+CIPRXGET: 1,0

OK

OK

OK

Error on HTTP request

Also just out of curiosity I would like to know if it is possible to use Blynk.AIR and Edgent with SIM800L, or is it a bad idea?

#define BLYNK_TEMPLATE_ID "XXXXXXXXXXX"
#define BLYNK_TEMPLATE_NAME "YYYYYYYYYY"
#define BLYNK_AUTH_TOKEN "ZZZZZZZZZ"

// Select your modem:
#define TINY_GSM_MODEM_SIM800

#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>
#include "DHT.h"
#include <numeric>
#include <HTTPClient.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_MLX90614.h>
#include "riodejaneiro_openweather.h"
#include "SPIFFS.h"
#include <deque>
#include <TinyGPSPlus.h>
#include <ArduinoJson.h>
#include <SoftwareSerial.h>


// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
#define SerialAT Serial1
#define RXD1 9 
#define TXD1 10

// Your GPRS credentials, if any
const char apn[]  = "claro.com.br";
const char user[] = "claro";
const char pass[] = "claro";

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
const char auth[] = "XXXXXXXXXXXXXXXXXXXX";


// Global state variables
struct GPSState {
  double longitude, latitude;
  int currentHour, currentMonth;
  String season;
  String gps_time;
} gpsstate;


// Global strings
struct GlobalStrings {
  String message;
  String apiKey = "XXXXXXXXX";
} globalStrings;

int timerId1;

// Create sensor instances
Adafruit_BMP280 bmp; // For the BMP280 sensor
DHT dht(DHTPIN, DHTTYPE); // For the DHT sensor
Adafruit_MLX90614 mlx = Adafruit_MLX90614(); // For the MLX90614 sensor
TinyGPSPlus gps; // For the GPS module
BlynkTimer timer; // For Blynk timer
TinyGsm modem(SerialAT);



void setup()
{
  // Set console baud rate
  SerialMon.begin(115200);
  delay(10);

  // Set GSM module baud rate
  SerialAT.begin(115200);
  delay(6000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println("Initializing modem...");
  modem.restart();

  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem Info: ");
  SerialMon.println(modemInfo);
  // Check if modemInfo is empty or null
  if (modemInfo == NULL || modemInfo.length() == 0) {
    SerialMon.println("No modem info, restarting modem...");

    // Power off the modem
    modem.poweroff();
    delay(10000); // Wait for some time (10 seconds)

    // Try getting the modem information again
    modemInfo = modem.getModemInfo();
    SerialMon.print("Modem Info after restart: ");
    SerialMon.println(modemInfo);
  }
  // Unlock your SIM card with a PIN
  //modem.simUnlock("1234");

  Blynk.begin(auth, modem, apn, user, pass);

  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  timerId1 = timer.setInterval(10 * 1000L, takeMeasurements);

  // Initialize sensors and buffers
  initializeSensors();
  
  // Update the dataset interval to 3 hours (180 minutes)
  settings.updateDatasetInterval(180);

  // Initialize maxEntries based on the smallest interval
  // Use the timeData instance to access intervals
  timeData.maxEntries = 3600000 / timeData.intervals[0]; // Max entries for 1 hour based on the smallest interval
  
  // Load previous measurements into the buffers
  loadMeasurementsAndInitializeBuffers();
}

void loop()
{
  Blynk.run();
  timer.run();
}


// Function to get the timezone offset in seconds
long getTimeZoneOffset() {
  HTTPClient http;
  // Use the latitude and longitude from the 'state' struct
  String apiEndpoint = "http://api.timezonedb.com/v2.1/get-time-zone?key=" + globalStrings.apiKey +
                       "&format=json&by=position&lat=" + String(gpsstate.latitude) +
                       "&lng=" + String(gpsstate.longitude);

  http.begin(apiEndpoint);
  int httpCode = http.GET();

  if (httpCode == 200) { // If the call to the API was successful
    String payload = http.getString();
    DynamicJsonDocument doc(1024);
    deserializeJson(doc, payload);

    if (doc["status"] == "OK") {
      long gmtOffset = doc["gmtOffset"]; // Get the GMT offset in seconds
      http.end();
      return gmtOffset;
    } else {
      Serial.println("API returned an error: " + String(doc["message"].as<const char*>()));
      http.end();
      return 0;
    }
  } else {
    Serial.println("Error on HTTP request");
    http.end();
    return 0;
  }
}

long getTimeZoneOffsetSim800l() {
  // Initialize HTTP service
  SerialAT.println("AT+HTTPINIT");
  delay(1000);

  // Set HTTP parameters
  String apiEndpoint = "http://api.timezonedb.com/v2.1/get-time-zone?key=" + globalStrings.apiKey +
                      "&format=json&by=position&lat=" + String(gpsstate.latitude, 2) +
                      "&lng=" + String(gpsstate.longitude, 2) + "&fields=gmtOffset";
  SerialAT.println("AT+HTTPPARA=\"URL\",\"" + apiEndpoint + "\"\r\n");

  delay(1000);

  // Start HTTP GET session
  SerialAT.println("AT+HTTPACTION=0");

  // Read the response
  SerialAT.println("AT+HTTPREAD");
  delay(1000);

  String response = "";
  while (SerialAT.available()) {
    response += char(SerialAT.read());
  }
  Serial.println("response=");
  Serial.println(response);
  // Parse response if HTTP request was successful
  if (response.indexOf("+HTTPACTION: 0,200") != -1) {
    int jsonStart = response.indexOf('{');
    int jsonEnd = response.lastIndexOf('}');

    if (jsonStart != -1 && jsonEnd != -1) {
      String jsonResponse = response.substring(jsonStart, jsonEnd + 1);
      DynamicJsonDocument doc(1024);
      deserializeJson(doc, jsonResponse);

      if (doc["status"] == "OK") {
        long gmtOffset = doc["gmtOffset"]; // Get the GMT offset in seconds
        return gmtOffset;
      } else {
        Serial.println("API returned an error: " + String(doc["message"].as<const char*>()));
        return 0;
      }
    }
  } else {
    Serial.println("Error on HTTP request");
    return 0;
  }

  // Terminate HTTP service
  SerialAT.println("AT+HTTPTERM");
  delay(1000);
}

Why don’t you get the TZ offset from Blynk?
In the Blynk app/console you can define the TZ and retrieve that from the Blynk server.

Pete.

Hi Pete,

Sounds like a good idea, will try that.

Best regards,

Alvaro Antelo