I have an issue when trying to upload sensor data to ThingSpeak using the GSMSSLClient with the Arduino MKR GSM 1400 over MQTT. Each time I attempt to establish an MQTT connection, the state is always -2. Below is the relevant sections of my code to do this:
const char broker[] = "mqtt3.thingspeak.com";
const int port = 8883;
GSMSSLClient sslClient;
GPRS gprs;
GSM gsmAccess;
PubSubClient mqttClient(sslClient);
This was what I started with before initializing the MQTT connection. It failed and I thought of implementing the handling of certificates to attempt the connection again. I thus followed the steps in https://www.mathworks.com/matlabcentral/answers/1889632-how-to-download-root-certificate-for-use-with-industrial-communication-toolbox-mqtt-functions to download the root certificate, specifically the DigiCert Global Root G2 PEM certificate. I set it up this way:
const char* caCert = \
"-----BEGIN CERTIFICATE-----\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"-----END CERTIFICATE-----\n";
sslClient.setTrustedRoot(caCert);
This failed as well. From the SSLCertificateManagement_Example in the MKRGSM library, I saw the certificate was in DER format, so I then used followed the steps here to convert the .pem to .der. I then used the sed command on Linux to format it in the structure 0xab, Below is the command:
sed 's/../0x&, /g'
I then implemented this in the code in the arduino_secrets.h
file:
const uint8_t CA_CERT[] = {
0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xcd, 0xe1,
};
Then in the .ino file:
sslClient.setTrustedRoot((const char*)CA_CERT));
It still failed. I then attempted to use the openssl command to get the certificates. I used two variations:
openssl s_client -showcerts -connect mqtt3.thingspeak.com:443
openssl s_client -showcerts -connect api.thingspeak.com:443
which output certificates which were similar to each other, but not similar to what I had downloaded from the link I had shared initially with the steps. I attempted to use these certificates as well, both in .pem and .der format but the connection still failed with state -2.
PS: Using port 1883 and GSMClient works and the data is uploaded to ThingSpeak successfully.
Here is a relatively verbose version of my code:
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <MKRGSM.h>
#include "arduino_secrets.h"
#include <PubSubClient.h>
#define DHTPIN 6
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// GSM credentials
// PIN Number
const char PINNUMBER[] = SECRET_PIN;
// APN data
const char GPRS_APN[] = SECRET_GPRS_APN;
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASS;
// MQTT credentials
const char* mqttServer = "mqtt3.thingspeak.com";
const int mqttPort = 8883;
const char* mqttClientID = SECRET_MQTT_CLIENT_ID;
const char* mqttUser = SECRET_MQTT_USERNAME;
const char* mqttPass = SECRET_MQTT_PASSWORD;
String topicString = "channels/" + String(SECRET_CH_ID) + "/publish";
char topic[50];
// GSM classes
GSMClient client;
GPRS gprs;
GSM gsmAccess;
PubSubClient mqttClient(client);
const char* caCert = \
"-----BEGIN CERTIFICATE-----\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"-----END CERTIFICATE-----\n";
void setup() {
Serial.begin(115200);
Serial.println("Initializing DHT11...");
dht.begin();
Serial.println("Starting Arudino web client.");
boolean connected = false;
delay(10000);
while (!connected) {
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) && (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println("Not connected to cellular network. Retrying...");
delay(1000);
}
}
Serial.println("Connected to cellular network");
sslClient.setTrustedRoot(caCert);
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setKeepAlive(60);
// MQTT connection
if (mqttConnect()) {
Serial.println("Connected to MQTT broker");
} else {
Serial.println("Failed to connect to MQTT broker");
}
}
bool mqttConnect() {
Serial.println("Connecting to MQTT...");
if (mqttClient.connect(mqttClientID, mqttUser, mqttPass)) {
Serial.println("MQTT connected");
return true;
} else {
Serial.print("MQTT connection failed. State: ");
Serial.println(mqttClient.state());
return false;
}
}
void loop() {
if (!mqttClient.connected()) {
Serial.println("MQTT disconnected. Reconnecting...");
mqttConnect();
}
mqttClient.loop();
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
} else {
Serial.print("Humidity: "); Serial.print(humidity); Serial.println("%");
Serial.print("Temperature: "); Serial.print(temperature); Serial.println("°C");
}
String payload = "field1=" + String(temperature) + "&field2=" + String(humidity);
// Publish to MQTT topic
if (mqttClient.publish(topic, payload.c_str())) {
Serial.print("Publishing to: ");
Serial.println(topic);
Serial.print("Payload: ");
Serial.println(payload);
Serial.println("Data published to ThingSpeak MQTT.");
} else {
Serial.println("MQTT publish failed.");
}
delay(15000);
}
0x0a
? Or do you convert each character\` and
n` into a separate hex value? Sorry I not the time to read the whole question, so it might be answered already. Just to present you my idea. ;-)