0

Adafruit_MQTT_Client setup with users params?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Adafruit_MQTT_Client setup with users params?

by xtalker on Thu Jul 13, 2017 3:47 pm

Hopefully this will be a simple question, but I've had no luck in searching for the answer.

I've setup the Adafruit sample code from the "mqtt_esp8266" example code and it works great. I'd now like to set up an mqtt subscription with parameters gathered from the user via a web page served from the same program.

This means I have to put the user data in place of the constants in the class call below:

Code: Select all | TOGGLE FULL SIZE
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);


Of course the user data comes from code late in the setup{} block.

My problem is how to handle references to the "mqtt" variable before it's defined. Is this possible?

Thanks,
Bob

xtalker
 
Posts: 10
Joined: Thu Jun 13, 2013 8:05 am

Re: Adafruit_MQTT_Client setup with users params?

by xtalker on Mon Jul 17, 2017 10:16 am

Ok, no responses, perhaps my question was too vague.

This is more of an Arduino coding question I guess.

I currently have this line in the "variable declaration section" of my Arduino code.

Code: Select all | TOGGLE FULL SIZE
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);


What I'm trying to do is gather the AIO_USERNAME, AIO_KEY params from the user from a page page served by the same program. These parameters are not available until late in the Arduino setup{} section. If I move the line above to the setup{} section I then get "mqtt variable not declared in this scope" errors (specifically: when it's used in the "MQTT_connect()" function).

Is there a way to do this?

Thanks for any help!
Bob

xtalker
 
Posts: 10
Joined: Thu Jun 13, 2013 8:05 am

Re: Adafruit_MQTT_Client setup with users params?

by adafruit_support_rick on Tue Jul 18, 2017 2:02 pm

So, what you want to do is to dynamically allocate the mqtt object, instead of statically allocating it.

instead of this:
Code: Select all | TOGGLE FULL SIZE
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

do this:
Code: Select all | TOGGLE FULL SIZE
Adafruit_MQTT_Client* mqtt = NULL;
Adafruit_MQTT_Subscribe* myFeed = NULL;

Then, once you have the username and key, create the object. Something like this (
Code: Select all | TOGGLE FULL SIZE
  mqtt = new Adafruit_MQTT_Client(&client, AIO_SERVER, AIO_SERVERPORT, GetMQTTUser(), GetMQTTKey());
  String myFeedStr = String(GetMQTTUser()) + "/feeds/myFeed";
  myFeed = new Adafruit_MQTT_Subscribe(mqtt,  myFeedStr.c_str());


Remember that myFeed and mqtt are pointers now. You'll have to dereference them with '->' instead of '.'

adafruit_support_rick
 
Posts: 34841
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: Adafruit_MQTT_Client setup with users params?

by xtalker on Thu Jul 20, 2017 11:25 am

Thanks Rick, I made some great progress with your help! Now the next problem:

This code works and subscribes to AIO just fine (ie: mqtt->connect() returns 0)

Code: Select all | TOGGLE FULL SIZE
char* myFeedStr = "myUserName/feeds/myFeed";
myFeed = new Adafruit_MQTT_Subscribe(mqtt, myFeedStr);

But I can't figure out how to dynamically build the subscribe path. The code below is per your suggestion and doesn't work. All the code below compiles ok but doesn't connect to AIO (mqtt->connectErrorString returns "Connection failed").
Code: Select all | TOGGLE FULL SIZE
char aio_username[12] = "myUserName";  //Adafruit IO username
char aio_feed[20] = "myFeed";          //Adafruit IO feed
String test = String(aio_username) + "/feeds/" + String(aio_feed);
myFeed = new Adafruit_MQTT_Subscribe(mqtt, test.c_str());

I then tried this with the same result:
Code: Select all | TOGGLE FULL SIZE
char aio_username[12] = "myUserName";  //Adafruit IO username
char aio_feed[20] = "myFeed";          //Adafruit IO feed
char temp[50];
sprintf(temp, "%s/feeds/%s",aio_username,aio_feed);
char *temp_ptr = temp;
myFeed = new Adafruit_MQTT_Subscribe(mqtt, temp_ptr);

In each case the subscribe path string looks fine when I print it, but obviously AIO doesn't like the pointer I send!
I'm not sure what else to try here!

Thanks again for your help,
Bob

xtalker
 
Posts: 10
Joined: Thu Jun 13, 2013 8:05 am

Re: Adafruit_MQTT_Client setup with users params?

by adafruit_support_rick on Thu Jul 20, 2017 12:50 pm

Really. No idea. It should work. Maybe try this?
Code: Select all | TOGGLE FULL SIZE
String test = String(aio_username) + "/feeds/" + aio_feed;

adafruit_support_rick
 
Posts: 34841
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: Adafruit_MQTT_Client setup with users params?

by xtalker on Thu Jul 20, 2017 1:07 pm

I tried your suggestion, but still get:

"Connection failed.... Retrying MQTT connection in 5 seconds..." (repeatedly)

Is it possible that there are logs on the server side that may give more detail on what exactly it doesn't like about the subscription path?

Thanks,
Bob

xtalker
 
Posts: 10
Joined: Thu Jun 13, 2013 8:05 am

Re: Adafruit_MQTT_Client setup with users params?

by adafruit_support_rick on Fri Jul 21, 2017 10:35 am

Ohhhhhhhh...! I know what's going on, I think. You're passing a pointer to the string to the Adafruit_MQTT_Subscribe constructor. The constructor copies the *pointer* into a local variable, it does not actually copy the string itself. I'm guessing that you exit your function after you create myFeed, but before you call connect.

So, what happens is that the local String variable test goes out of scope when you exit the function, and it destroyed. So, when you call connect, the variable in the Adafruit_MQTT_Subscribe class points to garbage.

The library really should copy the string into local storage instead of expecting the pointer to remain in scope. But it is what it is...

As a workaround, you can make test a global variable. Or, you can do the connect right after you create myFeed. Although if you do it that way, it might fail if you have to do a re-connect...

adafruit_support_rick
 
Posts: 34841
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: Adafruit_MQTT_Client setup with users params?

by xtalker on Fri Jul 21, 2017 11:19 am

Hey Rick, This code was all in the "setup{}" function with "MQTT_connect();" in the loop{} function.

Anyway, I got it working with this code (not that I can explain why exactly!):

Code: Select all | TOGGLE FULL SIZE
    char* subPath;
    char* fpath = "/feeds/";
    subPath = (char*)malloc(strlen(aio_username) + strlen(fpath) + strlen(aio_feed) + 2);
    strcpy(subPath, aio_username);
    strcat(subPath, fpath);
    strcat(subPath, aio_feed);
    myFeed = new Adafruit_MQTT_Subscribe(mqtt, (char*)subPath);


Thanks to some similar code I found here:
https://github.com/dafoink/IoT/blob/mas ... Sensor.ino

Hopefully this will save someone else some trouble sometime!

Bob

xtalker
 
Posts: 10
Joined: Thu Jun 13, 2013 8:05 am

Please be positive and constructive with your questions and comments.