How to use TinyGSM with Thinger

Hey all, first post in the forum here. Enjoying Thinger so far and have connected my test device via WiFi without issue and am excited to build this into our production codebase.

I am using PlatformIo in VSCode for an IDE and I have two issues at the moment, one is more practical and the other conceptual.

Practically: we are using an ESP32-S3-DevKit-C1 board with a SIMCOM7600G-H modem for GSM connectivity over HardwareSerial. Additionally, because this gsm module does not support SSL natively, I use SSLClient to setup our HTTP clients for handling network requests.

On top of that, we aim to use both WiFi and GSM, falling back to WiFi if our LTE connection is unavailable.

On to my questions, at the moment, I have included the necessary library files to connect to Thinger over GSM, but cannot compile. This is the error message:

In file included from src/main.cpp:8:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:136:5: error: 'TinyGsmClientSecure' does not name a type; did you mean 'TinyGsmClient'?
     TinyGsmClientSecure client_;
     ^~~~~~~~~~~~~~~~~~~
     TinyGsmClient
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h: In constructor 'ThingerTinyGSM::ThingerTinyGSM(const char*, const char*, const char*, Stream&)':
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:37:23: error: 'Client& ThingerClient::client_' is private within this context
         ThingerClient(client_, user, device, device_credential),
                       ^~~~~~~
In file included from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerWifi.h:27,
                 from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerESP32.h:32,
                 from src/main.cpp:2:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerClient.h:571:13: note: declared private here
     Client& client_;
             ^~~~~~~
In file included from src/main.cpp:8:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:39:9: error: 'Client& ThingerClient::client_' is private within this context
         client_(modem_)
         ^~~~~~~
In file included from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerWifi.h:27,
                 from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerESP32.h:32,
                 from src/main.cpp:2:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerClient.h:571:13: note: declared private here
     Client& client_;
             ^~~~~~~
In file included from src/main.cpp:8:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:39:9: error: class 'ThingerTinyGSM' does not have any field named 'client_'
         client_(modem_)
         ^~~~~~~
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h: In member function 'TinyGsmClient& ThingerTinyGSM::getTinyGsmClient()':
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:110:16: error: 'Client& ThingerClient::client_' is private within this context
         return client_;
                ^~~~~~~
In file included from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerWifi.h:27,
                 from .pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerESP32.h:32,
                 from src/main.cpp:2:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerClient.h:571:13: note: declared private here
     Client& client_;
             ^~~~~~~
In file included from src/main.cpp:8:
.pio/libdeps/esp32-s3-devkitc-1/thinger.io/src/ThingerTinyGSM.h:110:16: error: invalid initialization of reference of type 'TinyGsmClient&' {aka 'TinyGsmSim7600::GsmClientSim7600&'} from expression of type 'Client'
         return client_;

These are the relevant include directives from main.cpp

#define HAVE_HWSERIAL1
#include <ThingerESP32.h>

#define TINY_GSM_MODEM_SIM7600
#define TINY_GSM_RX_BUFFER 1024

#include <TinyGsmClient.h>
#include <ThingerTinyGSM.h>
#include <ThingerESP32OTA.h>

#include <Arduino.h>
#include <ArduinoJson.h>
#include <ArduinoHttpClient.h>
#include "SSLClient.h"

#ifdef NETWORK_MODE_LTE
  HardwareSerial gsmSerial(1);
  TinyGsm modem(gsmSerial);
  TinyGsmClient gsmClient(modem, 0);

  SSLClient secure_layer_lte(&gsmClient);
  HttpClient lte_ssl_client = HttpClient(secure_layer_lte, API_HOST, PORT);
  
  ThingerTinyGSM gsmthing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL, gsmSerial);
  ThingerESP32OTA ota(gsmthing);

  gsmSerial.begin(BAUD_RATE, SERIAL_8N1, LTE_RX, LTE_TX, false);
  secure_layer_lte.setCACert(api_root_ca);
  modem.init();
  modem.setNetworkMode(38);
  modem.waitForNetwork();
#endif

Iā€™m wondering because I know the SIM7600 module is not listed in the example sketch for GSM, perhaps this is not a supported module? I tried just to see switching to SIM900 but the same error.

More conceptually, what I would like to do is simply provide clients to Thinger so that I can handle setting up WiFi and GSM clients myself with SSL and not have the Thinger library itself managing the modem connection. Has anyone attempted this or know if it would be possible? What we are really going for is for our connection to Thinger to happen over GSM or WiFi depending on the state of our application (ie: LTE is connected? if not, try WiFi).

I read through the discussion at Connect to thinger.io via GPRS module (done) to get some context but so far no luck getting just GSM to work with Thinger, as per my errors above. I think if I could get the connection going, I could figure out a way with config variables to choose a routine based on the active connection type.

Thanks for reading and happy to clarify further or provide more samples. Here is our platform.ini file:

[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
lib_deps = 
	thinger.io
	bblanchon/ArduinoJson@7.0.3
	vshymanskyy/TinyGSM@0.11.7
	makuna/NeoPixelBus@2.7.8
	arduino-libraries/ArduinoHttpClient@0.6.0
	digitaldragon/SSLClient@1.1.8

Hi,

I would try downgrading thinger library to version 2.17.0 or 2.20.0 (I dont remember the last version compatible with the tiny gsm library) but for sure one of those will work.

Hope this helps

@ega thank you Iā€™ll give that a try!

seems odd that a newer version would break a supported integration? are you a long time thinger user, can I ask what your experience with updates has been? We are thinking of becoming a customer so trying to get some inside info!

Hi,

Yes it may look odd, but it may respond to the fact that the library have been updated to support, for example, new boards, so it could be some incompatibility between library versions and integations.

Regarding the updates, do you mean server version updates? they handle the updates very carefully, even if there are some bug that is messing around, they can apply a quick downgrade to the previous stable version if you are affected and report the situation, then they will apply the update to your specific private instance when the version is patched.

Hope this helps.

Hey @ega,

tried downgrading today. Only two other versions are available from PlatformIO, 2.26.0 (9 months old) and 2.25.2 (2 years old). If I modify platform.ini manually to any other version it cannot be found, downgrading to either of those versions didnā€™t change anything unfortunately.

However, I starting going through the github issues and found someone elseā€™s sketch with the comment that TLS must be disabled in order to compile on the ESP32. I set the disable tls flag and now the code compiles! Using my SIMCOM 7600G modem works with Thinger, so thatā€™s really good news, and I was able to run an OTA update, albeit after a few tries.

Iā€™m not clear why I have to disable TLS but perhaps this is something I can open an issue for on github and maybe it will be addressed. I notice there are a number of github issues open with no reply from maintainers, though.

Thanks so much chiming in and helping out I really appreciate it.

Hello, @reusables-official

Have you tried making these suggested changes?

If yes, did it solve your problem?

The Arduino-Library is a differentiator from Thinger. I donā€™t know of another platform that has a library with these resources in such an integrated way with the Iot Platform.
It was because of Arduino-Library that we chose to use the Thinger platform.
However, the update time and attention to some bugs could be more frequent.
We already suggested this fix a few months ago, but they havenā€™t analyzed it yet.

The possibility of using a device with WiFi and GSM would be very interesting. Example: Connect with WiFi. If WiFi goes offline, connect with GSM.
Did you manage to do this? If yes, how did you do it? Could you show your code?

Hey @George_Santiago, thanks for the note.

Yes, I saw the issues you opened on Github and was confused why you have had no response there, and I do find that to be of concern as well. That said, I agree without your assessment in terms of the features offered by Thinger and their ArduinoLibrary, and Iā€™ve spent a lot of time researching companies who claim to offer fleet management solutions for IoT. Only Golioth has stood out as being superior but they only support Espressif-idf which is too much of jump for us right now.

Yes, as of today I do have WiFi and GSM working together. Here are the relevant snippets, let me know if I can help you further:

#define HAVE_HWSERIAL1
#define _DISABLE_TLS_
#include <ThingerESP32.h>

#ifdef NETWORK_MODE_LTE
  #include "network/lte.h"
  ThingerTinyGSM gsmthing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL, gsmSerial);
  ThingerESP32OTA gsmota(gsmthing);
#endif
#ifdef NETWORK_MODE_WIFI
  #include "network/wpa.h"
  ThingerESP32 wifithing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);
  ThingerESP32OTA wifiota(wifithing);
#endif

setup() {
  #ifdef NETWORK_MODE_LTE
    lteInit();
    xTaskCreate(lteConnect, "Connect to LTE", 50000, NULL, 2, NULL);
    gsmota.set_enabled(true);
    gsmota.set_timeout(120000);
    gsmthing.setAPN(APN);
  #endif
  
  #ifdef NETWORK_MODE_WIFI
    xTaskCreate(wifiConnect, "Connect to WiFi network", 10000, NULL, 3, &wifiTaskHandler);
    wifithing.add_wifi(SSID, PASSWORD);
    wifiota.set_enabled(true);
    wifiota.set_timeout(120000);
  #endif
}

loop() {
// this part could be cleaner, but as a prototype it does work
  #ifdef NETWORK_MODE_LTE
    if (gsmthing.is_connected()) {
      #ifdef NETWORK_MODE_WIFI
        wifithing.stop();
      #endif
      gsmthing.handle();
    } else {
      gsmthing.stop();
      #ifdef NETWORK_MODE_WIFI
        wifithing.handle();
      #endif
    }
  #elif NETWORK_MODE_WIFI
    wifithing.handle();
  #endif
}
<lte.h>

#define TINY_GSM_MODEM_SIM7600
#define TINY_GSM_RX_BUFFER 1024

#include <TinyGsmClient.h>
#include <ThingerTinyGSM.h>
#include <ThingerESP32OTA.h>

HardwareSerial gsmSerial(1);
TinyGsm modem(gsmSerial);
TinyGsmClient gsmClient(modem, 0);

SSLClient secure_layer_lte(&gsmClient);
HttpClient lte_ssl_client = HttpClient(secure_layer_lte, API_HOST, PORT);

// lte_ssl_client is used for our api calls
// in theory we could go through Thinger instead of initializing our own http stack

void lteInit() {
  gsmSerial.begin(BAUD_RATE, SERIAL_8N1, LTE_RX, LTE_TX, false);
  secure_layer_lte.setCACert(api_root_ca);
  modem.init();
  modem.setNetworkMode(38);
  modem.waitForNetwork();
}

void lteConnect(void * parameter) {
  for (;;) {
    bool networkConnected = modem.waitForNetwork();
    bool gprsConnected = false;
    if (networkConnected) {
      gprsConnected = modem.isGprsConnected();
    }
    if (networkConnected && gprsConnected) {
      SRB_State.lte = true;
      setIndicator(NETWORK_STATUS, Blue);
      Serial.println("LTE Online");
      vTaskDelay(60000 / portTICK_PERIOD_MS);
    } else {
      SRB_State.lte = false;
      setIndicator(NETWORK_STATUS, Orange);
      bool networkConnected = modem.waitForNetwork();
      if (networkConnected) {
        Serial.println("LTE network connected");
        if (!modem.isGprsConnected()) {
          modem.gprsConnect(APN);
        }
      } else {
        Serial.println("LTE disconnected");
      }
    }
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

OK. I understand. You used compilation directives.
I imagined that you had managed to integrate the WiFi class with GSM, making them coexist.
Example:
The thing.handle() object would be connected to WiFi. If the router/modem went offline, thing.handle() would switch to GSM.
In your code example, from what I understand, there is no such functionality.

Another question.
I think I found bugs handling the thing.lock() and thing.unlock() methods. See this link:

Yes thatā€™s right, it would be nice to do it that way! Wouldnā€™t know where to start unfortunately, Iā€™m extremely new to c++.

Interesting! thanks for pointing me at that thread. It seems like the Thinger team (is it just Alvaro?!) is doing all the right things but perhaps under-resourced in terms of keeping on top of releases and support. Are you on a paid plan? We are about to pay for the maker plan but available support is just community so it probably wonā€™t give us any more insight.

Overall, the Thinger platform is very good. And the improvements have been continuous.
The curious thing is that complex and robust features are developed, but some bugs or simple features that impact the user experience end up taking a long time to be fixed or implemented.
But Thingerā€™s developers are very attentive and attentive to community messages.
I believe that Thinger will be an excellent choice for your projects.

1 Like

I believe it is the most promising platform among all the ones I researched.
Maybe a little focus on the features and bugs that compromise some user experiences, and, without a doubt, it will be the best IoT platform.

Some examples of features we are waiting for that will improve the platformā€™s user experience (which is already very good, but will get better):
(There are more complex implementations in our understanding, but these simple implementations would help a lot with the usersā€™ experience. We are looking forward to these implementations.)