Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function to change the MQTT packet size outside of the library #110

Closed
marcoschwartz opened this issue Jan 12, 2016 · 51 comments
Closed

Function to change the MQTT packet size outside of the library #110

marcoschwartz opened this issue Jan 12, 2016 · 51 comments

Comments

@marcoschwartz
Copy link

Hello, great library! For several of my projects I'd need to change the MQTT packet size, but I need to do it from outside of your library.

Indeed, now I'd need to change MQTT_MAX_PACKET_SIZE inside your library, which is not very convenient. A function or a way to do that without changing your library would be great! Thanks.

@skorokithakis
Copy link
Contributor

+1, I'm using PlatformIO which keeps a common cache for all libraries and this is presenting a big problem for me. An easier way to configure this would be great.

@lunanigra
Copy link

I need this too... 128 seems far too low.

We are using DeviceHub. Based on the long API key and Devic ID length you easily exceed 128.
So, perhaps set MQTT_MAX_PACKET_SIZE to 256 or better make it configurable.

Thanks :-)

@knolleary
Copy link
Owner

So the reason it's fixed is because we preallocate the memory at compile time. Given the limited memory of the original devices this targeted, I felt it was import to do this so potential memory issues could be caught then, and not at runtime (which are so much harder to debug). I also didn't want to set a default value that meant a lot of memory was pegged but went unused if you were only sending/receiving simple messages.

Any default value will have pros and cons.

Perhaps the answer is to move to fully dynamic memory allocation, but isn't a straight forward choice.

@skorokithakis
Copy link
Contributor

Could it be made optional with an ifdef so it can be defined at the preprocessor level perhaps, at least?

@knolleary
Copy link
Owner

I never found a way to allow an arduino sketch to ifdef its own value to override the library - all to do with how the Arduino tool chain preprocesses the app's files.

@skorokithakis
Copy link
Contributor

I use PlatformIO, which can do that (or, if not, I'm sure @ivankravets will approve a PR from me for it).

@ivankravets
Copy link
Contributor

@knolleary what is problem with #ifdef https://github.com/knolleary/pubsubclient/blob/master/src/PubSubClient.h#L23?

#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 128
#endif

PlatformIO users have full control of build process and can pass own build_flags. For example, platformio.ini

[env:myboard]
platform = espressif
framework = arduino
board = nodemcu
build_flags = -DMQTT_MAX_PACKET_SIZE=256

@knolleary
Copy link
Owner

@ivankravets because the last two times I've tried that approach it hasn't worked. The arduino tool chain includes library headers before it includes your sketch. So you cannot #define something in a sketch and have it picked up in the library.

@skorokithakis
Copy link
Contributor

The above would be ideal, and preserve backwards-compatibility.

@skorokithakis
Copy link
Contributor

@knolleary The build flags are included in the compiler command line, so they would take precedence. They aren't defined in the sketch.

@knolleary
Copy link
Owner

Ahh - sorry, read the rest of your comment.... so in the PlatformIO environment I can see how that would help. Doesn't address it for everyone else... but would be useful applied to all the customizable #defines.

@skorokithakis
Copy link
Contributor

@knolleary I think that's a good compromise, since it doesn't hurt Arduino IDE users but benefits PlatformIO users.

@knolleary
Copy link
Owner

I would certainly accept a PR that added that - as long as it applies to the other #defines and not just the packet size one.

@ivankravets
Copy link
Contributor

@knolleary Please don't mix Arduino IDE and it's builder with PlatformIO. PlatformIO uses only source code of Arduino framework core for AVR/SAM.

@ivankravets
Copy link
Contributor

I would certainly accept a PR that added that - as long as it applies to the other #defines and not just the packet size one.

Should I make it?

@skorokithakis
Copy link
Contributor

@ivankravets Too late! #119.

@knolleary
Copy link
Owner

Thanks @skorokithakis - will get it merged later today.

@ivankravets
Copy link
Contributor

@skorokithakis I'm not sure that need to redefine MQTT_VERSION. Let's wait for @knolleary.

@skorokithakis
Copy link
Contributor

@ivankravets That's the supported version for the client, the actual versions are defined a few lines above that.

@ivankravets
Copy link
Contributor

@knolleary thanks you too. Could you merge my PR with library.json? #44

@skorokithakis
Copy link
Contributor

+1 on that as well, so we also get this PR autoupdated in PlatformIO.

@skorokithakis
Copy link
Contributor

@knolleary Any news on this?

@knolleary
Copy link
Owner

Sorry, been flat out with work and have been at a conference yesterday/today. Will try to get to it all this weekend.

@skorokithakis
Copy link
Contributor

Sounds great, thank you!

@SirUli
Copy link

SirUli commented Feb 17, 2016

I think that one is solved - at least i can see it in the code :)

@knolleary
Copy link
Owner

It's solved for platorms that allow you to provide #defines outside of the sketch. That doesn't solve it for the Arduino environment. Still need to decide if we want to provide a programmatic wy for a sketch to set the packet size.

@SirUli
Copy link

SirUli commented Feb 18, 2016

@knolleary thanks - you are right, i just looked through my platformio glasses ;) Sorry!

@marcoschwartz
Copy link
Author

I would indeed go for the programmatic way to define the packet size - would be really useful for other libraries that uses this one :)

@marcoschwartz
Copy link
Author

Hello, any news on this issue? We'd really need it for our aREST library. Thanks!

@jonnor
Copy link

jonnor commented Jan 30, 2017

Use a template parameter for the buffer size, and then provide a default instantiation that uses the pre-existing MQTT_MAX_PACKET_SIZE ?

@jonnor
Copy link

jonnor commented Jan 30, 2017

I could not find a way which wasn't completely ugly using template parameter. Issue is that each and every method needs to become a template on the buffer size, which is a lot of distraction and complication. And one needs to the templated class, and then typedef an explicit instantiation for compatibility with existing code... Probably not worth it for saving 128 bytes in a cornercase.

So I reviewed #110 a bit instead

@mrdunk
Copy link
Contributor

mrdunk commented Apr 17, 2017

hi,
i'd like to add my interest in this feature as well.
I fully understand why the initial decision was made to statically allocate this buffer but it is very limiting for esp8266 users who have a reasonable amount of memory to play with. There are certainly lots of people online running into this issue.

I'd rather not have to include instructions in my code (which uses this library) on how to manually download and modify MQTT_MAX_PACKET_SIZE.
There's a nice opinion of why using a #define in a library is the wrong tool for a user changeable option here: https://stackoverflow.com/questions/14418936/overriding-define-in-libraries/14429506#14429506

So, solutions:

Option 1:
@vicatcu has a proposed change that i could be persuaded to support.
I agree with the majority of the comments in @jonnor 's review comments.
@vicatcu have you looked at @jonnor 's suggestions?

Option 2:
new in the constructor:

class PubSubClient {
  ......
 public:
  PubSubClient(Client& client) : buffer(new uint8_t[MQTT_MAX_PACKET_SIZE]), buffer_size(MQTT_MAX_PACKET_SIZE) ;
  PubSubClient(Client& client, uint16_t _buffer_size) : buffer(new uint8_t[buffer_size]), buffer_size(_buffer_size);
  ......
 private:
  uint8_t* buffer;
  uint16_t buffer_size;
  .....
}

Option 3:
A dynamically allocated solution would be trivial to implement:

class PubSubClient {
  ......
 public:
  PubSubClient(Client& client) : buffer(malloc(MQTT_MAX_PACKET_SIZE)), buffer_size(MQTT_MAX_PACKET_SIZE) ;
  ......
  bool setBuffer(uint16_t size){
    buffer = realloc(buffer, size);
    buffer_size = size;
    return (bool)buffer;
  }
  .....
 private:
  uint8_t* buffer;
  uint16_t buffer_size;
  .....
}

If it were up to me, i'd probably go with Option 3.
For both 2 and 3 very little code would need to change.
buffer would still be accessed and indexed in exactly the same way.
I don't really see the concerns about added complexity when debugging... Sure, buffer is on the Heap rather than the Stack but it's only allocated once by the constructor at startup (and once if the user elects to change the size).

Let me know your thoughts. I am prepared to work on any of these options if they are likely to be committed.
thanks for reading,
dunk.

@mrdunk
Copy link
Contributor

mrdunk commented May 4, 2017

Anyone have thoughts on pr #282 ?
It implements "Option 3" above in a way that does not change the existing API of this module; all existing code will continue to work as before.

@skorokithakis
Copy link
Contributor

I'm afraid I'm not knowledgeable enough to opine, but what you've done seems very reasonable to me, and without any downsides (it works the same as before unless the user elects to resize, no?).

@mrdunk
Copy link
Contributor

mrdunk commented May 4, 2017

Thanks for the feedback.

it works the same as before unless the user elects to resize, no?

Yes exactly. Existing users will not need to change code in any way.
Anyone who needs a larger buffer can re-size after initialization.

@knolleary has commented on pr #282 .
It probably makes sense to move further discussion there.

@Abdul-Samad-Saleem
Copy link

@knolleary Any update to modifying the maximum packet size in Arduino IDE?. Are we anywhere near to closing this issue?.

@Huibean
Copy link

Huibean commented Nov 20, 2018

is it possible to confige buffer using psram?

@jpswade
Copy link

jpswade commented Feb 3, 2019

I resolved this by switching to another library:

#include <MQTT.h>                 //https://github.com/256dpi/arduino-mqtt
MQTTClient mqtt(256);

@BingXiong1995
Copy link

This is because the defaul maxium length is 128b. So just go to PubSubClient.h and change #define MQTT_MAX_PACKET_SIZE 128 to #define MQTT_MAX_PACKET_SIZE 1024

@mcer12
Copy link

mcer12 commented Nov 5, 2019

Since this issue is dead for so long, I wonder if the library is even still being maintained. MQTT_MAX_PACKET_SIZE should be an optional parameter to init the library with. I personally got around this in my project by adding a compiler error so that users at least know what's wrong and how to fix it:

#if MQTT_MAX_PACKET_SIZE < 512  // If the max message size is too small, throw an error at compile time. See PubSubClient.cpp line 359
#error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h at line 359, increase it to 512"
#endif

@knolleary
Copy link
Owner

Hi @mcer12

it is maintained... but that doesn't mean I add every single feature users ask for, particularly ones that have been discussed many times before.

@mcer12
Copy link

mcer12 commented Nov 5, 2019

Seeing how many people struggle with this, one would think this should be a priority. It's absolutely your call what to prioritize in your own library, I am not refuting that.

@kartben
Copy link

kartben commented Jul 31, 2020

I believe this is fixed. There is now a PubSubClient#setBufferSize(size) API.

@knolleary
Copy link
Owner

Yup - all fixed. Just not done a trawl of the 300+ issues to spot which ones that feature closes ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests