I am still not sure what should be the exact Title for this question, because I don't know where the problem is.
I am using #include <MQTTClient.h>
mqtt library to subscribe on a topic.
This topic is created dynamically depending on the name of the device. Currently I am testing with device name myDeviceAbc
.
String baseTopic = "arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing";
String espInTopicStr = baseTopic + "/" + config.machineName + "/espIn"; //config.machineName is a string "myDeviceAbc"
const char* espInTopic = "";
espInTopic = espInTopicStr.c_str();
const char* hardCodedTopic = "arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing/myDeviceAbc/espIn";
int rc = client.subscribe(espInTopic, MQTT::QOS0, messageArrived);
if (rc != 0) {
Serial.print("rc from MQTT subscribe is ");
Serial.println(rc);
return;
}
Serial.println("MQTT subscribed");
Serial.print("size of hardcoded topic: ");
Serial.println(strlen(hardCodedTopic));
Serial.print("size of actual topic: ");
Serial.println(strlen(espInTopic));
Serial.print("hardCodedTopic >>>");
Serial.print(hardCodedTopic);
Serial.print("<<<");
Serial.println(".");
Serial.println("---");
Serial.print("espInTopic topic >>>");
Serial.print(espInTopic);
Serial.print("<<<");
Serial.println(".");
I have defined two variables for same topic
arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing/myDeviceAbc/espIn
. one is hardcoded hardCodedTopic
and other is created dynamically espInTopic
.
when I subscribe on espInTopic
, I get MQTT subscribed
message on serial console BUT nothing is received on this topic when I publish from AWS portal.
but when I subscribe on hardCodedTopic
I then receive all published messages. I cannot figure out what is the issue. I checked the mqttClient subscribe method inside the library header file, which is defined like this
int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh);
/** MQTT Unsubscribe - send an MQTT unsubscribe packet and wait for the unsuback
* @param topicFilter - a topic pattern which can include wildcards
* @return success code -
*/
int unsubscribe(const char* topicFilter);
It does takes const char* as topic name. I though maybe due to conversion from String to char array, there might be some unknown characters appended in the char array espInTopic
, but I also checked the size and content of both topics which is exactly the same.
size of hardcoded topic: 52
size of actual topic: 52
hardCodedTopic >>>arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing/myDeviceAbc/espIn<<<.
---
espInTopic topic >>>arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing/myDeviceAbc/espIn<<<.
Full Code:
#include <Arduino.h>
#include <Stream.h>
#include <EEPROM.h>
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFiMulti.h>
#include "helpers.h"
#include "global.h"
//AWS
#include "sha256.h"
#include "Utils.h"
//WEBSockets
#include <Hash.h>
#include <WebSocketsClient.h>
//MQTT PAHO
#include <SPI.h>
#include <IPStack.h>
#include <Countdown.h>
#include <MQTTClient.h>
//AWS MQTT Websocket
#include "Client.h"
#include "AWSWebSocketClient.h"
#include "CircularByteBuffer.h"
#define ACCESS_POINT_NAME "VM"
#define ACCESS_POINT_PASSWORD "12345678"
extern "C" {
#include "user_interface.h"
}
//AWS IOT config, change these:
char wifi_ssid[] = "TALKTALKAF521F";
char wifi_password[] = "xxxxxxxx";
char aws_endpoint[] = "xxxxxxxxxxxxxxxx.iot.us-east-2.amazonaws.com";
char aws_key[] = "xxxxxxxxxxxxxxxx";
char aws_secret[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
char aws_region[] = "us-east-2";
String baseTopic = "arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing";
//const char* espInTopic = ""; // was global before, but later I also tried to keep this local on subscribe() method
const char* espOutTopic = "";
int port = 443;
//MQTT config
const int maxMQTTpackageSize = 512;
const int maxMQTTMessageHandlers = 1;
const char response[] = "{\"response\": {\"request_id\":, \"data\":}}";
String nodeName = ""; // Name needs to be unique
String nodeMac = "";
ESP8266WiFiMulti WiFiMulti;
AWSWebSocketClient awsWSclient(1000);
IPStack ipstack(awsWSclient);
MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers> client(ipstack);
//# of connections
long connection = 0;
unsigned long timer = 0;
unsigned long maxTimeOut = 7000; //7 seconds
//generate random mqtt clientID
char* generateClientID () {
char* cID = new char[23]();
for (int i=0; i<22; i+=1)
cID[i]=(char)random(1, 256);
return cID;
}
//count messages arrived
int arrivedcount = 0;
//callback to handle mqtt messages
void messageArrived(MQTT::MessageData& md)
{
MQTT::Message &message = md.message;
Serial.print("Message ");
Serial.print(++arrivedcount);
Serial.print(" arrived: qos ");
Serial.print(message.qos);
Serial.print(", retained ");
Serial.print(message.retained);
Serial.print(", dup ");
Serial.print(message.dup);
Serial.print(", packetid ");
Serial.println(message.id);
Serial.print("Payload ");
char* msg = new char[message.payloadlen+1]();
memcpy (msg,message.payload,message.payloadlen);
}
//connects to websocket layer and mqtt layer
bool connect () {
if (client.isConnected ()) {
client.disconnect ();
}
//delay is not necessary... it just help us to get a "trustful" heap space value
delay (1000);
Serial.print (millis ());
Serial.print (" - conn: ");
Serial.print (++connection);
Serial.print (" - (");
Serial.print (ESP.getFreeHeap ());
Serial.println (")");
int rc = ipstack.connect(aws_endpoint, port);
if (rc != 1)
{
Serial.println("error connection to the websocket server");
return false;
} else {
Serial.println("websocket layer connected");
}
Serial.println("MQTT connecting");
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.MQTTVersion = 4;
char* clientID = generateClientID ();
data.clientID.cstring = clientID;
rc = client.connect(data);
delete[] clientID;
if (rc != 0)
{
Serial.print("error connection to MQTT server");
Serial.println(rc);
return false;
}
Serial.println("MQTT connected");
return true;
}
//subscribe to a mqtt topic
void subscribe () {
//subscript to a topic
String espInTopicStr = baseTopic + "/" + "myDeviceAbc" + "/espIn";
// String espOutTopicStr = baseTopic + "/" + config.machineName + "/espOut";
const char* espInTopic = espInTopicStr.c_str();
// espOutTopic = espOutTopicStr.c_str();
const char* hardCodedTopic = "arn:aws:iot:us-east-2:xxxxxxxxxxxxxx:thing/myDeviceAbc/espIn";
Serial.print("size of hardcoded topic: ");
Serial.println(strlen(hardCodedTopic));
Serial.print("size of actual topic: ");
Serial.println(strlen(espInTopic));
Serial.print("hardCodedTopic >>>");
Serial.print(hardCodedTopic);
Serial.print("<<<");
Serial.println(".");
Serial.println("---");
Serial.print("espInTopic topic >>>");
Serial.print(espInTopicStr.c_str());
Serial.print("<<<");
Serial.println(".");
int rc = 99;
while (rc != 0){
rc = client.subscribe(hardCodedTopic, MQTT::QOS0, messageArrived);
if (rc != 0) {
Serial.print("rc from MQTT subscribe is ");
Serial.println(rc);
return;
} else {
Serial.println("");
Serial.println("MQTT subscribed");
}
Serial.println("rc: " + String(rc));
delay(500);
}
}
//send a message to a mqtt topic
void sendmessage (const char* topic, String msg) {
//send a message
MQTT::Message message;
char buf[100];
strcpy(buf, msg.c_str());
message.qos = MQTT::QOS0;
message.retained = false;
message.dup = false;
message.payload = (void*)buf;
message.payloadlen = strlen(buf)+1;
int rc = client.publish(topic, message);
}
void setup() {
wifi_set_sleep_type(NONE_SLEEP_T);
EEPROM.begin(1024);
// for (int i = 0; i < 1024; ++i) { EEPROM.write(i, 0); }
Serial.begin(115200);
ardMegaSerial.begin(9600);
delay (2000);
//////////////////////////////////////////
if (!ReadConfig())
{
// DEFAULT CONFIG
config.configMode = true;
config.ssid = "N.A";
config.password = "N.A";
config.machineName = "N.A";
config.dhcp = true;
config.IP[0] = 192;config.IP[1] = 168;config.IP[2] = 1;config.IP[3] = 100;
config.Netmask[0] = 255;config.Netmask[1] = 255;config.Netmask[2] = 255;config.Netmask[3] = 0;
config.Gateway[0] = 192;config.Gateway[1] = 168;config.Gateway[2] = 1;config.Gateway[3] = 1;
WriteConfig(true);
Serial.println("default configs applied");
//////////starting web config server hotspot
Serial.println("No configuration stored, starting access point.");
ESP.eraseConfig();
WiFi.disconnect();
WiFi.setAutoConnect(false);
WiFi.setAutoReconnect(false);
WiFi.mode(WIFI_AP_STA);
nodeName = String(ACCESS_POINT_NAME) + String("-") + String(WiFi.softAPmacAddress().c_str());
WiFi.softAP(nodeName.c_str() , ACCESS_POINT_PASSWORD);
Serial.print("Connect to ssid " + nodeName + " to configure Node on IP: ");
Serial.println(WiFi.softAPIP());
ConfigureWifi();
server.on ( "/favicon.ico", []() { Serial.println("favicon.ico"); server.send ( 200, "text/html", "" ); } );
server.on ( "/", send_gateway_node_config_html );
server.on ( "/admin/values", send_gateway_node_config_values_html );
server.on ( "/admin/connectionstate", send_connection_state_values_html );
server.on ( "/style.css", []() { Serial.println("style.css"); server.send ( 200, "text/plain", PAGE_Style_css ); } );
server.on ( "/microajax.js", []() { Serial.println("microajax.js"); server.send ( 200, "text/plain", PAGE_microajax_js ); } );
server.onNotFound ( []() { Serial.println("Page Not Found"); server.send ( 400, "text/html", "Page not Found" ); } );
server.begin();
Serial.println( "HTTP server started" );
} else {
nodeName = String(ACCESS_POINT_NAME) + String("-") + String(WiFi.softAPmacAddress().c_str());
Serial.println("Device already configured");
Serial.println("Wifi SSID: " + config.ssid);
Serial.println("Wifi password: " + config.password);
Serial.println("Node name: " + config.machineName);
setupWifiAndAws();
}
//////////////////////////////////////////
}
void setupWifiAndAws() {
char ssidBfr[500];
strcpy(ssidBfr, config.ssid.c_str());
char passBfr[100];
strcpy(passBfr, config.password.c_str());
//fill with ssid and wifi password
WiFiMulti.addAP(ssidBfr, passBfr);
Serial.println ("connecting to wifi");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
Serial.print (".");
}
Serial.println("\nconnected");
ardMegaSerial.println("ESP Started\n");
//fill AWS parameters
awsWSclient.setAWSRegion(aws_region);
awsWSclient.setAWSDomain(aws_endpoint);
awsWSclient.setAWSKeyID(aws_key);
awsWSclient.setAWSSecretKey(aws_secret);
awsWSclient.setUseSSL(true);
if (connect ()) {
String espOutTopicStr = baseTopic + "/" + config.machineName + "/espOut";
espOutTopic = espOutTopicStr.c_str();
subscribe();
sendmessage (espOutTopic, "{\"device\":\"connected\"}}");
}
}
void loop() {
receiveFromArduino();
//responseTimeOutCheck();
//keep the mqtt up and running
if (awsWSclient.connected ()) {
client.yield(50);
} else {
//handle reconnection
if (connect ()){
subscribe ();
}
}
}