Skip to content

Add automatic connection multiplexing #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 246 additions & 14 deletions docs/api.md

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions examples/MultipleConnections/MultipleConnections.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* This example shows how to use the connection management features of the ArduinoCellular library
* to maintain multiple HTTP and HTTPS clients.
* This is useful if e.g. you want to use ArduinoIoTCloud or other services that require
* a dedicated client while making custom HTTP requests to other servers.
*
* Instructions:
* 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module.
* 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply
* with a current rating of at least 2A and connect it to the VIN and GND pins.
* 3. Specify the APN, login, and password for your cellular network provider.
* 4. Upload the sketch to the connected Arduino board.
* 5. Open the serial monitor to view the output.
*
* Initial author: Sebastian Romero
*/

#include <Arduino.h>
#include "ArduinoCellular.h"
#include <ArduinoHttpClient.h>

#define SECRET_PINNUMBER ""
#define SECRET_GPRS_LOGIN ""
#define SECRET_GPRS_APN "gprs.swisscom.ch"
#define SECRET_GPRS_PASSWORD ""

constexpr int SSL_PORT = 443;

ArduinoCellular cellular = ArduinoCellular();

void getResource(HttpClient &client, const char *resource) {
Serial.println("Making GET request...");
client.get(resource);
int statusCode = client.responseStatusCode();

if (statusCode < 0) {
Serial.print("Error Response Code: ");
Serial.println(statusCode);
return;
}
Serial.print("Response: ");
Serial.println(client.responseBody());
}


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

cellular.begin();

if(String(SECRET_PINNUMBER).length() > 0 && !cellular.unlockSIM(SECRET_PINNUMBER)){
Serial.println("Failed to unlock SIM card.");
while(true); // Stop here
}

Serial.println("Connecting...");
if(!cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD)){
Serial.println("Failed to connect to the network.");
while(true); // Stop here
}
Serial.println("Connected!");

HttpClient client1 = cellular.getHTTPSClient("vsh.pp.ua", SSL_PORT);
HttpClient client2 = cellular.getHTTPSClient("wttr.in", SSL_PORT);
Serial.print("Managed client count: ");
Serial.println(cellular.getManagedClientCount());

getResource(client1, "/TinyGSM/logo.txt");
getResource(client2, "/?format=3");
client1.stop();
client2.stop();
cellular.cleanup(); // Clean up connections after use

Serial.print("Managed client count: ");
Serial.println(cellular.getManagedClientCount());
}

void loop(){}
99 changes: 62 additions & 37 deletions src/ArduinoCellular.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@


#include "ArduinoCellular.h"

#if defined(ARDUINO_ARCH_MBED)
#include "Watchdog.h"
#endif

unsigned long ArduinoCellular::getTime() {
int year, month, day, hour, minute, second;
float tz;
modem.getNetworkTime(&year, &month, &day, &hour, &minute, &second, &tz);
Modem.getNetworkTime(&year, &month, &day, &hour, &minute, &second, &tz);
return Time(year, month, day, hour, minute, second).getUNIXTimestamp();
}

ArduinoCellular::ArduinoCellular() {
}

ArduinoCellular::~ArduinoCellular() {
cleanup();
}

void ArduinoCellular::begin() {
modem.init();
Modem.init();

String modemInfo = this ->sendATCommand("I");
if(modemInfo.indexOf("EC200A") > 0){
Expand All @@ -28,15 +33,15 @@ void ArduinoCellular::begin() {
}

// Set GSM module to text mode
modem.sendAT("+CMGF=1");
modem.waitResponse();
Modem.sendAT("+CMGF=1");
Modem.waitResponse();

modem.sendAT(GF("+CSCS=\"GSM\""));
modem.waitResponse();
Modem.sendAT(GF("+CSCS=\"GSM\""));
Modem.waitResponse();

// Send intrerupt when SMS has been received
modem.sendAT("+CNMI=2,1,0,0,0");
modem.waitResponse();
Modem.sendAT("+CNMI=2,1,0,0,0");
Modem.waitResponse();

#if defined(ARDUINO_CELLULAR_BEARSSL)
ArduinoBearSSL.onGetTime(ArduinoCellular::getTime);
Expand Down Expand Up @@ -103,7 +108,7 @@ Geolocation ArduinoCellular::getGPSLocation(unsigned long timeout){
unsigned long startTime = millis();

while((latitude == 0.00000 || longitude == 0.00000) && (millis() - startTime < timeout)) {
modem.getGPS(&latitude, &longitude);
Modem.getGPS(&latitude, &longitude);
delay(1000);
}

Expand All @@ -122,7 +127,7 @@ Geolocation ArduinoCellular::getGPSLocation(unsigned long timeout){

Time ArduinoCellular::getGPSTime(){
int year, month, day, hour, minute, second;
modem.getGPSTime(&year, &month, &day, &hour, &minute, &second);
Modem.getGPSTime(&year, &month, &day, &hour, &minute, &second);
return Time(year, month, day, hour, minute, second);
}

Expand All @@ -134,22 +139,22 @@ Time ArduinoCellular::getCellularTime(){
int minute = 0;
int second = 0;
float tz;
if (modem.NTPServerSync() == 0) {
modem.getNetworkTime(&year, &month, &day, &hour, &minute, &second, &tz);
if (Modem.NTPServerSync() == 0) {
Modem.getNetworkTime(&year, &month, &day, &hour, &minute, &second, &tz);
}
return Time(year, month, day, hour, minute, second);
}


void ArduinoCellular::sendSMS(String number, String message){
modem.sendAT("+CMGF=1");
modem.waitResponse(1000);
modem.sendAT(GF("+CMGS=\""), number, GF("\""));
if (modem.waitResponse(GF(">")) != 1) { }
modem.stream->print(message); // Actually send the message
modem.stream->write(static_cast<char>(0x1A)); // Terminate the message
modem.stream->flush();
auto response = modem.waitResponse(10000L);
Modem.sendAT("+CMGF=1");
Modem.waitResponse(1000);
Modem.sendAT(GF("+CMGS=\""), number, GF("\""));
if (Modem.waitResponse(GF(">")) != 1) { }
Modem.stream->print(message); // Actually send the message
Modem.stream->write(static_cast<char>(0x1A)); // Terminate the message
Modem.stream->flush();
auto response = Modem.waitResponse(10000L);

if(this->debugStream != nullptr){
this->debugStream->println("Response: " + String(response));
Expand All @@ -158,40 +163,60 @@ void ArduinoCellular::sendSMS(String number, String message){


IPAddress ArduinoCellular::getIPAddress(){
return modem.localIP();
return Modem.localIP();
}

int ArduinoCellular::getSignalQuality(){
return modem.getSignalQuality();
return Modem.getSignalQuality();
}

TinyGsmClient ArduinoCellular::getNetworkClient(){
return TinyGsmClient(modem);
return ManagedTinyGsmClient(Modem);
}

HttpClient ArduinoCellular::getHTTPClient(const char * server, const int port){
return HttpClient(* new TinyGsmClient(modem), server, port);
return HttpClient(* new ManagedTinyGsmClient(Modem), server, port);
}

#if defined(ARDUINO_CELLULAR_BEARSSL)
HttpClient ArduinoCellular::getHTTPSClient(const char * server, const int port){
return HttpClient(* new BearSSLClient(* new TinyGsmClient(modem)), server, port);
auto gsmClient = std::make_unique<ManagedTinyGsmClient>(Modem);
auto sslClient = std::make_unique<BearSSLClient>(*gsmClient);
auto& sslRef = *sslClient;

managedGsmClients.push_back(std::move(gsmClient));
managedSslClients.push_back(std::move(sslClient));
return HttpClient(sslRef, server, port);
}

BearSSLClient ArduinoCellular::getSecureNetworkClient(){
return BearSSLClient(* new TinyGsmClient(modem));
return BearSSLClient(* new ManagedTinyGsmClient(Modem));
}
#endif

void ArduinoCellular::cleanup() {
/*
It's necessary to to manage the lifetime of the clients created by the library
because the HttpClient and also BearSSLClient classes expect callers to manage the lifetime of the clients.
For convenience, the library provides factory functions that allocate these objects on behalf of the caller.
*/
managedSslClients.clear(); // Destroys BearSSLClient instances
managedGsmClients.clear(); // Destroys ManagedTinyGsmClient instances
}

size_t ArduinoCellular::getManagedClientCount() const {
return managedSslClients.size();
}

bool ArduinoCellular::isConnectedToOperator(){
return modem.isNetworkConnected();
return Modem.isNetworkConnected();
}

bool ArduinoCellular::connectToGPRS(const char * apn, const char * gprsUser, const char * gprsPass){
if(this->debugStream != nullptr){
this->debugStream->println("Connecting to 4G network...");
}
while(!modem.gprsConnect(apn, gprsUser, gprsPass)) {
while(!Modem.gprsConnect(apn, gprsUser, gprsPass)) {
if(this->debugStream != nullptr){
this->debugStream->print(".");
}
Expand All @@ -201,11 +226,11 @@ bool ArduinoCellular::connectToGPRS(const char * apn, const char * gprsUser, con
}

bool ArduinoCellular::isConnectedToInternet(){
return modem.isGprsConnected();
return Modem.isGprsConnected();
}

SimStatus ArduinoCellular::getSimStatus(){
int simStatus = modem.getSimStatus();
int simStatus = Modem.getSimStatus();
if(this->debugStream != nullptr){
this->debugStream->println("SIM Status: " + String(simStatus));
}
Expand All @@ -224,12 +249,12 @@ SimStatus ArduinoCellular::getSimStatus(){
}

bool ArduinoCellular::unlockSIM(String pin){
int simStatus = modem.getSimStatus();
int simStatus = Modem.getSimStatus();
if(simStatus == SIM_LOCKED) {
if(this->debugStream != nullptr){
this->debugStream->println("Unlocking SIM...");
}
return modem.simUnlock(pin.c_str());
return Modem.simUnlock(pin.c_str());
}
else if(simStatus == SIM_ERROR || simStatus == SIM_ANTITHEFT_LOCKED) {
return false;
Expand All @@ -242,7 +267,7 @@ bool ArduinoCellular::awaitNetworkRegistration(bool waitForever){
if(this->debugStream != nullptr){
this->debugStream->println("Waiting for network registration...");
}
while (!modem.waitForNetwork(waitForNetworkTimeout)) {
while (!Modem.waitForNetwork(waitForNetworkTimeout)) {

if(!waitForever) {
return false;
Expand Down Expand Up @@ -283,13 +308,13 @@ bool ArduinoCellular::enableGPS(bool assisted){
return false;
}

return modem.enableGPS();
return Modem.enableGPS();
}

String ArduinoCellular::sendATCommand(const char * command, unsigned long timeout){
String response;
modem.sendAT(command);
modem.waitResponse(timeout, response);
Modem.sendAT(command);
Modem.waitResponse(timeout, response);
return response;
}

Expand Down Expand Up @@ -401,7 +426,7 @@ std::vector<SMS> parseSMSData(const String& data) {
}

String ArduinoCellular::sendUSSDCommand(const char * command){
return modem.sendUSSD(command);
return Modem.sendUSSD(command);
}

std::vector<SMS> ArduinoCellular::getReadSMS(){
Expand Down
Loading