Mqtt не подписывается на тему, преобразованную из массива String в массив символов.
Я до сих пор не уверен, каким должен быть точный заголовок для этого вопроса, потому что не знаю, в чем проблема.
Я использую библиотеку #include <MQTTClient.h>
mqtt для подписки на тему.
Эта тема создается динамически в зависимости от названия устройства. В настоящее время я тестирую имя устройства 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(".");
Я определил две переменные для одной темы
arn:aws:iot:us-east-2:xxxxxxxxxxxx:thing/myDeviceAbc/espIn
. один жестко запрограммирован hardCodedTopic
, а другой создается динамически espInTopic
.
Когда я подписываюсь на espInTopic
, я получаю сообщение MQTT подписка
на последовательной консоли, НО ничего не получено по этой теме, когда я публикую с портала AWS.
но когда я подписываюсь на hardCodedTopic
, я получаю все опубликованные сообщения. Я не могу понять, в чем проблема. Я проверил метод подписки mqttClient внутри заголовочного файла библиотеки, который определен следующим образом
int subscribe(const char* topicFilter, enum QoS qos, messageHandler mh);
/** Отмена подписки MQTT — отправить пакет отмены подписки MQTT и дождаться отмены подписки.
* @param themeFilter — шаблон темы, который может включать подстановочные знаки.
* @return код успеха -
*/
int unsubscribe(const char* topicFilter);
В качестве имени темы принимает const char*. Хотя, возможно, из-за преобразования из массива String в массив символов в массив символов espInTopic
могут быть добавлены неизвестные символы, но я также проверил размер и содержимое обеих тем, которые абсолютно одинаковы.
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<<<.
Полный код:
#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"
//ВЕБ-сокеты
#include <Hash.h>
#include <WebSocketsClient.h>
//MQTT ПАОЗ
#include <SPI.h>
#include <IPStack.h>
#include <Countdown.h>
#include <MQTTClient.h>
//Веб-сокет AWS MQTT
#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, измените их:
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 = ""; // раньше был глобальным, но позже я также попытался сохранить его локальным в методе subscribe()
const char* espOutTopic = "";
int port = 443;
//Конфигурация MQTT
const int maxMQTTpackageSize = 512;
const int maxMQTTMessageHandlers = 1;
const char response[] = "{\"response\": {\"request_id\":, \"data\":}}";
String nodeName = ""; // Имя должно быть уникальным
String nodeMac = "";
ESP8266WiFiMulti WiFiMulti;
AWSWebSocketClient awsWSclient(1000);
IPStack ipstack(awsWSclient);
MQTT::Client<IPStack, Countdown, maxMQTTpackageSize, maxMQTTMessageHandlers> client(ipstack);
//# подключений
long connection = 0;
unsigned long timer = 0;
unsigned long maxTimeOut = 7000; //7 секунд
//генерируем случайный 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;
}
//считаем поступившие сообщения
int arrivedcount = 0;
// обратный вызов для обработки сообщений mqtt
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);
}
//подключается к уровню веб-сокета и уровню mqtt
bool connect () {
if (client.isConnected ()) {
client.disconnect ();
}
//задержка не обязательна... она просто поможет нам получить "доверительное" значение пространства в куче
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;
}
//подписаться на тему mqtt
void subscribe () {
//подписка к теме
String espInTopicStr = baseTopic + "/" + "myDeviceAbc" + "/espIn";
// Строка 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);
}
}
//отправляем сообщение в тему mqtt
void sendmessage (const char* topic, String msg) {
//Отправить сообщение
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())
{
// КОНФИГ ПО УМОЛЧАНИЮ
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");
//////////запускаем точку доступа сервера веб-конфигурации
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());
//заполняем пароль ssid и wifi
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");
//заполняем параметры AWS
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();
//поддерживаем работоспособность mqtt
if (awsWSclient.connected ()) {
client.yield(50);
} else {
//обработка повторного подключения
if (connect ()){
subscribe ();
}
}
}
@Anum Sheraz, 👍0
Обсуждение1 ответ
Лучший ответ:
Функция c_str()
класса String
возвращает указатель на текущий внутренний массив символов. Этот указатель действителен только до тех пор, пока строка не существует и не изменяется.
Переменная espInTopicStr
определяется в функции и уничтожается в конце функции. Он освобождает память, выделенную для внутреннего массива символов.
Вы отправляете указатель на внутренний массив символов espInTopicStr
в client.subscribe
. Библиотека MQTT не копирует этот массив символов, а сохраняет только указатель. Позже библиотека использует указатель для вызова темы, но память в этом месте уже изменилась и не содержит названия темы.
поместив глобальную строку espInTopicStr, сработало!... большое спасибо, Юрай, за указание на проблему :), @Anum Sheraz
- Преобразование JSON в строку для MQTT
- форматирование строк в Arduino для вывода
- Проблемы с преобразованием byte[] в String
- Чтение строки, разделенной запятыми
- Использование строки вместо строки C, еще одна попытка затронуть загруженную проблему
- Разделение Serial.readString на массив строк
- strcmp, похоже, не работает
- Как заменить объекты String массивами символов, продолжая использовать строковые методы
в этом случае разница должна быть четко показана в Serial.print(espInTopic)? но сегодня я вставлю свой полный код., @Anum Sheraz
как я могу проверить погоду, она действительна позже?, @Anum Sheraz
это не глобально., @Anum Sheraz