AWS iot с esp32 получает сообщения из одних тем, но не из других?

Я использую эту библиотеку aws-iot для esp32, и у меня проблемы с получением сообщений от определенная тема.

Мой код:

if (device.connect(HOST_ADDRESS, const_cast<char*>(client_id.c_str())) == 0) {
    Serial.println("Connected To AWS");
    delay(1000);

    char getAcceptedTopic[60];
    strcpy(getAcceptedTopic, "Lamps/"); //these ones need to be strcpy to get it started
    strcat(getAcceptedTopic, const_cast<char*>(myLampCred.username.c_str()));
    strcat(getAcceptedTopic, "/rga");

    Serial.print("\ngetAcceptedTopic: ");
    Serial.print(getAcceptedTopic);


    char republishedShadowTopic[60];
    strcpy(republishedShadowTopic, "Lamp/");
    strcat(republishedShadowTopic, const_cast<char*>(myLampCred.username.c_str()));
    strcat(republishedShadowTopic, "/rs");



    if (0==device.subscribe(getAcceptedTopic, mySubCallBackHandler)) {
    //if (0==device.subscribe("Lamps/SamHang/rs", mySubCallBackHandler)) { //try just doing it with the string? 
    Serial.print("Subscribe Successful");
    } else {
    Serial.println("Subscribe Failed, Check The Thing Name and Certificates");
    while(1);
    } 

    if (0==device.subscribe("testchannel", mySubCallBackHandler)) {
    Serial.println("Subscribe Successful");
    } else {
    Serial.println("Subscribe Failed, Check The Thing Name and Certificates");
    while(1);
    } 
    //will need to add in effects/channel topic at some point, but since none of the effects code is set up yet anyways, theres no point in adding a topic now

    Serial.println(republishedShadowTopic);
    if (0 == device.subscribe(republishedShadowTopic, mySubCallBackHandler)){
        Serial.println("Subscribe Successful");
    } else {
        Serial.println("Subscribe Failed, Check The THing Name and Certificates");
        while(1);
    }

    delay(500);
    //send get request
    gettingShadow = true;
    std::string shadowGetTopic = "$aws/things/" + myLampCred.username + "Lamp/shadow/get";
    publishFunc(shadowGetTopic.c_str(), "");
} else {
    //could add error for this but unless the host address changes and EVERYTHING breaks or wifi isn't connected, then there shouldn't be a problem
    Serial.println("AWS connection failed, check the HOST address");
    while(1);
}

У меня есть три темы, на которые я подписан: testchannel, Lamps / user / rga (в переменной getAcceptedTopic) и Lamp / user / rs (в переменной republishedShadowTopic).

В этих разделах пользователь может изменить в зависимости от того, на какое устройство загружен код, а имя пользователя извлекается с помощью myLampCred.username (который возвращает std :: string). Таким образом, если myLampCred.username = actualUsername, тогда название темы getAccepted, на которое он должен подписаться, будет «Lamps / actualUsername / rga».

Я всегда могу получать сообщения по моей теме getAccepted и моей теме testchannel, но не получаю сообщения по теме republishedShadow. Если я заменю переменную republishedShadowTopic на «Lamp / actualUsername / rs», она будет работать и получать сообщения, как и должна. Я бы подумал, что проблема в том, как я объявляю / создаю переменную, но я делаю переменную темы getAccepted таким же образом, и она работает нормально?

Я также отправлял сообщения различной длины по каждой теме, и каждое сообщение получало одинаковый результат относительно своей темы, поэтому я не думаю, что это связано с содержанием сообщений. Я также проверил файл конфигурации и не думаю, что это что-то ограничивает? Я почти уверен, что любая проблема связана с сегментом кода, которым я поделился, поскольку любое полученное сообщение объявляется, когда оно приходит.

Моя текущая теория заключается в том, что где-то есть проблема с типом данных? но метод device.subscribe () запрашивает char *, и, насколько я знаю, это то, что я ему даю (я все еще не на 100% по всем char [] vs char * и const, я понимаю что такое каждый из них, но не как их использовать, я полагаю). Я пробовал различные формы преобразования символов и std :: string, но, похоже, ни один из них не работает, если он не основан на строковом литерале.

Я очень смущен этим, и любая помощь будет принята с благодарностью, спасибо! : D


person SamsTheNerd    schedule 05.01.2020    source источник


Ответы (1)


Код, создающий republishedShadowTopic, выглядит нормально. Строка, созданная этим кодом, должна быть такой же, как строковый литерал "Lamp/actualUsername/rs", просто посмотрите здесь.

Я не эксперт по Arduino, но, насколько мне известно, строковые литералы могут храниться в постоянной памяти (в случае Arduino это будет флэш-память, я думаю).

Попытка изменить строковый литерал приводит к неопределенному поведению: они могут храниться в хранилище только для чтения (например, .rodata) или в сочетании с другими строковыми литералами.

Причина, по которой он работает, когда вы используете строковый литерал, может заключаться в его статической продолжительности хранения.

Строковые литералы имеют статический срок хранения и, таким образом, существуют в памяти на протяжении всей жизни программы.

С другой стороны, ваш массив имеет автоматическую продолжительность хранения, что означает, что он может быть недействительным после выхода из текущей области.

Если вы посмотрите здесь, вы увидите, что адрес вашей строки был перенаправлен и сохранен прямо здесь.

После выхода из области видимости внутри этого оператора if:

if (device.connect(HOST_ADDRESS, const_cast<char*>(client_id.c_str())) == 0)

вы больше не можете полагаться на этот указатель. Я предполагаю, что вы получите сообщение после выхода из этого оператора if.

Вы очень легко можете проверить мою гипотезу. Просто сделайте этот массив статическим или глобальным и убедитесь, что он работает. Вы должны сделать то же самое с первым массивом, потому что вам, вероятно, повезло, что он сработал.

person chwala    schedule 05.01.2020