Arduino MKRGSM 1400 crashes when connecting to MQTT - arduino

I have a question concerning the Arduino MKRGSM 1400 and MQTT.
I use the code below to connect my MKRGSM to the internet via a SIM-card, then connect it to a HiveMQ-broker I have installed on Docker. Even though the code is compiled without any errors, once I upload it to my board, it crashes. Once it has crashed, I have to reset my board entirely. I've tried this code with the Arduino IDE and Platform.io on VS Code, both give the same result.
Before I put in the MQTT-connection, the board connected successfully to the internet and the DHT11-sensor was able to read humidity and temperature values without problems.
I'm not great with Arduino and this is the first time I'm trying to use MQTT myself.
Does anyone know why the code not only doesn't work, but also makes my board crash?
Thanks in advance!
//Includes
#include <PubSubClient.h>
#include <MKRGSM.h>
#include "DHT.h"
#include <Adafruit_Sensor.h>
//Var declaration
//SIM-internet connection
GSMClient net;
GPRS gprs;
GSM gsmAccess;
const char pin[] = "my pin";
const char apn[] = "my apn";
const char login[] = "my login";
const char password[] = "my password";
//MQTT connection
PubSubClient client;
const String serialNumber = "1";
const String mqtt_server = "server_ip";
const String topic = "/prototype/" + serialNumber;
//DHT sensor PIN declaration
#define DHTPIN 2 //DHT is pinned on 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void connect() {
//SIM not connected
bool connected = false;
Serial.print("Connecting to cellular network.");
//SIM connecting
while (!connected) {
if ((gsmAccess.begin(pin) == GSM_READY) &&
(gprs.attachGPRS(apn, login, password) == GPRS_READY)) {
//SIM connected
connected = true;
Serial.print("Connected to cellular network.");
}
else {
//If SIM doesn't connect
Serial.print(".");
delay(1000);
}
}
}
void setup() {
Serial.begin(9600);
//Connect to Docker MQTT
client.setServer(mqtt_server.c_str(), 8086);
client.connect(serialNumber.c_str());
Serial.print("MQTT connection state: ");
Serial.println(client.state());
//Start DHT 11
dht.begin();
}
void loop() {
delay(10000);
//Get DHT values
float humidty = dht.readHumidity();
float temperature = dht.readTemperature();
//Create JSON out of values and send it.
const String json = "{\"temperature\": " + String(temperature, 2) + ", \"humidity\": " + String(humidty) + " }";
Serial.println(json);
client.publish(topic.c_str(), json.c_str());
//Check if MQTT connection is holding.
Serial.print("MQTT connection state: ");
Serial.println(client.state());
//Reconnect if MQTT connection is lost.
if (!client.connected()) {
Serial.println("MQTT disconnected! Trying reconnect.");
client.connect("whatever");
}
}

As hashed out in the comments
You never called the connect() function so the GSM network was never setup.
You then probably need to use the GSMClient to initialise the PubSubClient so it knows how to access the network.

Related

Can't connect ESP32 to MQTT

I have been trying to connect my ESP32 with HiveMQ MQTT broker url. It connects when I use free public MQTT broker like broker.hivemq.com, but when I use my url which I got after registering in HiveMQ, it doesn't connect. It returns error with code 2.
I have used this MQTT broker url with windows MQTT client app and it works fine but it doesn't work with ESP32.
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi
const char *ssid = "********"; // Enter your WiFi name
const char *password = "********"; // Enter WiFi password
// MQTT Broker
const char *mqtt_broker = "591c2cacc87d4e248d106212ae6e0d4f.s2.eu.hivemq.cloud";
const char *topic = "esp32/test";
const char *mqtt_username = "*******";
const char *mqtt_password = "*******";
const int mqtt_port = 8883;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
// Set software serial baud to 115200;
Serial.begin(115200);
// connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
//connecting to a mqtt broker
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Public emqx mqtt broker connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// publish and subscribe
client.publish(topic, "Hi EMQ X I'm ESP32 ^^");
client.subscribe(topic);
}
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void loop() {
client.loop();
}
In the comments, #hcheung said:
When you use MQTT over TLS (port 8883), you need to use WiFiClientSecure.h and add the root CA of broker.hivemq.com to your sketch. Refer to WiFiClientSecure on how to do it.
You can get the root CA of your HiveMQ broker with the following OpenSSL method:
openssl s_client -connect hivemq-broker-host:8883 -showcerts
Change hivemq-broker-host with your MQTT host.
Using a combination of Farhan's example and a few other examples I found elsewhere, I was able to get this to work.
First, open a terminal run the command from Johnny Boy's answer (This assumes you have openssl installed. If not, install it.
openssl s_client -connect YOUR_URL.hivemq.cloud:8883 -showcerts
You'll get three certificates. They look like this
-----BEGIN CERTIFICATE----- MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
...Lots more characters that I'll omit for brevity...
-----END CERTIFICATE-----
The third certificate is the one you want. Copy this certificate out of your terminal (including the BEGIN and END CERTIFICATE parts). Paste the cert into your ESP32 code as a const char variable, such as:
const char *ROOT_CERT = "-----BEGIN CERTIFICATE-----\n"
"MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
... etc..
Using the WiFiClientSecure library mentioned in the comments, use the setCACert function to utilize your certificate. The rest of the code looks pretty close to what Farhan had. In my example, a few of the variables, including the ROOT_CERT variable from above, were defined in another file (WifiCredentials.h):
#include <PubSubClient.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
#include "WifiCredentials.h"
#include <WiFiClientSecure.h>
*********/
Helpful References:
* https://randomnerdtutorials.com/esp32-web-server-arduino-ide/
*
*********/
WiFiClientSecure wifiClient;
PubSubClient mqttClient(wifiClient);
char *mqttServer = "YOUR_URL.hivemq.cloud";
int mqttPort = 8883;
const char *mqtt_password = "password_I_setup_at_hivemq";
const char *mqtt_username = "username_I-setup_at_hivemq";
void setup() {
Serial.begin(9600);
// Connect to Wi-Fi network
Serial.print("Connecting to ");
Serial.println(WifiSSID);
WiFi.begin(WifiSSID, WifiPassword);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("...Still Connecting");
}
Serial.println("");
Serial.println("WiFi connected.");
wifiClient.setCACert(ROOT_CERT);
}
void loop(){
if (!mqttClient.connected()) {
mqttClient.setServer(mqttServer, mqttPort);
// set the callback function
mqttClient.setCallback(callback);
Serial.println("Connecting to MQTT Broker...");
while (!mqttClient.connected()) {
Serial.println("Reconnecting to MQTT Broker..");
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Connected to MQTT BRoker!.");
// subscribe to topic
mqttClient.subscribe("/transactions/device1");
mqttClient.publish("/transactions/device1", "testing hello");
} else {
Serial.print("failed with state ");
Serial.print(mqttClient.state());
delay(2000);
}
}
}
mqttClient.loop();
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Callback - ");
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
}
Connect a tool like MQTT Dash to your HiveMQ instance, open a serial monitor, and test your code.

Esp8266 Http communication over Wifi

Goal
I am trying to send temperature data between two Esp8266 modules.
The Server reads a temperature value from the analog pin and is supposed to host this data on a website (I don´t know the correct term for that) over a wifi access point that also runs on the Esp. The Client is supposed to receive the temperature value and output it via serial.
What works
I can connect my phone to the access point and access the data on the IP of the access point. I also can connect the client Esp to my home wifi and it outputs code from different websites.
Problem
But when I try to connect it to the Esp wifi, the wifi login/connection works, but the http.GET function outputs -1 which corresponds to the error message "HTTPC_ERROR_CONNECTION_FAILED".
While the client is connected to the wifi of the Esp my phone displays a similar error message.
I also had the problem that the esp could not continually read A0 while using the Wifi, so I had to build in a delay.
Server Code
// Import required libraries
#include "ESPAsyncWebServer.h"
#include "WiFi.h"
#include <math.h>
#include <ESP8266WiFi.h>
//Constants for temperature calculation
double T;
float V_0 = 5.02;
float R_1 = 99700.0;
float a = 283786.2;
float b = 0.06593;
float c = 49886.0;
float set = 30;
int sensorValue;
float voltage;
// Set your access point network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String readTemp() {
return String((-1.0/b)*(log(((R_1*voltage)/(a*(V_0-voltage)))-(c/a)))); //Function to calculate temperature from Voltage
}
void setup(){
Serial.begin(115200);
Serial.println();
// Setting the ESP as an access point
Serial.print("Setting AP (Access Point)…");
// Remove the password parameter, if you want the AP (Access Point) to be open
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readTemp().c_str());
});
// Start server
server.begin();
}
void loop()
{
//reading of A0
Serial.println(voltage);
Serial.println(readTemp().c_str());
sensorValue = analogRead(0); //?Wifi not working, when reading A0?
delay(10);
voltage = sensorValue * (3.3 / 1023.0);
}
Client Code
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h>
ESP8266WiFiMulti WiFiMulti;
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";
void setup () {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting..");
}
Serial.print("Connected to ");
Serial.println(ssid);
}
void loop() {
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
HTTPClient http; //Declare an object of class HTTPClient
http.begin("http://192.168.4.1/temperature"); //Specify request destination
int httpCode = http.GET(); //Send the request
if (httpCode > 0) { //Check the returning code
String payload = http.getString(); //Get the request response payload
Serial.println("/////////////////////////////////////////////////////////////");
Serial.println(payload); //Print the response payload
}
else{Serial.println("Error");}
http.end(); //Close connection
}
delay(30000); //Send a request every 30 seconds
}
I would really appreciate it if anybody could help me with this because I have been tearing my hair out for weeks over this. Thanks in advance and sorry for any grammatical or spelling mistakes in advance.

How to connect esp_mqtt library to thingsboard.io?

I am trying to publish sensor data using esp_mqtt library to thingsboard.io dashboard. But the connection between the library and thingsboard is not getting established. I am using esp8266 nodeMCU v2 and platformIO
Here is the link to the esp_mqtt library documentation.
https://github.com/tuanpmt/esp_mqtt/blob/master/README.md
Here is the code snippet :
#include <ESP8266WiFi.h>
#include <MQTT.h>
#define CLIENT_ID "client1"
#define TOPIC "v1/devices/me/telemetry"
#define TOKEN "access token"
MQTT myMqtt(CLIENT_ID,"localhost",1883);
const char* ssid = "ssid";
const char* password = "password";
void setup() {
Serial.begin(115200);
delay(1000);
setup_wifi();
Serial.println("Connecting to MQTT server");
// setup callbacks
myMqtt.onConnected(myConnectedCb);
myMqtt.onDisconnected(myDisconnectedCb);
myMqtt.onPublished(myPublishedCb);
myMqtt.onData(myDataCb);
Serial.println("connect mqtt...");
myMqtt.setClientId(CLIENT_ID);
myMqtt.setUserPwd(TOKEN,"");
myMqtt.connect();
Serial.println("subscribe to topic...");
myMqtt.subscribe(TOPIC);
delay(10);
}
void loop() {
float value = analogRead(A0);
String temp=String(value);
// publish value to topic
String payload = "{";
//payload += "\"temperature\":"; payload += temperature; payload += ",";
payload += "\"temperature\":"; payload += temp;
payload += "}";
// Send payload
char attributes[100];
payload.toCharArray( attributes, 100 );
//String(attributes);
boolean result = myMqtt.publish("v1/devices
/me/telemetry",attributes,100,1,0);
delay(1000);
}
You are trying to connect to localhost unless you are running a broker on the ESP8266 this is never going to work.
You need to know what the host name of thingsboard.io's broker is and replace localhost with that value. The port number may also need changing.
I'm also guessing the clientid may need to be something a little more unique than client1

Not able to Receive subscribed Message with PubSubClient.h in Arduino Uno R3

#include "SPI.h"
#include “WiFiEsp.h”
#include <WiFiEspClient.h>
#include “SoftwareSerial.h”
#include <PubSubClient.h>
#include <WiFiEspUdp.h>
float temp=0;
int tempPin = 0;
int isClientConnected = 0;
char data[80];
char ssid[] = “SSID”; // your network SSID (name)
char pass[] = “PASSWORD”; // your network password
int status = WL_IDLE_STATUS; // the Wifi radio’s status
char deviceName = “ArduinoClient1”;
IPAddress server(xxx,xxx,xxx,xxx); //MQTT server IP
IPAddress ip(192,168,43,200);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print(“Message arrived [“);
Serial.print(topic);
Serial.print(“] “);
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println("-");
}
// Emulate Serial1 on pins 6/7 if not present
WiFiEspClient espClient;
PubSubClient client(espClient);
SoftwareSerial Serial1(6,7); // RX, TX
void setup(){
Serial.begin(9600);
Serial1.begin(9600);
WiFi.init(&Serial1);
WiFi.config(ip);
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
while (true);
}
while ( status != WL_CONNECTED) {
Serial.print("Attemptingonnect to WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
Serial.print("WiFius : ");
Serial.println(status);
}
//connect to MQTT server
client.setServer(server, 1883);
client.setCallback(callback);
isClientConnected = client.connect(deviceName);
Serial.println("+++++++");
Serial.print("isClientConnected;
Serial.println(isClientConnected);
Serial.print("client.state");
Serial.println(client.state());
if (isClientConnected) {
Serial.println("Connected…..");
client.publish("status","Welcome to ISG");
client.subscribe("isg/demoPublish/rpi/ardTempWarn");
//Not able to recieve for this subscribed topic on Arduino Uno Only if I
//print it returns 1
}
}
void loop() {
temp = (5.0 * analogRead(tempPin) * 100.0) / 1024;
Serial.print(" temp : " );
Serial.println(temp);
Serial.print("client.connected);
Serial.println(client.connected());
if (!client.connected()) {
reconnect();
}
client.publish("isg/demoPublish/ard1/tempLM35",String(temp).c_str());
// able to receive data at other
// clients like RPI,Web using Mosquitto broker
client.loop();
delay(5000);
}
void reconnect() {
Serial.println("Device is trying to connect to server ");
while (!client.connected()) {
if (client.connect(deviceName)) {
} else {
delay(5000);
}
}
}
I am using Arduino Uno R3 and ESP8266-01 as wifi connector.
I have to read temperature data and send to Mosquitto ,MongoDB and Raspberry Pi and receive a data on specific condition for that i have subscribed a topic in Arduino.
I am able to receive data from Arduino to all other clients but I am not able to receive data on Subscribed topic in Arduino. But all other deviced like MongoDB able to receive data from Raspberry Pi.
I have used Arduino Uno R3, ESP8266-01 devices and liberary for to connect and send/receive data WiFiEsp.h, WiFiEspClient.h, WiFiEspUdp.h, SoftwareSerial.h, PubSubClient.h
client.subscribe("topic"); returns 1
Also callback function implemented but not able to get call.
So can any one help me why I am not getting subscribed topic message in Arduino?
I have follow https://sonyarouje.com/2016/03/15/mqtt-communication-with-arduino-using-esp8266-esp-01/#comment-111773
The library that you are using has bug in callback hence it would be better that you use other library my preference would be
https://github.com/vshymanskyy/TinyGSM
this library include almost all variants of SIM800(A,C,L,H,808), variants of SIM900(A,D,908,968), ESP8266 (mounted on arduino), Ethernet shield etc. It worked for me, as same issue bugged me for almost 1-2 weeks but latter was able to receive all subscribed message irrespective of mode of communication(GSM,Ethernet,WiFi)

Connecting esp8266 to AWS IoT

I am trying to connect a WeMos D1 mini based on ESP8266 to the Amazon Web Service AWS IoT using https://github.com/heskew/aws-sdk-arduino.
However, when I flash the device, I get a 403 back, with the following message:
"Credential should be scoped to correct service: 'execute-api'. "
Changing
this->awsService = "iotdata";
to
this->awsService = "execute-api";
in AmazonIOTClient.cpp results in a 404:
"No method found matching route things/my-thing/shadow for http method POST."
and, according to this thread the service should be 'iotdata' for the request to succeed.
Has someone had the same problem and figured out a way to get it running? If so, help would be greatly appreciated. Thanks!
Here the full code for the example:
#include <AmazonIOTClient.h>
#include <Esp8266AWSImplementations.h>
#include <AWSFoundationalTypes.h>
#include "keys.h"
const int sleepTimeS = 30;
void printWiFiData();
void printCurrentNetwork();
void publish(const char *topic, String data);
void publishToAWS();
void setup() {
Serial.begin(9600);
Serial.println("Started!");
publishToAWS();
ESP.deepSleep(sleepTimeS * 1000000);
}
void loop() {
}
void printWiFiData() {
// IP address
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// MAC address
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
Serial.print(mac[5], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.println(mac[0], HEX);
}
void printCurrentNetwork() {
// SSID
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// signal strength:
Serial.print("signal strength (RSSI): ");
Serial.println(WiFi.RSSI());
}
void publish(const char *topic, String data) {
AmazonIOTClient iotClient;
ActionError actionError;
Esp8266HttpClient httpClient;
Esp8266DateTimeProvider dateTimeProvider;
Serial.println();
Serial.print("Connecting to ");
Serial.print(wifiSsid);
Serial.println("...");
WiFi.begin(wifiSsid, wifiPwd);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(50);
}
Serial.println("");
Serial.println("WiFi connected");
printCurrentNetwork();
printWiFiData();
delay(50);
Serial.println("Initializing IoT client...");
iotClient.setAWSRegion(awsIotRegion);
iotClient.setAWSEndpoint(awsIotEndpoint);
iotClient.setAWSDomain(awsIotDomain);
iotClient.setAWSPath("/things/my-thing/shadow");
iotClient.setAWSKeyID(awsKeyID);
iotClient.setAWSSecretKey(awsSecKey);
iotClient.setHttpClient(&httpClient);
iotClient.setDateTimeProvider(&dateTimeProvider);
delay(50);
Serial.println("Updating thing shadow...");
MinimalString shadow = ("{\"state\":{\"reported\":{\"text\":" + data + "}}}").c_str();
char* result = iotClient.update_shadow(shadow, actionError);
Serial.print("result: ");
Serial.println(result);
}
void publishToAWS() {
Serial.println("Publishing to AWS IoT Broker");
publish("my-thing/text", "Hello World!");
}
keys.cpp file:
#include "keys.h"
// AWS User Credentials
const char* awsKeyID = "XXXXXXXXXXXXXXXXXXXX";
const char* awsSecKey = "X1xxx23xxxxXXXX34XXxxxxX56xXxxxxxxXx789x";
// AWS IoT
const char* awsIotRegion = "eu-central-1";
const char* awsIotEndpoint = "xxxxxxxxxxxxxx";
const char* awsIotDomain = "iot.eu-central-1.amazonaws.com";
// Init and connect WiFi to local WLAN
char* wifiSsid = "mySSID";
char* wifiPwd = "password";
I can finally contribute something :)
I got this very same example working a few days ago. However I used the same library just a different branch iot-get-shadow-and-cleanup. I don't recall having to make any changes as the one you mentioned:
this->awsService = "iotdata"; to this->awsService = "execute-api";
Here are the correct settings for your AWS endpoint that goes into keys.cpp
awsIotRegion = "us-east-1";
awsIotEndpoint = "amazonaws.com";
awsIotDomain = "axxxxs2pxxxrlx.iot.us-east-1.amazonaws.com";`
Also add delete[] result; to the end of the publish() to save some precious heap space.
I would recommend using the iot-get-shadow-and-cleanup branch since it has fixes for memory leaks.
I made one more change to resolve all issues with running out of heap space when updating the shadow continiously. In AWSClient4.cpp I changed // delete[] server; to delete[] data; - I am not 100% sure if this was necessary but combined with the addition of delete[] result; I was able to update the shadown every minute continuously for an hour without loosing any heap.
Hope this helps.

Resources