0

I may have done some things incorrectly here, but this I what I have for publishing image that I read from serial camera to the MQTT broker:

void capturePicture() {
  if (!cam.takePicture())
    client.publish("info", "Failed to snap!");
  else
    client.publish("info", "Picture taken!");

  char length[21];
  uint32_t jpglen = cam.frameLength();

  sprintf(length, "buffer length: %d", jpglen);
  client.publish("info", length);

  byte wCount = 0;  // For counting # of writes
  client.publish("info", "transfer about to begin");
  client.beginPublish("picture", jpglen, false);
  client.publish("info", "after beginPublish");

  while (jpglen > 0) {
    uint8_t* buffer;
    uint8_t bytesToRead = min((uint32_t)16, jpglen);  // change 32 to 64 for a speedup but may not work with all setups!
    buffer = cam.readPicture(bytesToRead);

    client.write(buffer, bytesToRead);

    jpglen -= bytesToRead;
  }

  client.endPublish();
  client.publish("info", "transfer should have ended;");
}

I know the board is working, I am connected to the broker and I can receive messages. In the loop I am reading few sensors and pushing the string into the topic

void loop() {
  delay(1000);

  if (count == 5) capturePicture();

  if (!client.connected()) {
    reconnect();
  }

  int multi = analogRead(A2);
  int odor = analogRead(A1);
  int voc = analogRead(A0);

  char name[21];
  sprintf(name, "%d;%d;%d", multi, odor, voc);

  bool pubScss = client.publish("measurement", name);

  count++;
  client.loop();
}

and all that works fine.

what happens when capturePicture() gets executed is this:

Picture taken!
buffer length: 49048
transfer about to begin

--that's what I see on the topic's subscriber side, then it freezes for about 10secs and then it continues with sending messages from the loop.

So it seems like it never gets past client.beginPublish("picture", jpglen, false); call. I'm setting PubSubClient's buffer size to client.setBufferSize(10235);

What can be happening here? Something I can further test??

Thanks for advices!

0

1 Answer 1

0

The short form of the below is something like: "After calling .beginPublish(), call .endPublish() before making a call to either .publish() or .beginPublish().


We don't have your actual code. And that makes things difficult. However, this is a source of problems in what you have shown:

  client.beginPublish("picture", jpglen, false);
  client.publish("info", "after beginPublish");
  ...
  client.endPublish();

It kind of looks like you may intended the second publish to help you debug the initial problem. But again, we don't have your code. I don't know if this (or something just like it) is in your original. In any case, it's not doing you any good as a debug aid.


The .beginPublish()/[.write()-type stuff]/.endPublish() constructs a message in the MQTT protocol as you make these calls. By inserting .publish() call between them you are corrupting the communication. In short, you're embedding an MQTT message part way inside of another MQTT message.

Something a bit like saying

HowHello. are you today?

instead of

Hello. How are you today?

This is confusing something, probably the server. Perhaps also the library itself and any client that receives whatever the server ends up passing along.


I tested with a few variations on this code:

//#define CAUSE_TROUBLE

void one_shot_message() {
  client.publish(MQTT_TOPIC, "[hi]");
}

void do_test() {
  static const char part1[] = "<Hello";
  static const char part2[] = " World>";
  static const char both_parts_length = // just being very explicit 
      (sizeof part1 - 1) // part1 sans null terminator
    + (sizeof part2 - 1);// part2 sans null terminator
                       // the .publish accepting strings doesn't null terminate, so we aren't.

#ifndef CAUSE_TROUBLE
  one_shot_message(); // okay before beginPublish or after endPublish
#endif

  client.beginPublish(MQTT_TOPIC, both_parts_length, false);
#ifdef CAUSE_TROUBLE
  one_shot_message(); // not okay between beginPublish/endPublish
#endif
  client.print(part1);
  // tested with one_shot_message() called here (not-okay location) as well
  client.print(part2);
  client.endPublish();
}

What happens in the case of #define CAUSE_TROUBLE (at the least with server I'm using and the client I've written on a PC) is that a single corrupt-looking message comes through and then the ESP32 client reconnects to the server. Probably the server is closing the connection. It does this on a cycle of about 6 seconds. The corrupt message has the correct topic, which makes some sense because the topic is written as part of the .beginPublish() before there's an opportunity to corrupt the message. This may not be exactly what you're seeing, but I don't have good cause to think I should be seeing exactly what you're seeing; not the same exact code, client, server. It is similar anyway.


So, you can have client.publish("info", "before beginPublish"); or a client.publish("info", "after endPublish"); at those locations, but not between the begin and end calls. If you wanted to try doing something like that, you probably could probably do so by creating a second PubSubClient so that you could fire off these smaller messages in a separate protocol stream while in the middle of constructing/sending a larger message on the main stream. However the messages may not arrive in order, either because the of how the library works or because of timing in the network. So if you want to do that you may also want to send a counter value with each message so you can reconstruct the timeline in the sending code.

An aside regarding sprintf vs snprintf:

  char name[21];
  snprintf(name, sizeof name, "%d;%d;%d", multi, odor, voc);

sprintf() is something that exists to support very old code or very old compilers. There's otherwise no use case involving sprintf() that would not be better using snprintf()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.