[Submission] MQTT Library and Sample

Spark is fairly focused on on the Spark Cloud functions and i’m sure working on the new hardware.

I agree that a more stable MQTT library is really useful, I’m keen to help out and test and put energy into Smark/MQTT but my C isn’t strong enough to dive down and debug the MQTT library / Spark TCP stack interaction.

Back to your problem.

your code line

float msg = atof( (const char *) payload);

Is doing in one line what i’m doing in two

char* cstring = (char *) payload;
long n = atol(cstring);

But my C’s not good enough to know if there is any difference. The obvious once is yours is const but that should be ok.

1 Like

Yes, you're right. Realized it after looking at the code to try it.

I tried your method for longs. I can work with long for the payload instead int or floats, that's fine. I'm still getting 0 however. Wondering what I'm doing wrong. Are you including any libraries in your code? Do you have Serial.begin(9600) enabled on the sparkcore program you're using MQTT on?

My code:

client.publish("11122","topic is 9999, in callback routine");
payload[length] = '\0';
char* cstring = (char *) payload;
long msg = atol (cstring);
  if (msg > 42)
    {
        client.publish("11122","msg is 43");
        myservo.write(170);
    }
    else
    {
        client.publish("11122","msg is NOT 43");
        myservo.write(10);
    }

This is what I'm publishing.

mosquitto_pub -h 192.168.2.15 -t 9999 -m 43

The debug code sees that the callback is being run, and that the topic is indeed 9999. But the message fails the if statement test. "msg is NOT 43" on debug topic 11122.

@Kitard Is there a Github repo for the library ?

My spark core would hang after a couple of days (perhaps a week) in the loop() call (using the latest firmware).

I believe that I tracked the problem to this part :

uint8_t MQTT::readByte() {
    while(!_client.available()) {}
    return _client.read();
}

(Same code in hirotakaster and Chris Howard’s versions)

Changing it to this :

uint8_t MQTT::readByte() {        
    unsigned long tstart = millis();    
    while(!_client.available()) {
        unsigned long tnow = millis();
        if (tnow-tstart > 20*1000UL) {
            _client.stop();
            return 0;
        }        
    }
    return _client.read();
}

seems to have fixed the problem ?

There must be a better way to handle this ?

1 Like

Newbie question, but maybe you could help me out me answering what to set for (Hirotakaster):

MQTT client(?server?, 1883, callback);

// connect to the server
client.connect(?sparkclient?);

What should be set for server and sparkclient respectively?

My server is located @ 192.168.1.254

Pass the IP to the function like this:

byte server[] = {192, 168, 1, 254};

Also sparkclient is just an identifier for the client, set it to what ever you like.

Important to note though if your using multiple nodes the client name needs to be different on each node or you going to see some weird behaviour between the nodes and the broker.

I tried the MQTT demo code with Mosquitto running on my home server 192.168.1.4

When I upload the sample code the led flashes the proper sequence and the web IDE reports success.
I am following the instructions here tutorialbut using my own Mosquitto server instead of CloudMQTT.
I tested my Mosquitto install and I can subscribe and publish using command line from two terminals.

Am I understanding this code correctly? The "inTopic" is replaced with "led/status" so that when I enter

mosquitto_pub -d -h 192.168.1.4 -t led/status -m "BLUE"

the led on the Spark should turn blue. I have tried replacing "server_name" with 192.168.1.4 or defining the
IP address as shown below. I can't figure out how to get the Spark to connect to the Mosquitto server.

#include "MQTT/MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);
MQTT client("server_name", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);

    if (message.equals("RED"))    
        RGB.color(255, 0, 0);
    else if (message.equals("GREEN"))    
        RGB.color(0, 255, 0);
    else if (message.equals("BLUE"))    
        RGB.color(0, 0, 255);
    else    
        RGB.color(255, 255, 255);
    delay(1000);
}


void setup() {
    RGB.control(true);

    // connect to the server
    client.connect("sparkclient");

    byte server_name[] = {192, 168, 1, 4};

    // publish/subscribe
    if (client.isConnected()) {
        client.publish("outTopic","hello world");
        client.subscribe("led/status");
    }
}

void loop() {
    if (client.isConnected())
        client.loop();
}

I copied the code in the first post above, and the replaced the IP address with the MQTT server that I was using. The port is the same. It does not require a username or password. I also changed what I was subscribing to and tested it. Nothing happens. No errors in flashing the code, and nothing comes from the MQTT server. I can send and receive from a command line, so I know the MQTT broker is working. I chose the anonymous authentication line and commented out the other line, without any success.

What else do I need to do to get this working?

MQTT Library fails to compile. See error info below.
Does this library need to be updated for newer spark firmware?

Error from Spark IDE compiler:

  In file included from ../inc/spark_wiring.h:29:0,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
  #warning "Defaulting to Release Build"
  ^
  In file included from ../../core-common-lib/CC3000_Host_Driver/evnt_handler.h:38:0,
  from ../inc/spark_wlan.h:33,
  from ../inc/main.h:38,
  from ../inc/spark_utilities.h:30,
  from ../inc/spark_wiring.h:33,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/CC3000_Host_Driver/socket.h:146:0: warning: "fd_set" redefined [enabled by default]
  #define fd_set _types_fd_set_cc3000
  ^
  In file included from /opt/gcc_arm/arm-none-eabi/include/stdio.h:47:0,
  from ../inc/spark_wiring_print.h:30,
  from ../inc/spark_wiring_string.h:33,
  from MQTT.cpp:55:
  /opt/gcc_arm/arm-none-eabi/include/sys/types.h:256:0: note: this is the location of the previous definition
  #define fd_set _types_fd_set
  ^
  In file included from ../../core-common-lib/CC3000_Host_Driver/evnt_handler.h:38:0,
  from ../inc/spark_wlan.h:33,
  from ../inc/main.h:38,
  from ../inc/spark_utilities.h:30,
  from ../inc/spark_wiring.h:33,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/CC3000_Host_Driver/socket.h:162:0: warning: "FD_SET" redefined [enabled by default]
  #define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp)
  ^
  In file included from /opt/gcc_arm/arm-none-eabi/include/stdio.h:47:0,
  from ../inc/spark_wiring_print.h:30,
  from ../inc/spark_wiring_string.h:33,
  from MQTT.cpp:55:
  /opt/gcc_arm/arm-none-eabi/include/sys/types.h:258:0: note: this is the location of the previous definition
  # define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
  ^
  In file included from ../../core-common-lib/CC3000_Host_Driver/evnt_handler.h:38:0,
  from ../inc/spark_wlan.h:33,
  from ../inc/main.h:38,
  from ../inc/spark_utilities.h:30,
  from ../inc/spark_wiring.h:33,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/CC3000_Host_Driver/socket.h:163:0: warning: "FD_CLR" redefined [enabled by default]
  #define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp)
  ^
  In file included from /opt/gcc_arm/arm-none-eabi/include/stdio.h:47:0,
  from ../inc/spark_wiring_print.h:30,
  from ../inc/spark_wiring_string.h:33,
  from MQTT.cpp:55:
  /opt/gcc_arm/arm-none-eabi/include/sys/types.h:259:0: note: this is the location of the previous definition
  # define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
  ^
  In file included from ../../core-common-lib/CC3000_Host_Driver/evnt_handler.h:38:0,
  from ../inc/spark_wlan.h:33,
  from ../inc/main.h:38,
  from ../inc/spark_utilities.h:30,
  from ../inc/spark_wiring.h:33,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/CC3000_Host_Driver/socket.h:164:0: warning: "FD_ISSET" redefined [enabled by default]
  #define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp)
  ^
  In file included from /opt/gcc_arm/arm-none-eabi/include/stdio.h:47:0,
  from ../inc/spark_wiring_print.h:30,
  from ../inc/spark_wiring_string.h:33,
  from MQTT.cpp:55:
  /opt/gcc_arm/arm-none-eabi/include/sys/types.h:260:0: note: this is the location of the previous definition
  # define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
  ^
  In file included from ../../core-common-lib/CC3000_Host_Driver/evnt_handler.h:38:0,
  from ../inc/spark_wlan.h:33,
  from ../inc/main.h:38,
  from ../inc/spark_utilities.h:30,
  from ../inc/spark_wiring.h:33,
  from ../inc/spark_wiring_stream.h:36,
  from ../inc/spark_wiring_client.h:24,
  from ../inc/spark_wiring_tcpclient.h:29,
  from MQTT.cpp:56:
  ../../core-common-lib/CC3000_Host_Driver/socket.h:165:0: warning: "FD_ZERO" redefined [enabled by default]
  #define FD_ZERO(fdsetp) __FD_ZERO (fdsetp)
  ^
  In file included from /opt/gcc_arm/arm-none-eabi/include/stdio.h:47:0,
  from ../inc/spark_wiring_print.h:30,
  from ../inc/spark_wiring_string.h:33,
  from MQTT.cpp:55:
  /opt/gcc_arm/arm-none-eabi/include/sys/types.h:261:0: note: this is the location of the previous definition
  # define FD_ZERO(p) (__extension__ (void)({ \
  ^
  In file included from ../inc/spark_wiring.h:29:0,
  from ../inc/application.h:29,
  from mqtttest.cpp:2:
  ../../core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning "Defaulting to Release Build" [-Wcpp]
  #warning "Defaulting to Release Build"
  ^
  mqtttest.cpp:5:42: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
  #line 1 
  ^
  mqtttest.cpp: In function 'void callback(char*, byte*, unsigned int)':
  mqtttest.cpp:11:15: warning: converting to non-pointer type 'char' from NULL [-Wconversion-null]

  ^
  mqtttest.cpp: In function 'void setup()':
  mqtttest.cpp:30:33: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

  ^
  mqtttest.cpp:34:48: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
  // connect to the server
  ^
  mqtttest.cpp:34:48: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
  mqtttest.cpp:35:35: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
  client.connect("sparkclient");
  ^
  mqtttest.o: In function `setup':
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:30: undefined reference to `MQTT::connect(char*)'
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:33: undefined reference to `MQTT::isConnected()'
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:34: undefined reference to `MQTT::publish(char*, char*)'
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:35: undefined reference to `MQTT::subscribe(char*)'
  mqtttest.o: In function `loop':
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:40: undefined reference to `MQTT::isConnected()'
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:41: undefined reference to `MQTT::loop()'
  mqtttest.o: In function `__static_initialization_and_destruction_0':
  /spark/compile_server/shared/workspace/2_compile-server2/core-firmware/build/mqtttest.cpp:5: undefined reference to `MQTT::MQTT(char*, unsigned short, void (*)(char*, unsigned char*, unsigned int))'
  collect2: error: ld returned 1 exit status
  make: *** [b43d8f930b22f0b9b2e8154ddd3da59ac91e0edc109424a182be4a17143d.elf] Error 1

I get the same thing unless I copy the code from the first post in this thread. That doesn’t rely on any additional files.

However, I never get my LED to turn on, which makes me wonder if I have to open a port in my firewall. That doesn’t seem right though, since I can subscribe to the MQTT broker with my computer (also behind the firewall) just fine.

Maybe I should just ask this. Can someone post some working code to subscribe and publish to a public MQTT broker such as this: http://iot.eclipse.org/sandbox.html Thanks!

The example code in the Spark IDE does not build. The error is in the include.

change

#include "MQTT.h"

to

 #include "MQTT/MQTT.h"

And it will compile.

To get the library talking to your local MQTT broker you need to pass the IP address in the correct format to the mqtt object. The following works for me.

byte server[] = { 192, 168, 1, 20 }; //insert  you IP Address
MQTT client(server, 1883, callback);

Also note there are some subtle differences between the example code in the IDE and the code posted my @bad_gui above. The main one is the subscription topic in the IDE example is “inTopic” and in the code above its “led/status”.

After solving these problems I was able to get the example to work and change the LED colour using mosquitto_pub

mosquitto_pub -h 192.168.x.x -t inTopic -m "GREEN"
1 Like

Mine still isn’t working. I followed the advice above without any luck. What did you do with this statement:

// connect to the server
client.connect("sparkclient");

@rpauto I think I’m running into the same issue that resulted in your question.

Did @hypergolic 's solution work for you?

I’m new to both MQTT and Spark.
currently using cloudMQTT.com instance as my “server”.

for line 4 in hirotakaster’s example, what should replace “server_name” in:

4.    MQTT client("server_name", 1883, callback);

I already added my cloudMQTT server url in line 29:

28.    // connect to the server
29.   client.connect("<cloudMQTT_Server_URL>", "<username>", "<password>");

So my question is - What goes in line 4? the same URL as the cloudMQTT url on line 29?

PS I have been following ToutHackAmon instructable here:

that page does not mention anything about changing or replacing “server_name” in line 4.

Cheers

Ok I had a bit more of a read of that tutorial and with all respect to the author I believe its wrong and leading people astray.

On the basis that our objective is to get this https://github.com/hirotakaster/MQTT/blob/master/firmware/examples/mqtttest.ino code working.

On line 4 as suggested in the original code.

MQTT client("server_name", 1883, callback);

This is where you need to specify this server address. Replace “server_name” with your MQTT broker address. In my case above I’m using an IP address.

on line 29 and where the tutorial becomes confusing.

client.connect(clientID, username, password);

The clientID is usually fairly arbitrary but i’m guessing that perhaps that cloud service requires the URL as a client ID.

However too reiterate line 29 is not where the MQTT server address is set that happens on line 4.

I’d recommend running a local http://mosquitto.org/ MQTT broker as its far simpler.

1 Like

Thanks @mrOmatic for taking the time to dig into this.

I’ll test out your suggestion as soon as I have time.

It sure would be nice to be able to follow a complete, and fully tested, guide for us newbies, but hey, this is what it takes to live on the cutting edge!

Okay, so I think I’m doing everything right here, but for some reason, the code is NOT working. I have to use a public server since I need to pull sensor data down from the cloud somewhere. If anyone has another MQTT broker I should try, let me know. Here is what does NOT work, even when I subscribe to the “led” topic:

#include "MQTT/MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);
MQTT client("198.41.30.241", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);

    if (message.equals("RED"))    
        RGB.color(255, 0, 0);
    else if (message.equals("GREEN"))    
        RGB.color(0, 255, 0);
    else if (message.equals("BLUE"))    
        RGB.color(0, 0, 255);
    else    
        RGB.color(255, 255, 255);
    delay(1000);
}

void setup() {
    RGB.control(true);
    
    // connect to the server
    client.connect("m2m.eclipse.org");

    // publish/subscribe
    if (client.isConnected()) {
        //client.publish("led","hello world");
        client.subscribe("led");
    }
}

void loop() {
    if (client.isConnected())
        client.loop();
}

Very close, only problem is that server needs to be either a domain name as a string or an ip address as an array of uint8_t. I think passing the IP address as a string isn’t going to work

I would try this. I tested the iot.eclipse.org broker on the commandline with mosquitto_sub & mosquitto_pub so it should work.

#include "MQTT/MQTT.h"

void callback(char* topic, byte* payload, unsigned int length);
MQTT client("iot.eclipse.org", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);

    if (message.equals("RED"))    
        RGB.color(255, 0, 0);
    else if (message.equals("GREEN"))    
        RGB.color(0, 255, 0);
    else if (message.equals("BLUE"))    
        RGB.color(0, 0, 255);
    else    
        RGB.color(255, 255, 255);
    delay(1000);
}

void setup() {
    RGB.control(true);

    // connect to the server
    client.connect("alligator_client");

    // publish/subscribe
    if (client.isConnected()) {
        //client.publish("led","hello world");
        client.subscribe("led");
    }
}

void loop() {
    if (client.isConnected())
        client.loop();
}

It works fine on my command line, but not on my Core. All LEDs on the Core go out after flashing, and nothing turns on. Here is what I’m publishing on the command line:

mosquitto_pub -h iot.eclipse.org -t led -m "RED"

In another window where I have subscribed to the topic, I can see “RED” show up, so I know it’s getting through the broker. The core runs other programs fine, just not this one.

I’ll give it a go tonight when i’m home and report back. I’ve never connected to a broker via a domain name only an IP address.

Could try the following, again works using mosquitto_pub/sub

byte server[] = { 198.41.30.241 };
MQTT client(server, 1883, callback);