1

I'm trying to implement a MQTT subscription and publisher to my C++ application. The publishing is working just fine, but it looks like the subscriber isn't receiving any massages at all.

#include "MbedJSONValue.h"
#include "OLEDDisplay.h"
#include "http_request.h"
#include "mbed.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

#include <MQTTClient.h>
#include <MQTTClientMbedOs.h>
#include <MQTTNetwork.h>
#include <MQTTmbed.h>
// UI
OLEDDisplay oled(MBED_CONF_IOTKIT_OLED_RST, MBED_CONF_IOTKIT_OLED_SDA,
                 MBED_CONF_IOTKIT_OLED_SCL);

SPI spi(MBED_CONF_IOTKIT_LED_SPI_MOSI, NC, MBED_CONF_IOTKIT_LED_SPI_SCLK);
DigitalOut myled(MBED_CONF_IOTKIT_LED1);
DigitalIn userbutton(MBED_CONF_IOTKIT_BUTTON1);

// Topic's publish
char *topicLightsOn = (char *)"iotkit/pub_lights";

// Topic's subscribe
char *topicLights = (char *)"iotkit/sub_lights/#";

// MQTT Brocker
char *hostname = (char *)"192.168.1.1";
int port = 1883;

// MQTT Message
MQTT::Message message;

// I/O Buffer
char *buf = "0";

// LED strip
unsigned int strip[9];

//function to turn lights on
void writeLED() {
  for (int p = 0; p < 9; p++)
    spi.write(strip[p]);
}

//function to turn lights off
void clearLED() {
  for (int p = 0; p < 9; p++) {
    strip[p] = 0;
    spi.write(strip[p]);
  }
}

//callback on message arrived
void messageArrived(MQTT::MessageData &md) {
  printf("message arrived");
  int value;
  MQTT::Message &message = md.message;
  printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\n",
         message.qos, message.retained, message.dup, message.id);
  printf("Topic %.*s, ", md.topicName.lenstring.len,
         (char *)md.topicName.lenstring.data);
  printf("Payload %.*s\n", message.payloadlen, (char *)message.payload);

  sscanf((char *)message.payload, "%i", &value);
  // TODO: Turn lights off/on
  if (value == 1) {
    // LED 1
    strip[0] = 1;
    strip[1] = 0;
    strip[2] = 0;
    writeLED();
    // LED 2
    strip[3] = 1;
    strip[4] = 0;
    strip[5] = 0;
    writeLED();
    // LED 3
    strip[6] = 1;
    strip[7] = 0;
    strip[8] = 0;
    writeLED();

    // setting the buf to the new value
    buf = (char *)message.payload;
  } else {
    clearLED();
  }
}

// function to publish to topic
void publish(MQTTNetwork &mqttNetwork,
             MQTT::Client<MQTTNetwork, Countdown> &client, char *topic) {
  MQTT::Message message;
  message.qos = MQTT::QOS0;
  message.retained = false;
  message.dup = false;
  message.payload = (void *)buf;
  message.payloadlen = strlen(buf) + 1;
  client.publish(topic, message);
}

/* char message[1024]; */

int main() {
  oled.clear();
  clearLED();

  WiFiInterface *network = WiFiInterface::get_default_instance();
  if (!network) {
    printf("ERROR: No WiFiInterface found.\n");
    return -1;
  }

  printf("\nConnecting to %s...\n", MBED_CONF_APP_WIFI_SSID);
  int ret =
      network->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD,
                       NSAPI_SECURITY_WPA_WPA2);
  if (ret != 0) {
    printf("\nConnection error: %d\n", ret);
    return -1;
  }

  MQTTNetwork mqttNetwork(network);
  MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork);
  printf("Connecting to %s:%d\r\n", hostname, port);
  int rc = mqttNetwork.connect(hostname, port);
  if (rc != 0)
    printf("rc from TCP connect is %d\r\n", rc);

  // Zugangsdaten - der Mosquitto Broker ignoriert diese
  MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
  data.MQTTVersion = 3;
  data.clientID.cstring =
      (char *)network->get_mac_address();
                                          
  data.username.cstring =
      (char *)network->get_mac_address(); 
  data.password.cstring = (char *)"password";
  if ((rc = client.connect(data)) != 0) {
    printf("rc from MQTT connect is %d\r\n", rc);
  }

  // MQTT Subscribe!
  client.subscribe(topicLights, MQTT::QOS0, messageArrived);

  printf("MQTT subscribe %s\n", topicLights);

  printf("Success\n\n");
  printf("MAC: %s\n", network->get_mac_address());
  SocketAddress a;
  network->get_ip_address(&a);
  printf("IP: %s\n", a.get_ip_address());

  while (1) {

    publish(mqttNetwork, client, topicLightsOn);
    thread_sleep_for(10000);

    /* client.subscribe(topicLights, MQTT::QOS0, messageArrived); */
    printf("\nlight status: %s\n", buf);
  }
}

if the client.subscribe(topicLights, MQTT::QOS0, messageArrived); is active the subscription will fire messages arrived, even if they are old ones.

I'm using a Mosquitto broker and putting it all into context with node-red. The messages arriving from the publisher are also saved to a MongoDB collection

Node-red config

Any ideas?

Brits
  • 14,829
  • 2
  • 18
  • 31
  • Is your SUBSCRIBE packet going through okay? You should receive a SUBACK back from the broker if you subscribed successfully. If not, this is probably the issue. – Mathyou Apr 20 '21 at 20:23
  • You say " the subscriber isn't receiving any messages at all" then later "is active the subscription will fire messages arrived" so I'm not really clear what your issue is? Note that at QOS0 messages the broker receives while your client is disconnected will not be stored (unless you have set the non-standard option `queue_qos0_messages` in `mosquitto.conf`). – Brits Apr 21 '21 at 04:46

1 Answers1

0

You need to use the MQTT client yield instead of thread_sleep_for.

while (1) {
  publish(mqttNetwork, client, topicLightsOn);
  /* thread_sleep_for(10000); */
  client.yield(10000);
        
  printf("\nlight status: %s\n", buf);
}
phlegx
  • 2,618
  • 3
  • 35
  • 39