bertmelis / espMqttClient

MQTT 3.1.1 client library for the Espressif devices ESP8266 and ESP32 on the Arduino framework.
https://www.emelis.net/espMqttClient/
MIT License
100 stars 21 forks source link

Compiler error using example simpleAsync-esp32.ino.ino #92

Closed GnomiBerlin closed 1 year ago

GnomiBerlin commented 1 year ago

using Arduino IDE 1.8.19 with "AI Thinker ESP32-CAM" board.

In file included from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/MqttClient.h:22:0,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/MqttClientSetup.h:14,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/espMqttClientAsync.h:18,
                 from D:\SYS_ext\Joerg\Documents\Arduino\simpleAsync-esp32.ino\simpleAsync-esp32.ino.ino:3:
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/Packets/Packet.h: In constructor 'espMqttClientInternals::Packet::Packet(espMqttClientTypes::Error&, uint16_t, const char*, uint8_t, const char*, uint8_t, Args&& ...)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/Packets/Packet.h:100:43: error: expected ',' before ')' token
     static_assert(sizeof...(Args) % 2 == 0);
                                           ^
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-1.4.2\src/Packets/Packet.h:100:43: error: expected string-literal before ')' token

Thanks

Joerg

bertmelis commented 1 year ago

Should be fixed in the main branch. I'll create a release soon.

GnomiBerlin commented 1 year ago

@bertmelis : my results with new main branch and compiling "simpleAsync-esp32.ino.ino" again:

D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp: In constructor 'espMqttClientInternals::Packet::Packet(espMqttClientTypes::Error&, uint16_t, const char*, espMqttClientTypes::PayloadCallback, size_t, uint8_t, bool)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp:218:96: error: 'EMC_RX_BUFFER_SIZE' was not declared in this scope
   if (!_allocate(remainingLength - payloadLength + std::min(payloadLength, static_cast<size_t>(EMC_RX_BUFFER_SIZE)))) {
                                                                                                ^
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp: In member function 'bool espMqttClientInternals::Packet::_allocate(size_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp:304:31: error: 'EMC_MIN_FREE_MEMORY' was not declared in this scope
   if (EMC_GET_FREE_MEMORY() < EMC_MIN_FREE_MEMORY) {
                               ^
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp: In member function 'size_t espMqttClientInternals::Packet::_chunkedAvailable(size_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp:414:87: error: 'EMC_TX_BUFFER_SIZE' was not declared in this scope
       size_t copied = _getPayload(&_data[_payloadIndex], std::min(static_cast<size_t>(EMC_TX_BUFFER_SIZE), _size - _payloadStartIndex), index);
                                                                                       ^
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Packets\Packet.cpp:422:85: error: 'EMC_TX_BUFFER_SIZE' was not declared in this scope
     size_t copied = _getPayload(&_data[_payloadIndex], std::min(static_cast<size_t>(EMC_TX_BUFFER_SIZE), _size - _payloadStartIndex), index);
bertmelis commented 1 year ago

Are you using Arduino IDE? Is this the only error you have?

Automatic testing uses Platformio and apparently their toolchain finds the included file (the #include does have an error).

bertmelis commented 1 year ago

Should at least fix the error you mention.

I added testing with Arduino IDE and your error didn't pop up though...

GnomiBerlin commented 1 year ago

Thanks @bertmelis I did not spend much time now, just compiling the example again, using Arduino IDE 1.8.19:

D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp: In member function 'virtual bool espMqttClientInternals::ClientSync::connect(IPAddress, uint16_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp:29:71: error: no matching function for call to 'WiFiClient::setSocketOption(int, int, int*, unsigned int)'
     client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
                                                                       ^
In file included from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.h:13:0,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp:11:
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note: candidate: int WiFiClient::setSocketOption(int, char*, size_t)
     int setSocketOption(int option, char* value, size_t len);
         ^
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note:   candidate expects 3 arguments, 4 provided
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp: In member function 'virtual bool espMqttClientInternals::ClientSync::connect(const char*, uint16_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp:43:71: error: no matching function for call to 'WiFiClient::setSocketOption(int, int, int*, unsigned int)'
     client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
                                                                       ^
In file included from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.h:13:0,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSync.cpp:11:
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note: candidate: int WiFiClient::setSocketOption(int, char*, size_t)
     int setSocketOption(int option, char* value, size_t len);
         ^
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note:   candidate expects 3 arguments, 4 provided
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp: In member function 'virtual bool espMqttClientInternals::ClientSecureSync::connect(IPAddress, uint16_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp:29:71: error: no matching function for call to 'WiFiClientSecure::setSocketOption(int, int, int*, unsigned int)'
     client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
                                                                       ^
In file included from C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFi.h:37:0,
                 from C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFiClientSecure\src/WiFiClientSecure.h:25,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.h:13,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp:11:
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note: candidate: int WiFiClient::setSocketOption(int, char*, size_t)
     int setSocketOption(int option, char* value, size_t len);
         ^
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note:   candidate expects 3 arguments, 4 provided
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp: In member function 'virtual bool espMqttClientInternals::ClientSecureSync::connect(const char*, uint16_t)':
D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp:43:71: error: no matching function for call to 'WiFiClientSecure::setSocketOption(int, int, int*, unsigned int)'
     client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
                                                                       ^
In file included from C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFi.h:37:0,
                 from C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFiClientSecure\src/WiFiClientSecure.h:25,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.h:13,
                 from D:\SYS_ext\Joerg\Documents\Arduino\libraries\espMqttClient-main\src\Transport\ClientSecureSync.cpp:11:
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note: candidate: int WiFiClient::setSocketOption(int, char*, size_t)
     int setSocketOption(int option, char* value, size_t len);
         ^
C:\Users\Joerg\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi\src/WiFiClient.h:88:9: note:   candidate expects 3 arguments, 4 provided

Sorry, for these results.

bertmelis commented 1 year ago

Don't be sorry. But you do have to update your Arduino core. setSocketOption has been added months ago. (december 2022)

Note: update the Arduino core for ESP32, not the Arduino IDE: https://support.arduino.cc/hc/en-us/articles/4404691106066-How-to-update-the-core-of-your-Arduino-Board

GnomiBerlin commented 1 year ago

I thought this is the newest for my ESP32-CAM AI Thinker Board image

I use the folowing entry in the config for the board manager: https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json,

bertmelis commented 1 year ago

They are at v2.0.9 already: https://github.com/espressif/arduino-esp32/releases

I believe you should use this package link: https://espressif.github.io/arduino-esp32/package_esp32_index.json

GnomiBerlin commented 1 year ago

I really missed to use another link for the boards package. THANKS A LOT!

Due to the updates, I had also to update the esp32-CAM camera routines. Now all works also with bigger jpeg pictures using your asyncMqtt version.

So the merge for my problems should be o.k.

bertmelis commented 1 year ago

Happy to hear. I release a new version with some improvements.

I haven't used the big payloads myself as it's somewhere below on the to do list. Please report any issues.

GnomiBerlin commented 1 year ago

Hi, as you asked for any issues/observations. When using pubsubclient the MQTT transfer of the big pictured ( 70k-120 kB) is much faster than with your routines. using

packetIdPubTemp = mqttClient.publish( topic_PUBLISH, 0, false, fb->buf, length );
    if( !packetIdPubTemp  )
    {
    Serial.print( "Sending Failed! err: ");
    Serial.println( String( packetIdPubTemp ) );
    }
    else
    {
    Serial.print("MQTT Publish succesful: ");
    Serial.println( String( packetIdPubTemp ) );
    }

the "MQTT Publish succesful" debug message comes fast, but the picture in NodeRed only receives after 7 seeconds, where with pubsubclient it was only costing less than a second.

I did not anayze more, as I also have troubles with the elegantOTA function now.

bertmelis commented 1 year ago

Both libraries work differently. This lib has a worker task so the esp32 needs to switch tasks which takes some time. Furthermore, pubsubclient blocks while sending whereas this library doesn't. So in between sending chunks of your image, it is possible to run other code as well. This also contributes to the lost time.

You can emulate the behaviour of Pubsubclient though. You'll have to disable the internal task and call mqttClient.loop() in your Arduino loop. After sending the image, you can block and call loop() until done. For this you'll need to send with qos 1 or 2.

espMqttClient mqttClient(espMqttClientTypes::UseInternalTask::NO);
bool sendPictureFlag = false;
uint16_t packetIdToConfirm = 0;

void mqttClient.onPublish(uint16_t packetId) {
  if (packetId == packetIdToConfirm) {
    sendPictureFlag = false;
  }
}

size_t fetchPicture(uint8_t* dest, size_t len, size_t index) {
  // get picture data
}

void sendPicture() {
  packetIdToConfirm  = mqttCient.publish("topic/picture", 1, false, fetchPicture, 120000);
  if (packetIdToConfirm > 0) {
    sendPictureFlag = true;
  }
}

void setup() {
  mqttClient.onPublish(onPublish);
}

void loop() {
  while (sendPictureFlag) {
    mqttClient.loop();
  }
  mqttClient.loop();
}

I hope you get the point?

GnomiBerlin commented 1 year ago

Thanks again for the fast and detailled explanation. I made the adapted changes and it was really as fast as pubsubclient. I did not expect, that there is such a difference, when this picture sending is mostly the only task of the ESP at this time.

So there is no problem on my side and I can use your version. The delay is no problem in my application and I can concentrate on my OTA problem again.

But I have not fully understood one thing: your project is async MQTT - whai is the difference of using

#include <espMqttClientAsync.h>
...
espMqttClientAsync mqttClient;
...
#include <espMqttClient.h>
...
espMqttClient mqttClient(espMqttClientTypes::UseInternalTask::YES);
...

Sorry, if I should get it from your good documentation.

PS: I think there was a little error in your hints:

void mqttClient.onPublish(uint16_t packetId) {
   ....
}

should be

void onPublish(uint16_t packetId) {
  .....
}
bertmelis commented 1 year ago

But I have not fully understood one thing: your project is async MQTT - whai is the difference of using...

This library can use different underlying transport libraries. By separating MQTT from the transport, it should be straightforward to implement other transport methods, like websockets. The lib has a transport method for Linux for example, used in automated testing.

espMqttClientAsync

Uses AsyncTCP or ESPAsyncTCP. It should be faster and wastes less cpu cycles. It also doesn't block when connecting. The async version works with callback functions that run as soon as there is incoming traffic. So espMqttClientAsync doesn't need to check anything on a regular basis: it receives a signal when it has to do something. Out of the box, there is no TLS support for async (it can be done of course, the library just hasn't implemented this).

espMqttClient

Uses (the built-in in the Arduino framework) WifiClient or WiFiClientSecure. This is also the transport library that pubsubclient uses. It works using polling: every time you call loop() or every time the internal task runs, it checks for incoming or outgoing data. If there is none, it can be considered as a wasted effort. The major drawback is however that program halts when making the TCP connection, blocking any other code from running. When you call loop() using the internal task or your own separate task, you might not notice this. But depending on your program, it might be unacceptable. (on an ESP8266 for example). Then you can switch to the async version.