Code Monkey home page Code Monkey logo

esp_sslclient's Introduction

ESP SSLClient

Compile Examples Github Stars Github Issues

arduino-library-badge PlatformIO

The upgradable SSL Client for ESP8266, ESP32, Raspberry Pi Pico (RP2040) and other Arduino devices (except for avr) that supports external networking interfaces e.g., WiFiClient, EthernetClient, and GSMClient.

This library provided the Secure Layer Networking (SSL/TLS) TCP Client.

The Arduino Client library buffer size should be large enough (1k or more) for transporting SSL data.

The RP2040 boards required Arduino-Pico SDK from Earle F. Philhower https://github.com/earlephilhower/arduino-pico

This library used light weight SSL engine library BearSSL for secure data encryption and decryption.

In ESP8266 device, the native BearSSL in Core SDK will be used and built-in BearSSL library will be used for other Arduino devices.

This library is fully compatible and able to work with ESP-Mail-Client library seamlessly.

Supposted Arduino Devices with flash size > 128k.

  • ESP32
  • ESP8266
  • Arduino SAMD
  • Arduino STM32
  • Teensy 3.1 to 4.1
  • Arduino Nano RP2040 Connect
  • Raspberry Pi Pico
  • Arduino UNO R4 WiFi (Renesas).

Supposted Networking Devices with Client (with driver) library.

  • WIZnet Wxxx series modules
  • All SPI Ethernet modules
  • All GSM modules
  • All WiFi modules

Some PHY and MAC ethernet chips are already supported by Core WiFiClientSecure and ethernet libraries which this ESP_SSLClient library is not needed.

The following PHY ethernet chips i.e. LAN8720, TLK101, RTL8201, DP83848, DM9051, KSZ8041 and KSZ8081 were supported by ESP32 Arduino Core natively then this and can be used with WiFiClientSecure.h and ETH.h libraries as normally.

The SPI Ethernet module that uses WIZNet W5100, W5500 and ENC28J60 are supported by ESP8266 Arduino Core natively and can be used with WiFiClientSecure.h and ENC28J60lwIP.h or W5100lwIP.h or W5500lwIP.h libraries as normally.

Features

  • Uses BearSSL SSL engine for all devices (since v2.0.0).

  • Supports all Arduino devices with enough program flash space (128k or more).

  • First and only one SSL Client library that supports SSL/TLS connection upgrades.

  • Support STARTTLS in Email application.

  • Use Client pointer without copy to constructor then it can be changed seemlessly at run time.

  • The receive and transmit buffer memory can be reserved as supported by BearSSL.

  • Easy to use as it provides the same interface functions as in ESP8266's WiFiClientSecure.

  • Supports the authentications as in WiFiClientSecure.

Basic Usage

  #include <Arduino.h>
  #if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
  #include <WiFi.h>
  #elif defined(ESP8266)
  #include <ESP8266WiFi.h>
  #elif __has_include(<WiFiNINA.h>)
  #include <WiFiNINA.h>
  #elif __has_include(<WiFi101.h>)
  #include <WiFi101.h>
  #elif __has_include(<WiFiS3.h>)
  #include <WiFiS3.h>
  #endif
  
  #include <ESP_SSLClient.h>

  ESP_SSLClient ssl_client;
  EthernetClient basic_client;
  
  // ignore server ssl certificate verification
  ssl_client.setInsecure();

  /** Call setDebugLevel(level) to set the debug
  * esp_ssl_debug_none = 0
  * esp_ssl_debug_error = 1
  * esp_ssl_debug_warn = 2
  * esp_ssl_debug_info = 3
  * esp_ssl_debug_dump = 4
  */
  ssl_client.setDebugLevel(1);

  // Set the receive and transmit buffers size in bytes for memory allocation (512 to 16384).
  // For server that does not support SSL fragment size negotiation, leave this setting the default value
  // by not set any buffer size or set the rx buffer size to maximum SSL record size (16384) and 512 for tx buffer size.  
  ssl_client.setBufferSizes(1024 /* rx */, 512 /* tx */);
  
  // Assign the basic client
  // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existed 
  // as long as it was used by ssl_client for transportation.
  ssl_client.setClient(&basic_client);

  Serial.print("Connecting to server...");

  String payload = "{\"title\":\"hello\"}";

  if (ssl_client.connect("reqres.in", 443))
  {
    Serial.println(" ok");
    Serial.println("Send POST request...");
    ssl_client.print("POST /api/users HTTP/1.1\n");
    ssl_client.print("Host: reqres.in\n");
    ssl_client.print("Content-Type: application/json\n");
    ssl_client.print("Content-Length: ");
    ssl_client.print(payload.length());
    ssl_client.print("\n\n");
    ssl_client.print(payload);

    Serial.print("Read response...");

    unsigned long ms = millis();
    while (!ssl_client.available() && millis() - ms < 3000)
    {
      delay(0);
    }
    
    Serial.println();
    while (ssl_client.available())
    {
      Serial.print((char)ssl_client.read());
    }
    Serial.println();
  }
  else
    Serial.println(" failed\n");

  ssl_client.stop();

RP2040 Arduino SDK installation

For Arduino IDE, the Arduino-Pico SDK can be installed from Boards Manager by searching pico and choose Raspberry Pi Pico/RP2040 to install.

For PlatformIO, the Arduino-Pico SDK can be installed via platformio.ini

[env:rpipicow]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = rpipicow
framework = arduino
board_build.core = earlephilhower
monitor_speed = 115200

See this Arduino-Pico SDK documentation for more information.

Functions Interfaces

The ESP_SSLClient available functions are similare to the WiFiClientSecure.h class in ESP8266.

The Sessions and ServerSessions for ESP8266 BearSSL will be renamed to BearSSL_Sessions and BearSSL_ServerSessions respectively.

For all functions available in this library, see src/client/BSSL_TCP_Client.h

Additional Functions

The following are the additional functions over ESP8266 WiFiClientSecure.

Set the client.

param client The pointer to Client interface.

param enableSSL The ssl option; true for enable, false for disable.

Due to the client pointer is assigned, to avoid dangling pointer, client should be existed as long as it was used for transportation.

void setClient(Client *client, bool enableSSL = true);

Set debug level.

param level The debug level or esp_ssl_client_debug_level.

esp_ssl_debug_none = 0

esp_ssl_debug_error = 1

esp_ssl_debug_warn = 2

esp_ssl_debug_info = 3

esp_ssl_debug_dump = 4

void setDebugLevel(int level);

Validate the last Client connection with these host and port.

param host The server host name.

param port The server port to connect.

The Client connection will be closed when the provided host or port is not match with that of last connection.

void validate(const char *host, uint16_t port);

Validate the last Client connection with these IP and port.

param ip The server IP to connect.

param port The server port to connect.

The Client connection will be closed when the provided IP or port is not match with that of last connection.

void validate(IPAddress ip, uint16_t port);

Enable/disable the SSL layer transport.

param enable The enable option; true for enable, false to disable.

void enableSSL(bool enable);

Upgrade the current connection by setting up the SSL and perform the SSL handshake.

return operating result.

bool connectSSL();

Set the TCP connection timeout in seconds.

param seconds The TCP connection timeout in seconds.

int setTimeout(uint32_t seconds);

Get the TCP connection timeout in seconds.

return The TCP connection timeout in seconds.

int getTimeout();

Set the SSL handshake timeout in seconds.

param handshake_timeout The SSL handshake timeout in seconds.

void setHandshakeTimeout(unsigned long handshake_timeout);

Set the TCP session timeout in seconds.

param seconds The TCP session timeout in seconds.

The minimum session timeout value is 60 seconds.

Set 0 to disable session timed out.

If There is no data to send (write) within this period, the current connection will be closed and reconnect.

This requires when ESP32 WiFiClient was used.

int setSessionTimeout(uint32_t seconds);

MIT License

Copyright (c) 2024 mobizt

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

esp_sslclient's People

Contributors

mobizt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

esp_sslclient's Issues

JWT error (Off-Topic)

Hello author, this problem occurs when reconnecting after a few days

Token error: code: -1, message: Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values ​​in the JWT claim.

Will this problem occur if the gmtOffset setting of Firebase.setUDPClient does not match the current zone?
Or is there any part that needs special attention?

Allow custom Port

Hi thanks for the example earlier, I finally saw the culprint to my problem its mIsSecurePort allows only predefined secure ports in my case Im using a custom port like 5353 or 5443, I added my custom port on the ESP_SSLClient_Const.h _secure_ports and finally it worked!!. Maybe you can provide a flag or method to turn off the checking?, THank you.

TelegramUniversalBot & TimeClient

hi i dont get it... i want to use TelegramUniversalBot. For that I probably need SSL, so I included your library.

First, now i cant get a valid time from NTP servers. Before there was no problem.

with the telegram bot I get the following error from your lib:
11:02:21.792 -> > ERROR.mRunUntil: SSL internals timed out!
11:02:21.856 -> > ERROR.mConnectSSL: Failed to initlalize the SSL layer.
11:02:21.921 -> > ERROR.mConnectSSL: Unknown error code.
######################################################
11:03:04.366 -> > ERROR.mUpdateEngine: Error writing to basic client.
11:03:04.430 -> > ERROR.mConnectSSL: Failed to initlalize the SSL layer.
11:03:04.494 -> > ERROR.mConnectSSL: Unknown error code.

my Ethernet works and I get an IP with DHCP
i included telegram root certificate
i use sslClient.setX509Time(timeClient->getEpochTime()); but it is not working (see above)

my minimalized code

#include <UniversalTelegramBot.h>
#include <EthernetENC.h>
#include <EthernetUdp.h>
#include <ESP_SSLClient.h>
ESP_SSLClient sslClient;
EthernetClient ethClient;
EthernetUDP ethUDP;
UniversalTelegramBot *bot;

const char rootCA[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" ...

void setup() {
  Ethernet.begin(macAddr);
  
  sslClient.setInsecure();
  sslClient.setBufferSizes(1024 /* rx */, 512 /* tx */);
  sslClient.setDebugLevel(1);
  sslClient.setSessionTimeout(150); 
  sslClient.setX509Time(timeClient->getEpochTime());
  sslClient.setCACert(rootCA);
  sslClient.setClient(&ethClient);
  
  bot = new UniversalTelegramBot(tele_token, sslClient);
}

void loop() {
  bot->sendMessage(tele_id, tele_message, "");
}

how can i get TimeClient work again? How can i get your lib to work :D

ESP_SSLClient with Ethernet Client connection delay

Hello!
I am trying to integrate the library with ESP32 + ethernet W5100 chip. I noticed that there is a connection delay of ~600ms everytime I connect to my HTTPS server with the function .connect(server,port). I need my firmware to be fast in transmitting data, so this delay is a problem for me. Is there a way to reduce this delay with session caching or connecting with a persistant connection?
Thank You.

mqtt/tls configuration error

Hi, I have a problem establishing an MQTT(PubSubClient) connection using TLS over the W5500 ethernet with ESP32-S3.
When I remove TLS, everything works, I have communication via MQTT.

First I connect one certificate (piece of the main code):

#include "Ethernet.h"
#include <w5500.h>
#include <ESP_SSLClient.h>
#include <PubSubClient.h>
...
Ethernet ethernet;
EthernetClient client;
ESP_SSLClient sslClient;
PubSubClient mqttClient(sslClient;)
...
const char clientCa2[] PROGMEM = R"(.........) // from provider side
...
void setup()
{
// W5500 ethernet initialisation mac configuration etc. default chip/library settings
...
  sslClient.setInsecure();
  sslClient.setCertificate(clientCa2); // from test broker site test.mosquitto.org
  sslClient.setBufferSizes(1024, 512);
  sslClient.setDebugLevel(4);
  sslClient.setClient(&client, true);

  mqttClient.setServer("test.mosquitto.org", 8883); // test broker
);

void loop()
{
    if (!mqttClient.connected()) {
      while (!mqttClient.connected()) {
        if (mqttClient.connect("123456")) {
          mqttClient.subscribe("status", 0);
          delay(1000);
          Serial.println("publich message");
          mqttClient.publish("status", "message ssl");
          delay(1000);
        } else {
          Serial.printf("connect failed status: %d", mqttClient.state());
        }
        delay(5000);
      }
    } else {
      Serial.println("connection failed";)
    }
);

logs:

INFO.mConnectBasicClient: Basic client connected!
INFO.mConnectSSL: Start connection.
INFO.mConnectSSL: Wait for SSL handshake.
INFO.mUpdateEngine: State RECVREC
INFO.mUpdateEngine: State RECVREC
INFO.mUpdateEngine: State Connection close
WARN.mRunUntil: Terminating because the ssl engine closed.
ERROR.mConnectSSL: Failed to initlalize the SSL layer.
ERROR.mConnectSSL: Incoming record or message has wrong type with regards to the current engine state.

If I switch to WIFI and use WiFiClientSecure and perform functions with the same names, everything works on the new encryption client.

Ultimately, I would like to connect to AWS and there it has 3 certificates (from the AWS website) I just add the certs. In addition, I have read that you have to set the correct clock:

#include <EthernetUdp.h>
#include <NTPClient.h>
EthernetUDP ethUdp;
NTPClient timeClient(ethUdp);
  timeClient.begin();
  timeClient.update();
  time_t t = timeClient.getEpochTime();
  Serial.println(t);
  sslClient.setX509Time(t);

and now I attach a new certificate:

  // sslClient.setInsecure();
  sslClient.setCACert(rootCA);
  sslClient.setCertificate(clientCa2);
  sslClient.setPrivateKey(clientKey);

Logs:

same as prev and new

WARN.mRunUntil: Terminating because the ssl engine closed.
ERROR.mConnectSSL: Failed to initlalize the SSL layer.
ERROR.mConnectSSL: Caller-provided parameter is incorrect.

I've tried many options, maybe I'm doing something wrong I'm not setting something or not in the right order.

Can you help

Does not keep connection open

Hi amazing work for this library, I've implemented a server sent event client on esp32 and esp8266 its working fine on WifiSecureClient but when I change it to this ESP_SSLClient Implementation it keeps on disconnecting after the connection failing to send the Connection: keep-alive required by servent sent events.

EthernetClient not connecting

Hi,

I am testing https.ino example with esp32+w5500. While the code itself works if I use wifi only, when I switch to EthernetClient, after ethernet is initialized successfully, when the connection is attempted, it goes right away to


Connecting to server...ERROR - Generic error
failed

I am using Ethernet2 library, and I have made some modifications such as max sockets=2, use large buffers, etc (as recommended for similar use cases). Have you seen such issues? I do see in the code that you have commented out EthernetClient base_client, so I am guessing you may have tested it? Much appreciate any suggestions.

PS, the ESP32+w5500 works well for normal code. So, I know the hardware is good.

Data loss

As a test I replaced:

WiFiClientSecure client;
client.setInsecure();

by

ESP_SSLClient client;
WifiClient net;
client.setInsecure();
client.setClient(&net);

I connect to a website which returns 7712 (= content-length) bytes with the original code.
The replaced code gives a read timeout after 6703 bytes, with the same content-length in the return header.
Do I do something wrong?

Regards, Hans

MQTT-TLS with Ethernet w5500

Hello, I have a somewhat similar problem. I have to connect to a broker (this one gave me a certificate) and when I want to connect with ethernet w5500

EthernetClient ethClient;
ESP_SSLClient ssl_client; 
PubSubClient client(ssl_client);


void setup() {
  Serial.begin(115200);

M5.begin();
 M5.Power.begin();
 SPI.begin(SCK, MISO, MOSI, -1);
 Ethernet.init(CS);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); // do nothing, no point running without Ethernet hardware
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
   ssl_client.setCACert(root_ca);
    ssl_client.setBufferSizes(1024 /* rx */, 512 /* tx */);
    ssl_client.setDebugLevel(1);
    ssl_client.setClient(&ethClient);
  client.setServer(mqtt_server, 8883); // Puerto 8883 para conexión segura

}

and the logs was:

Failed to connect to MQTT broker, rc=-2
ERROR.mConnectSSL: Failed to initlalize the SSL layer.
ERROR.mConnectSSL: Certificate is expired or not yet valid.

can you help me pls?

MQTT-TLS with Ethernet w5500

Hi it's me again. Finally i can connect me to the broker mqtt successfully, but in another proyect https://github.com/mobizt/ESP_SSLClient/issues/9#issue-2388394631 .

In my main proyect, i try to use the same but i had some problems:

void setup() {
  WiFi.mode(WIFI_STA);  // explicitly set mode, esp defaults to STA+AP

  Serial.begin(115200);

  disableCore0WDT();
  disableCore1WDT();
  M5.begin();        
  M5.Power.begin();
    
  uint64_t chipId1 = 0;
  chipId1 = ESP.getEfuseMac();

  char chipIdString[18];
  snprintf(chipIdString, sizeof(chipIdString), "%04X%08X", (uint16_t)(chipId1 >> 32), (uint32_t)chipId1);
  Serial.print(chipIdString);
  
  if (!SD.begin()) {
        M5.Lcd.println("Card failed, or not present");
        while (1);
    }
    M5.Lcd.println("TF card initialized.");

    while (!module.begin(&Wire, 21, 22, MODULE_4IN8OUT_ADDR)) {
        Serial.println("4IN8OUT INIT ERROR");
        M5.Lcd.println("4IN8OUT INIT ERROR");
    }
    
  SPI.begin(SCK, MISO, MOSI, -1);
  Ethernet.init(CS);

  Ethernet.begin(mac);
  Serial.print("Ethernet iniciado. Dirección IP: ");
  Serial.println(Ethernet.localIP());
  timeClient.begin();
  timeClient.update(); 

   time_t currentTime = timeClient.getEpochTime();

    ssl_client.setX509Time(currentTime);

    ssl_client.setCACert(rootCA);

    ssl_client.setBufferSizes(1024 , 1024 );


    ssl_client.setDebugLevel(1);

    ssl_client.setClient(&basic_client);
  Reinicio.attach(2,reinicio);

  xTaskCreatePinnedToCore(
    mqttTask,   
    "mqttTask",  
    8192,         
    NULL,
    1,  
    NULL,
    0   
  );
  xTaskCreatePinnedToCore(
    countTask,    
    "countTask",  
    8192,         
    NULL,
    1,  
    NULL,
    1   
  );


  client.setServer(mqtt_server, mqtt_port);  
  client.setCallback(callback);

 
  M5.Lcd.fillScreen(ILI9341_BLACK);
  M5.Lcd.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);  
  M5.Lcd.fillRect(0, 0, 320, 30, ILI9341_NAVY);
  M5.Lcd.setTextColor(ILI9341_WHITE);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(15, 6);  
  M5.Lcd.print("Registro produccion V2.5");
  M5.Lcd.setCursor(10, 40); 
  M5.Lcd.print("Maquina:");
  M5.Lcd.setCursor(10, 70); 
  M5.Lcd.print("Contador:");
  M5.Lcd.setCursor(10, 180); 
  M5.Lcd.print("Operario:");
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(10, 210); 
  M5.Lcd.print("IP:");
  M5.Lcd.setCursor(10, 150);
  M5.Lcd.print("Conexion:");
  M5.Lcd.setCursor(180, 70);
  M5.Lcd.print("Scrap:");
  M5.Lcd.setCursor(45, 210);
  M5.Lcd.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  M5.Lcd.print(Ethernet.localIP());
  valor.store(readFile(SD, "/inputInt.txt").toInt());

}

and the log was:

ERROR.write: Failed while waiting for the engine to enter BR_SSL_SENDAPP.
ERROR.available: Cannot operate on a closed SSL connection.

Pd: In the main proyect i use 2 task, 1 for mqtt and another for an oled screen

Issue connecting to AWS IOT (Arduino UNO R4 WiFi)

Hey, I am having trouble using this library as well as a few others to connect to AWS IOT. These are the relevant parts of the code:

#include <WiFiS3.h>
#include "WiFiSSLClient.h"
#include <ArduinoJson.h>
#include <NTPClient.h>
#include "certs.h"
#include <MQTTClient.h>
#include <ESP_SSLClient.h>

// AWS
#define DEVICE_NAME "Arduino_1"
#define AWS_IOT_ENDPOINT "censored-ats.iot.eu-north-1.amazonaws.com"
#define AWS_IOT_TOPIC_1 "arduino/logs"
#define AWS_IOT_TOPIC_2 "arduino/thermostats"
#define AWS_MAX_RECONNECT_TRIES 10

// WiFi credentials
const char ssid[] = "censored";
const char pass[] = "censored";

WiFiClient wifi;
ESP_SSLClient net;
MQTTClient client1(net);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 1000);  // Sync every second

void setup() {
  Serial.begin(9600);

  // Connect to Wi-Fi
  Serial.print("Connecting to Wi-Fi...");
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to Wi-Fi");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Initialize NTPClient
  timeClient.begin();
  timeClient.update();

  connectToAWS();
}

void connectToAWS() {
  timeClient.update();

  // Get the current epoch time in UTC
  unsigned long utcTime = timeClient.getEpochTime();
  
  // Print the UTC time in Unix format
  Serial.print("Current UTC time in Unix format: ");
  Serial.println(utcTime);
  
  net.setX509Time(utcTime);
  
  // Configure WiFiClientSecure to use the AWS certificates we generated
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);
  
  net.setBufferSizes(1024 /* rx */, 512 /* tx */);

  net.setDebugLevel(4);
  net.setClient(&wifi);

  // Connect to the MQTT broker on the AWS endpoint we defined earlier
  client1.begin(AWS_IOT_ENDPOINT, 8883, net);

  // Try to connect to AWS
  Serial.println("Connecting to AWS IOT...");

  client1.connect(DEVICE_NAME);
}

This is the serial output for the connection attempt:

16:54:06.681 -> Current UTC time in Unix format: 1722873246
16:54:06.915 -> Connecting to AWS IOT...
16:54:07.384 -> > INFO.mConnectBasicClient: Basic client connected!
16:54:07.384 -> > INFO.mConnectSSL: Start connection.
16:54:07.384 -> > WARN.mConnectSSL: Connection will fail, no authentication method is setup.
16:54:07.571 -> > INFO.mConnectSSL: Wait for SSL handshake.
16:54:07.571 -> > INFO.mUpdateEngine: State RECVREC
16:54:07.618 -> > INFO.mUpdateEngine: State RECVREC
16:54:07.757 -> > INFO.mRunUntil: SSL state changed.
16:54:07.757 -> > INFO.mRunUntil: State RECVREC
16:54:07.757 -> > INFO.mRunUntil: Expected bytes count: 5
16:54:09.395 -> > INFO.mUpdateEngine: State RECVREC
16:54:15.010 -> > INFO.mUpdateEngine: State RECVREC
16:54:15.195 -> > INFO.mUpdateEngine: State SENDAPP
16:54:15.288 -> > INFO.mRunUntil: SSL state changed.
16:54:15.288 -> > INFO.mRunUntil: State SENDAPP
16:54:15.288 -> > INFO.mConnectSSL: Connection successful!

Is it really connecting? It says that the connection will fail but then it says it connected successfully. I tried using an insecure connection, in that case it just says that the connection was successful.

Later in my code I have a function to attempt sending data to the database, structured like this:

void sendDeviceData() {

  timeClient.update();

  // Get the current epoch time in UTC
  unsigned long utcTime = timeClient.getEpochTime();
  
  // Print the UTC time in Unix format
  Serial.print("Current UTC time in Unix format: ");
  Serial.println(utcTime);

  Serial.println("Sending device data to AWS...");

  // Create a JSON object to hold the temperature data
  DynamicJsonDocument tempDoc(512); // Adjust size as needed
  JsonObject historyEntry = tempDoc.createNestedObject(utcTime);
  historyEntry["tempA"] = tempA;
  historyEntry["tempF"] = tempF;
  historyEntry["tempR"] = tempR;
  historyEntry["tempD"] = tempD;

  // Serialize JSON object to string
  String tempData;
  serializeJson(tempDoc, tempData);

  // Publish temperature data to AWS IoT
  if (client1.publish(AWS_IOT_TOPIC_1, tempData)) {
    Serial.println("Temperature data published to AWS IoT");
  } else {
    Serial.println("Failed to publish temperature data");
  }

  // Create a JSON object to hold the message and alarm data
  DynamicJsonDocument messageDoc(256);  // Adjust size as needed
  messageDoc["message"] = message;
  messageDoc["alarm"] = alarm;

  // Serialize JSON object to string
  String messageData;
  serializeJson(messageDoc, messageData);

  // Publish message data to AWS IoT
  if (client1.publish(AWS_IOT_TOPIC_2, messageData)) {
    Serial.println("Message data published to AWS IoT");
  } else {
    Serial.println("Failed to publish message data");
  }
}

However, the message is never received by AWS IOT.

If someone could help me with this I'd really appreciate it. Other alternatives like using SSLClientSecure are not an option because of the board I'm using (most tutorials I found use that library).

Thanks in advance.

connectSSL hangs

Hi,

I am using the ESP_SSLClient library on a LilyGo TCALL v1.4 with a SIM800H module mounted inside.
The project I am working on measures a few parameters (air humidity, temperature and soil moisture), then sends them to a server through HTTPS. I can only rely on GSM, since the place where this board will be installed does not have access to WiFi.

Below is the code I have written:

#include "DHT.h"
#include <esp_task_wdt.h>


//////////////////////////////
// Sensor Variables Section //
//////////////////////////////

#define WDT_TIMEOUT   6*60  // Watchdog for three minutes
#define DHTTYPE       DHT11 // We're using DHT 11 for this project
#define DHTPIN        15    // Serial communication for DHT sensor goes through this pin
#define SOILSENS      34    // The analog signal from the soil mosture sensor is fed in this pin
#define MEASUREMENTS  5     // How many measurements should be computed in a measurement cycle

// Define the dht variable holding type and pin information
DHT dht(DHTPIN, DHTTYPE);

// Temperature and air humidity variables are defined here
float temperature[MEASUREMENTS];
float air_humidity[MEASUREMENTS];

// Soil moisture variables defined here
const int air_moisture = 3390;            // This is the minimum value we can get through the soil moisture sensor
const int water_moisture = 1490;          // This is the maximum value we can get through the soil moisture sensor
int soil_moisture_val;                    // This variable will then be scaled wrt the air and water moisture levels
int soil_moisture_percent[MEASUREMENTS];  // Final moisture value holding array


////////////////////////////////
// Internet Variables Section //
////////////////////////////////
// GPRS credentials (leave empty, if not needed)
const char apn[]      = "TM"; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org
const char gprsUser[] = "";   // GPRS User
const char gprsPass[] = "";   // GPRS Password

// SIM card PIN (leave empty, if not defined)
const char simPIN[]   = "1503"; 

// Server details
// The server variable can be just a domain name or it can have a subdomain. It depends on the service you are using
const char server[] = <my_server>;   // domain name: example.com, maker.ifttt.com, etc
const int  port = 443;                                                   // server port number

const char token [] = <my_token>;

// TTGO T-Call pins
#define MODEM_RST            5
#define MODEM_PWKEY          4
#define MODEM_POWER_ON       23
#define MODEM_TX             27
#define MODEM_RX             26
#define I2C_SDA              21
#define I2C_SCL              22

// Set serial for debug console (to Serial Monitor, default speed 115200)
#define SerialMon Serial
// Set serial for AT commands (to SIM800 module)
#define SerialAT Serial1

// Configure TinyGSM library
#define TINY_GSM_MODEM_SIM800      // Modem is SIM800
#define TINY_GSM_RX_BUFFER   1024  // Set RX buffer to 1Kb

#include <Wire.h>
#include <TinyGsmClient.h>
#include "ESP_SSLClient.h"

TinyGsm modem(SerialAT);

// I2C for SIM800 (to keep it running when powered from battery)
TwoWire I2CPower = TwoWire(0);

// TinyGSM and ESP_SSLClient for Internet connection
TinyGsmClient client(modem);
ESP_SSLClient ssl_client;

#define uS_TO_S_FACTOR  1000000UL   /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP   3520        /* Time ESP32 will go to sleep (in seconds) 3520 seconds = 58 minutes, 40 seconds */
#define MAX_RETRY       10          /* How many times a POST request should be attempted before giving up */

#define IP5306_ADDR          0x75
#define IP5306_REG_SYS_CTL0  0x00


////////////////////////////
// USER DEFINED FUNCTIONS //
////////////////////////////
// Function: setPowerBoostKeepOn
bool setPowerBoostKeepOn(int en){
  I2CPower.beginTransmission(IP5306_ADDR);
  I2CPower.write(IP5306_REG_SYS_CTL0);
  if (en) {
    I2CPower.write(0x37); // Set bit1: 1 enable 0 disable boost keep on
  } else {
    I2CPower.write(0x35); // 0x37 is default reg value
  }
  return I2CPower.endTransmission() == 0;
}

// Function: htmlGet
// Performs the get request
boolean htmlGet(const char* URI) {
  if (ssl_client.connect(server, port)) {

    Serial.print("[HTTPS] Upgrade to HTTPS...");
    if (!ssl_client.connectSSL()) {
      Serial.println(" failed");
      return false;
    }

    Serial.println(" ok");
    
    // HTML response is stored here
    String msg;
    
    Serial.println("[HTTPS] Send GET request...");
    ssl_client.print(String("GET ") + URI + " HTTP/1.1\r\n");
    ssl_client.print(String("Host: ") + server + "\r\n");
    ssl_client.print("Content-Type: application/json\r\n");
    ssl_client.print(String("Authorization: Bearer ") + token + "\r\n");
    ssl_client.print("Connection: close\r\n\r\n");


    unsigned long ms = millis();
    while (!ssl_client.available() && millis() - ms < 3000) {
        delay(0);
    }
    Serial.println();
    while (ssl_client.available()) {
        msg += (char)ssl_client.read();
    }

      if(msg.substring(9, 12) == "200" || msg.substring(9, 12) == "201") {
      ssl_client.stop();
      return true;
    }
    
  }
  else
    Serial.println("[HTTPS] Connection to server failed");

  ssl_client.stop();
  return false;

}

// Function: htmlPost
// Performs the post request
boolean htmlPost(const char* URI, const char* payload, int payload_length) {
  if (ssl_client.connect(server, port)) {

    Serial.print("[HTTPS] Upgrade to HTTPS...");
    if (!ssl_client.connectSSL()) {
      Serial.println(" failed");
      return false;
    }

    Serial.println(" ok");
    
    // HTML response is stored here
    String msg;
    
    // Start of transmission
    Serial.println("[HTTPS] Send POST request...");
    ssl_client.print(String("POST ") + URI + " HTTP/1.1\r\n");
    ssl_client.print(String("Host: ") + server + "\r\n");
    ssl_client.print("Content-Type: application/json\r\n");
    ssl_client.print(String("Authorization: Bearer ") + token + "\r\n");
    ssl_client.print("Content-Length: ");
    ssl_client.print(payload_length);
    ssl_client.print("\r\n\r\n");
    ssl_client.print(payload);

    // Check for correctness
    unsigned long ms = millis();
    while (!ssl_client.available() && millis() - ms < 10000L) {
      delay(10);
    }

    while (ssl_client.available()) {
      msg += (char)ssl_client.read();
    }

    if(msg.substring(9, 12) == "200" || msg.substring(9, 12) == "201") {
      ssl_client.stop();
      return true;
    }
    Serial.println(msg);  
  }
  else
    Serial.println("[HTTPS] Connection to server failed");

  ssl_client.stop();
  return false;

}


///////////////////
// Setup Section //
///////////////////
void setup() {
  // Set serial monitor debugging window baud rate to 115200
  Serial.begin(115200);
  Serial.println("[SETUP] Setting up peripherals...");

  // Add watchdog
  esp_task_wdt_init(WDT_TIMEOUT, true); // Enable panic so ESP32 restarts
  esp_task_wdt_add(NULL);               // Add current thread to WDT watch

  // Initialize humidity and temperature sensor
  dht.begin();

  // Setup code for modem
  // Start I2C communication
  I2CPower.begin(I2C_SDA, I2C_SCL, 400000);

  // Keep power when running from battery
  bool isOk = setPowerBoostKeepOn(1);
  SerialMon.println(String("[SETUP] IP5306 KeepOn ") + (isOk ? "OK" : "FAIL"));

  // Set modem reset, enable, power pins
  pinMode(MODEM_PWKEY, OUTPUT);
  pinMode(MODEM_RST, OUTPUT);
  pinMode(MODEM_POWER_ON, OUTPUT);
  digitalWrite(MODEM_PWKEY, LOW);
  digitalWrite(MODEM_RST, LOW);
  digitalWrite(MODEM_POWER_ON, HIGH);
  delay(1000);
  digitalWrite(MODEM_RST, HIGH);
  delay(1000);

  // Set GSM module baud rate and UART pins
  SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
  delay(3000);

  //secure_presentation_layer.setCACert(hass_root_ca);

  // Restart SIM800 module, it takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println("[TinyGSM] Initializing modem...");
  modem.restart();
  // use modem.init() if you don't need the complete restart

  String modemInfo = modem.getModemInfo();
  SerialMon.print("[TinyGSM] Modem Info: ");
  SerialMon.println(modemInfo);

  // Unlock your SIM card with a PIN if needed
  if (strlen(simPIN) && modem.getSimStatus() != 3 ) {
    modem.simUnlock(simPIN);
  }

  // Check network presence
  SerialMon.print("[TinyGSM] Waiting for network...");
  if (!modem.waitForNetwork()) {  
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isNetworkConnected()) { SerialMon.println("[TinyGSM] Network connected"); }

  // Connect to APN
  SerialMon.print(F("[TinyGSM] Connecting to "));
  SerialMon.print(apn);
  if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isGprsConnected()) { SerialMon.println("[TinyGSM] GPRS connected"); }


  // Ignore server ssl certificate verification
  ssl_client.setInsecure();
    
  // Set the receive and transmit buffers size in bytes for memory allocation (512 to 16384).
  ssl_client.setBufferSizes(4096 /* rx */, 512 /* tx */);

  /** Call setDebugLevel(level) to set the debug
   * esp_ssl_debug_none = 0
   * esp_ssl_debug_error = 1
   * esp_ssl_debug_warn = 2
   * esp_ssl_debug_info = 3
   * esp_ssl_debug_dump = 4
   */
  ssl_client.setDebugLevel(4);

  // Assign the basic client
  // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existent
  // as long as it was used by ssl_client for transportation.
  ssl_client.setClient(&client, false);

      
  // Configure the wake up source as timer wake up  
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  Serial.println("[SETUP] Weather station is ready to start!");

}


//////////////////
// LOOP SECTION //
//////////////////
void loop() {

  // The goal here is to compute several measurements and average them to get a measurement as accurate as possible.
  // For this reason, 30 measurements are taken before the data is sent to the server.
  for(int i = 0; i < MEASUREMENTS; i++) {

    SerialMon.print("[LOOP] Measurement number ");
    SerialMon.println(i);
    
    // Reading temperature or humidity takes about 250 milliseconds!
    air_humidity[i] = dht.readHumidity();
    // Read temperature as Celsius
    temperature[i] = dht.readTemperature();
  
    // Check if any reads failed and exit early (to try again).
    while (isnan(air_humidity[i]) || isnan(temperature[i])) {
      // Reading temperature or humidity takes about 250 milliseconds!
      air_humidity[i] = dht.readHumidity();
      // Read temperature as Celsius
      temperature[i] = dht.readTemperature();
    }

    // Compute soil moisture value
    soil_moisture_val = analogRead(SOILSENS);
    soil_moisture_percent[i] = map(soil_moisture_val, air_moisture, water_moisture, 0, 100);
  
    // Cut values exceeding bounds
    if(soil_moisture_percent[i] > 100)
      soil_moisture_percent[i] = 100;
    else if(soil_moisture_percent[i] < 0)
      soil_moisture_percent[i] = 0;

    // Sleep for 4 seconds (to account for measurement time)
    delay(4000);
  }

  // Compute the average of the previous measurements
  float air_humidity_avg = 0.0;
  float temperature_avg = 0.0;
  float soil_moisture_avg = 0.0;

  // First add...
  for(int i = 0; i < MEASUREMENTS; i++) {
    air_humidity_avg += air_humidity[i];
    temperature_avg += temperature[i];
    soil_moisture_avg += soil_moisture_percent[i];
  }

  // Then divide by number of measurements
  air_humidity_avg /= MEASUREMENTS;
  temperature_avg /= MEASUREMENTS;
  soil_moisture_avg /= MEASUREMENTS;

  // Print relevant info
  SerialMon.println("[LOOP] Measurement phase is complete. Following measurements will be transmitted:");
  SerialMon.print(F("[LOOP] Air humidity: "));
  SerialMon.print(air_humidity_avg);
  SerialMon.println(F(" %"));
  SerialMon.print(F("[LOOP] Temperature: "));
  SerialMon.print(temperature_avg);
  SerialMon.println(F(" °C"));
  SerialMon.print(F("[LOOP] Soil humidity: "));
  SerialMon.print(soil_moisture_avg);
  SerialMon.println(F(" %"));

  // Compute heat index in Celsius (isFahreheit = false)
  //float hic = dht.computeHeatIndex(temperature, air_humidity, false);
  //Serial.print(F("Heat index: "));
  //Serial.print(hic);
  //Serial.println(F("°C"));

  // Prepare the json file to send it
  char convert_meas[5];
  String json_data; //= "{\"state\": ";
  uint8_t retry = 0;

  // Air Humidity
  sprintf(convert_meas, "%.1f", air_humidity_avg);
  json_data = String("{\"state\": ") + convert_meas + ", \"attributes\": {\"unit_of_measurement\": \"%\"}}";

  while(!htmlPost("/api/states/sensor.weather_sensor_humidity_home", json_data.c_str(), json_data.length()) && (retry < MAX_RETRY)) {
    Serial.println("[LOOP] HTTPS post failed, retrying in 5 seconds");
    retry++;
    delay(5000);    
  }

  Serial.println("[LOOP] Humidity data successfully transmitted");
  delay(5000);

  // Temperature
  sprintf(convert_meas, "%.1f", temperature_avg);
  retry = 0;
  json_data = String("{\"state\": ") + convert_meas + ", \"attributes\": {\"unit_of_measurement\": \"°C\"}}"; 

  while(!htmlPost("/api/states/sensor.weather_sensor_temp_home", json_data.c_str(), json_data.length()) && (retry < MAX_RETRY)) {
    Serial.println("[LOOP] HTTPS post failed, retrying in 5 seconds");
    retry;
    delay(5000);
  }

  Serial.println("[LOOP] Temperature data successfully transmitted");
  delay(5000);

  // Soil moisture
  sprintf(convert_meas, "%.1f", soil_moisture_avg);
  retry = 0;
  json_data = String("{\"state\": ") + convert_meas + ", \"attributes\": {\"unit_of_measurement\": \"%\"}}";

  while(!htmlPost("/api/states/sensor.weather_sensor_soil_moisture_home", json_data.c_str(), json_data.length()) && (retry < MAX_RETRY)) {
    Serial.println("[LOOP] HTTPS post failed, retrying in 5 seconds");
    retry++;
    delay(5000);
  }

  Serial.println("[LOOP] Soil moisture data successfully transmitted");
  delay(5000);

  Serial.println("[LOOP] Device now is going to sleep...");
  
  // This will put the ESP32 to sleep
  esp_deep_sleep_start();

}

The issue I am encountering is that from time to time the connectSSL() function fails, and that can happen multiple times in a row thus stalling the whole transmission process.
Setting the debug option to 4, this is what I read when such failures occur:

INFO.mConnectBasicClient: Basic client connected!
INFO.mConnectSSL: Start connection.
INFO.mConnectSSL: Wait for SSL handshake.
INFO.mUpdateEngine: State RECVREC
INFO.mUpdateEngine: State RECVREC
INFO.mRunUntil: SSL state changed.
INFO.mRunUntil: State RECVREC
INFO.mRunUntil: Expected bytes count: 5
ERROR.mRunUntil: SSL internals timed out!
ERROR.mConnectSSL: Failed to initlalize the SSL layer.
ERROR.mConnectSSL: Unknown error code.

Is it something related to my code/settings? How can I fix this problem? Sometimes the board will be able to connect at the first try and everything goes smoothly, sometimes it takes few retries and other times is completely stuck. I am using the latest version of this library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.