pubnub / arduino

The Official PubNub Arduino-based API!
Other
103 stars 49 forks source link

Support for own instantiated client or possibility to execute client method before publish #19

Closed dawidcieszynski closed 5 years ago

dawidcieszynski commented 6 years ago

Hello, I started using PubNub for my new arduino (on ESP8266) but I want to publish messages by GPRS with SIM800 module. I'm using TinyGSM lib for other things like reading/sending sms'es etc.

TinyGSM provides TinyGsmClient class that can be used as PubNub_BASE_CLIENT but there is small problem. TinyGsmClient class require existing TinyGsm passed into constructor or as parameter of init method (if used prameterless constructor). PubNub_BASE_CLIENT is instantiated inside PubNub class and I have no possibility to pass constructor paramters or execute init method before publish.

Will it be possible to do something on PubNub_BASE_CLIENT before publish? Or better provide own instance of PubNub_BASE_CLIENT.

Now I have workaround for this by publish messages using PubNub http api with this example: https://github.com/vshymanskyy/TinyGSM/blob/master/examples/HttpClient/HttpClient.ino

vveljko commented 6 years ago

Hi @dawidcieszynski,

I understand the constructor problem, but I don't understand why you can't call init()? PubNub class inherits publicly from PubNub_BASE_CLIENT, so you should be able to call any public member function of PubNub_BASE_CLIENT on a PubNub object.

Can you please try and let us know if you find any issues?

dawidcieszynski commented 6 years ago

Hi, @vveljko!

PubSubClient inherits from PubNub_BASE_CLIENT, not PubNub. https://github.com/pubnub/arduino/blob/master/PubNubDefs.h#L67

PubNub_BASE_CLIENT is stored in private field named publish_client of PubNub class and it is returned only as result of publish. https://github.com/pubnub/arduino/blob/master/PubNubDefs.h#L324

So actually I can't do anything with it before any publish call.

vveljko commented 6 years ago

@dawidcieszynski Sure, sorry for being too concise. :)

So, my point was, you get a pointer to a PubNub_BASE_CLIENT from a call to, say, publish. That call will fail, of course, because it is not initialized correctly. Can you not then call init()? Like:

    TinyGsmClient *p  = PubSub.publish(....);
    p->init(....);
    /// now do the "real" publish

In any case, we're working on providing you a way to do this "nicely", but, it might take a while as we don't see a simple solution, so I'm thinking of ways you could do it with code "as-is".

dawidcieszynski commented 6 years ago

Hmm, I didn't try this way. I will check the getting client from first empty publish in a few days and share results here.

vveljko commented 6 years ago

Hi,

Please try the latest commit in the develop branch. This is preliminary support for clients such as your TinyGsm. The usage would be a little "unorthodox", because you need to declare your own PubNub object, in order to pass values for parameters of the constructor of your client class. You may #include <PunNub.h> and simply "ignore" the global PubNub object it declares, or "cut out the middle man" and #include <PubNubDefs.h>.

Then, in your code, do something like (for TinyGsmU201 we found here: https://github.com/vshymanskyy/TinyGSM/blob/master/TinyGsmClientU201.h):

TinyGsmU201 u201 = ....; // initialize it somehow
PubNub mypb(u201, 1, u201, 1, u201, 1); 
// now use `mypb` as you wish, it's ready to go!

Here we pass the same u201 object for all three clients that we use (for publish, history and subscribe), but, you can, of course, pass different, if you wish. Ditto for the mux parameter.

Please observe that this kind of "imperfect forwarding" can't handle default parameters, so, you need to pass both parameters to the constructor of TinyGsmU201::GsmClient declared as:

GsmClient(TinyGsmU201& modem, uint8_t mux = 1);

Please try this and let us know if it works for you.

dawidcieszynski commented 6 years ago

Hello, thanks for update.

Usage of TinyGsm is a bit different:

// declare modem connection, I use SIM800 here
#define TINY_GSM_MODEM_SIM800
#include <TinyGsmClient.h>
TinyGsm modem(Serial);

// create client object, here mux param is optional
TinyGsmClient push_gsm_client(modem);

// create PubNub object
#define PubNub_BASE_CLIENT TinyGsmClient
#define PUBNUB_DEFINE_STRSPN_AND_STRNCASECMP
#include <PubNubDefs.h>
PubNub gsmPubNub(push_gsm_client, push_gsm_client, push_gsm_client);

1) Now there is no default parameterless constructor so I had error:

In file included from src\push_gsm.cpp:15:0: lib\PubNub/Pubnub.h:4:14: error: no matching function for call to 'PubNub::PubNub()' class PubNub PubNub; ^ fixed with including PubNubDefs.h directly

2) There was errors with redundant constructors so I removed few constructors an helper methods

src\push_gsm.cpp:16:49: error: call of overloaded 'PubNub(TinyGsmClient&, int, TinyGsmClient&, int, TinyGsmClient&, int)' is a mbiguous PubNub gsmPubNub(client, 1, client, 1, client, 1); ^ src\push_gsm.cpp:16:49: note: candidates are: In file included from src\push_gsm.cpp:15:0: lib\PubNub/PubNubDefs.h:228:5: note: PubNub::PubNub(FIRST&, SECOND, FIRST&, SECOND, FIRST&, SECOND) [with FIRST = TinyGsmSim80 0::GsmClient; SECOND = int] PubNub(FIRST& first_for_publish, SECOND second_for_publish, ^ lib\PubNub/PubNubDefs.h:220:5: note: PubNub::PubNub(FIRST, SECOND, FIRST, SECOND, FIRST, SECOND) [with FIRST = TinyGsmSim800:: GsmClient; SECOND = int] PubNub(FIRST first_for_publish, SECOND second_for_publish, ^

Now it compiles but I get no messages through PubNub, I think that this may be because TinyGsm submits data to modem for each print execution instead of buffering and waiting to flush or close.

I will probably stay with HttpClient because this works without problems.

Thank you very much for your effort!

vveljko commented 5 years ago

Closing because of inactivity. Please reopen if this is still a concern.