shurillu / CTBot

A simple (and easy to use) Arduino Telegram BOT Library for ESP8266/ESP32
MIT License
147 stars 34 forks source link

CTBotInlineKeyboard addButton String param issue #71

Open mad-b opened 3 years ago

mad-b commented 3 years ago

Hi Stefano

I was modifying a bit my already working application code that uses CTBot, then my inline menu stopped working. Then I noted an interesting thing:

(Sorry I am not familiar with styling here): Working code:

CTBotInlineKeyboard  kbd;
...
kbd.addButton("Act1", "Command1", CTBotKeyboardButtonQuery);

Then, since I was (am) replicating strings, decided to do:

String cmd1 = "Command1";
CTBotInlineKeyboard  kbd;
...
kbd.addButton("Act1", cmd1, CTBotKeyboardButtonQuery);

Then, the menu stopped working, because I replaced explicit text parameters with String variables..

Well, the reference states clearly that one passes a STRING as parameter:

bool CTBotInlineKeyboard::addButton(String text, String command, CTBotInlineKeyboardButtonType buttonType)

But if I pass a String as a parameter, the menu does not mount, I need to pass a text (as the example above) for it to work. This way I get duplicated strings in the code.

Is this an implementation issue or documentation issue?

Best regards Lissandro

PS.: I changed kbd.addButton("Act1", cmd1, CTBotKeyboardButtonQuery); to kbd.addButton("Act1", cmd1.c_str(), CTBotKeyboardButtonQuery); then it worked. I presume your code is working with something like that instead (did not check first parameter)

"bool CTBotInlineKeyboard::addButton(String text, C-style string command, CTBotInlineKeyboardButtonType buttonType)"

shurillu commented 3 years ago

Hello Lissandro,

it's a very weird behavior! The two parameters are declared as String, so they must accept a string as input. BTW I try to modify the inline keyboard example just doing these simply changes:

//#define LIGHT_ON_CALLBACK  "lightON"  // callback data sent when "LIGHT ON" button is pressed
//#define LIGHT_OFF_CALLBACK "lightOFF" // callback data sent when "LIGHT OFF" button is pressed

String LIGHT_ON_CALLBACK  = "lightON";  // callback data sent when "LIGHT ON" button is pressed
String LIGHT_OFF_CALLBACK = "lightOFF"; // callback data sent when "LIGHT OFF" button is pressed

Adding my WiFi credentials and my Telegram Bot Token the example just work.

I tested the code with an ESP8266 (NodeMCU) and the 2.1.3 library version. Are you using the same library version or are you using the v3.0.0 version? Finally I compile&run the example with the ArduinoJson library v5.13.5 and the v6.1.17.

Could you try the example?

Cheers,

Stefano

mad-b commented 3 years ago

Hi. Consider String var = "button". I tried previously as you made here when I pass the String variables the menu does not show on the client i.e. var. If I pass a string literal i.e. "button" then it works. If I take var.c_str() it works. I am using the latest libs. It is working with c_str() though, I will let as this.

shurillu commented 3 years ago

Hi Lissando, finally I solved the riddle. One of the major changes in the v3.0.0 is the use of "C style string" only inside of the library: most of the issues related to random resets are dued to the Stringclass. BTW, for backward compatibility, there are stub member functions that takes Stringparameters as input but inside calls the "C style string" versions. So, the addButton member function exist in two form:

bool addButton(const String& text, const String& command, CTBotInlineKeyboardButtonType buttonType);
bool addButton(const char* text, const char* command, CTBotInlineKeyboardButtonType buttonType);

When you use only Stringtype parameters, will be executed the first, when you use only "C style string", will be executed the second one.

By the other hand, when you mix the two types of string, there are two possibilities:

  1. First parameter String, second parameter "C style string": in this case, will be executed the first one and the second parameter will be converter in Stringby the constructor.
  2. First parameter "C style string", second parameter String: in this case will be executed the second one and you must force the string conversion of the second parameter by using the Stringmember function c_str(), because the "C style string" don't have a constructor (it is just a pointer, not a class).

So this is the explanation of the weird behavior.

Cheers,

Stefano