Open lenokoe opened 2 weeks ago
Now sure why you are installing MQTTPubSubClient
, doesn't seem like you require that library.
The rest of the libraries seems to be correct, so I'm not sure why it fails when it attempts to initalize an instance of the HttpClient abstract class. The only thing I could imagine is a naming conflict, but I'm not sure either.
Could you attach a simple version of your code? Because with the current information it is not possible to help any further.
Hi @MathewHDYT
My bad, MQTTPubSubClient was my trial and error for this case. The library should not be there.
Below i put my code
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#define THINGSBOARD_ENABLE_PROGMEM 0
#elif defined(ESP32) || defined(RASPBERRYPI_PICO) || defined(RASPBERRYPI_PICO_W)
#include <WiFi.h>
#endif
#ifndef LED_BUILTIN
#define LED_BUILTIN 8
#endif
#include <Arduino_MQTT_Client.h>
#include <Server_Side_RPC.h>
#include <Attribute_Request.h>
#include <Shared_Attribute_Update.h>
#include <ThingsBoard.h>
constexpr char WIFI_SSID[] = "18XXXXXX18";
constexpr char WIFI_PASSWORD[] = "XXXXXXXX";
// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
//
constexpr char TOKEN[] = "keXwLa1xCoFwZXXXXXXX";
// Thingsboard we want to establish a connection too
constexpr char THINGSBOARD_SERVER[] = "demo.thingsboard.io";
// constexpr char THINGSBOARD_SERVER[] = "localhost:8080";
// MQTT port used to communicate with the server, 1883 is the default unencrypted MQTT port.
constexpr uint16_t THINGSBOARD_PORT = 1883U;
// Maximum size packets will ever be sent or received by the underlying MQTT client,
// if the size is to small messages might not be sent or received messages will be discarded
constexpr uint32_t MAX_MESSAGE_SIZE = 1024U;
// Baud rate for the debugging serial connection.
// If the Serial output is mangled, ensure to change the monitor speed accordingly to this variable
constexpr uint32_t SERIAL_DEBUG_BAUD = 115200U;
// Maximum amount of attributs we can request or subscribe, has to be set both in the ThingsBoard template list and Attribute_Request_Callback template list
// and should be the same as the amount of variables in the passed array. If it is less not all variables will be requested or subscribed
constexpr size_t MAX_ATTRIBUTES = 3U;
constexpr uint64_t REQUEST_TIMEOUT_MICROSECONDS = 5000U * 1000U;
// Attribute names for attribute request and attribute updates functionality
constexpr const char BLINKING_INTERVAL_ATTR[] = "blinkingInterval";
constexpr const char LED_MODE_ATTR[] = "ledMode";
constexpr const char LED_STATE_ATTR[] = "ledState";
// Initialize underlying client, used to establish a connection
WiFiClient wifiClient;
// Initalize the Mqtt client instance
Arduino_MQTT_Client mqttClient(wifiClient);
// Initialize used apis
Server_Side_RPC<3U, 5U> rpc;
Attribute_Request<2U, MAX_ATTRIBUTES> attr_request;
Shared_Attribute_Update<3U, MAX_ATTRIBUTES> shared_update;
const std::array<IAPI_Implementation*, 3U> apis = {
&rpc,
&attr_request,
&shared_update
};
// Initialize ThingsBoard instance with the maximum needed buffer size, stack size and the apis we want to use
ThingsBoard tb(mqttClient, MAX_MESSAGE_SIZE, Default_Max_Stack_Size, apis);
// handle led state and mode changes
volatile bool attributesChanged = false;
// LED modes: 0 - continious state, 1 - blinking
volatile int ledMode = 0;
// Current led state
volatile bool ledState = false;
// Settings for interval in blinking mode
constexpr uint16_t BLINKING_INTERVAL_MS_MIN = 10U;
constexpr uint16_t BLINKING_INTERVAL_MS_MAX = 60000U;
volatile uint16_t blinkingInterval = 1000U;
uint32_t previousStateChange;
// For telemetry
constexpr int16_t telemetrySendInterval = 2000U;
uint32_t previousDataSend;
// List of shared attributes for subscribing to their updates
constexpr std::array<const char *, 2U> SHARED_ATTRIBUTES_LIST = {
LED_STATE_ATTR,
BLINKING_INTERVAL_ATTR
};
// List of client attributes for requesting them (Using to initialize device states)
constexpr std::array<const char *, 1U> CLIENT_ATTRIBUTES_LIST = {
LED_MODE_ATTR
};
/// @brief Initalizes WiFi connection,
// will endlessly delay until a connection has been successfully established
void InitWiFi() {
Serial.println("Connecting to AP ...");
// Attempting to establish a connection to the given WiFi network
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
// Delay 500ms until a connection has been succesfully established
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
/// @brief Reconnects the WiFi uses InitWiFi if the connection has been removed
/// @return Returns true as soon as a connection has been established again
const bool reconnect() {
// Check to ensure we aren't connected yet
const wl_status_t status = WiFi.status();
if (status == WL_CONNECTED) {
return true;
}
// If we aren't establish a new connection to the given WiFi network
InitWiFi();
return true;
}
/// @brief Processes function for RPC call "setLedMode"
/// RPC_Data is a JSON variant, that can be queried using operator[]
/// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
/// @param data Data containing the rpc data that was called and its current value
void processSetLedMode(const JsonVariantConst &data, JsonDocument &response) {
Serial.println("Received the set led state RPC method");
// Process data
int new_mode = data;
Serial.print("Mode to change: ");
Serial.println(new_mode);
StaticJsonDocument<1> response_doc;
if (new_mode != 0 && new_mode != 1) {
response_doc["error"] = "Unknown mode!";
response.set(response_doc);
return;
}
ledMode = new_mode;
attributesChanged = true;
// Returning current mode
response_doc["newMode"] = (int)ledMode;
response.set(response_doc);
}
// Optional, keep subscribed shared attributes empty instead,
// and the callback will be called for every shared attribute changed on the device,
// instead of only the one that were entered instead
const std::array<RPC_Callback, 1U> callbacks = {
RPC_Callback{ "setLedMode", processSetLedMode }
};
/// @brief Update callback that will be called as soon as one of the provided shared attributes changes value,
/// if none are provided we subscribe to any shared attribute change instead
/// @param data Data containing the shared attributes that were changed and their current value
void processSharedAttributes(const JsonObjectConst &data) {
for (auto it = data.begin(); it != data.end(); ++it) {
if (strcmp(it->key().c_str(), BLINKING_INTERVAL_ATTR) == 0) {
const uint16_t new_interval = it->value().as<uint16_t>();
if (new_interval >= BLINKING_INTERVAL_MS_MIN && new_interval <= BLINKING_INTERVAL_MS_MAX) {
blinkingInterval = new_interval;
Serial.print("Blinking interval is set to: ");
Serial.println(new_interval);
}
} else if (strcmp(it->key().c_str(), LED_STATE_ATTR) == 0) {
ledState = it->value().as<bool>();
if (LED_BUILTIN != 99) {
digitalWrite(LED_BUILTIN, ledState);
}
Serial.print("LED state is set to: ");
Serial.println(ledState);
}
}
attributesChanged = true;
}
void processClientAttributes(const JsonObjectConst &data) {
for (auto it = data.begin(); it != data.end(); ++it) {
if (strcmp(it->key().c_str(), LED_MODE_ATTR) == 0) {
const uint16_t new_mode = it->value().as<uint16_t>();
ledMode = new_mode;
}
}
}
// Attribute request did not receive a response in the expected amount of microseconds
void requestTimedOut() {
Serial.printf("Attribute request timed out did not receive a response in (%llu) microseconds. Ensure client is connected to the MQTT broker and that the keys actually exist on the target device\n", REQUEST_TIMEOUT_MICROSECONDS);
}
const Shared_Attribute_Callback<MAX_ATTRIBUTES> attributes_callback(&processSharedAttributes, SHARED_ATTRIBUTES_LIST.cbegin(), SHARED_ATTRIBUTES_LIST.cend());
const Attribute_Request_Callback<MAX_ATTRIBUTES> attribute_shared_request_callback(&processSharedAttributes, REQUEST_TIMEOUT_MICROSECONDS, &requestTimedOut, SHARED_ATTRIBUTES_LIST);
const Attribute_Request_Callback<MAX_ATTRIBUTES> attribute_client_request_callback(&processClientAttributes, REQUEST_TIMEOUT_MICROSECONDS, &requestTimedOut, CLIENT_ATTRIBUTES_LIST);
void setup() {
// Initialize serial connection for debugging
Serial.begin(SERIAL_DEBUG_BAUD);
if (LED_BUILTIN != 99) {
pinMode(LED_BUILTIN, OUTPUT);
}
delay(1000);
InitWiFi();
}
void loop() {
delay(10);
if (!reconnect()) {
return;
}
if (!tb.connected()) {
// Connect to the ThingsBoard
Serial.print("Connecting to: ");
Serial.print(THINGSBOARD_SERVER);
Serial.print(" with token ");
Serial.println(TOKEN);
if (!tb.connect(THINGSBOARD_SERVER, TOKEN, THINGSBOARD_PORT)) {
Serial.println("Failed to connect");
return;
}
// Sending a MAC address as an attribute
tb.sendAttributeData("macAddress", WiFi.macAddress().c_str());
Serial.println("Subscribing for RPC...");
// Perform a subscription. All consequent data processing will happen in
// processSetLedState() and processSetLedMode() functions,
// as denoted by callbacks array.
if (!rpc.RPC_Subscribe(callbacks.cbegin(), callbacks.cend())) {
Serial.println("Failed to subscribe for RPC");
return;
}
if (!shared_update.Shared_Attributes_Subscribe(attributes_callback)) {
Serial.println("Failed to subscribe for shared attribute updates");
return;
}
Serial.println("Subscribe done");
// Request current states of shared attributes
if (!attr_request.Shared_Attributes_Request(attribute_shared_request_callback)) {
Serial.println("Failed to request for shared attributes");
return;
}
// Request current states of client attributes
if (!attr_request.Client_Attributes_Request(attribute_client_request_callback)) {
Serial.println("Failed to request for client attributes");
return;
}
}
if (attributesChanged) {
attributesChanged = false;
if (ledMode == 0) {
previousStateChange = millis();
}
tb.sendTelemetryData(LED_MODE_ATTR, ledMode);
tb.sendTelemetryData(LED_STATE_ATTR, ledState);
tb.sendAttributeData(LED_MODE_ATTR, ledMode);
tb.sendAttributeData(LED_STATE_ATTR, ledState);
}
if (ledMode == 1 && millis() - previousStateChange > blinkingInterval) {
previousStateChange = millis();
ledState = !ledState;
tb.sendTelemetryData(LED_STATE_ATTR, ledState);
tb.sendAttributeData(LED_STATE_ATTR, ledState);
if (LED_BUILTIN == 99) {
Serial.print("LED state changed to: ");
Serial.println(ledState);
} else {
digitalWrite(LED_BUILTIN, ledState);
}
}
// Sending telemetry every telemetrySendInterval time
if (millis() - previousDataSend > telemetrySendInterval) {
previousDataSend = millis();
tb.sendTelemetryData("temperature", random(10, 20));
tb.sendAttributeData("rssi", WiFi.RSSI());
tb.sendAttributeData("channel", WiFi.channel());
tb.sendAttributeData("bssid", WiFi.BSSIDstr().c_str());
tb.sendAttributeData("localIp", WiFi.localIP().toString().c_str());
tb.sendAttributeData("ssid", WiFi.SSID().c_str());
}
tb.loop();
}
In file included from c:\Users\XXXXX\Documents\Arduino\libraries\ThingsBoard\src\Arduino_HTTP_Client.cpp:2:
c:\Users\XXXXX\Documents\Arduino\libraries\ThingsBoard\src\Arduino_HTTP_Client.h:46:16: error: cannot declare field 'Arduino_HTTP_Client::m_http_client' to be of abstract type 'HttpClient'
46 | HttpClient m_http_client; // Underlying HTTP client instance used to send data
| ^~~~~~~~~~~~~
In file included from c:\Users\XXXXX\Documents\Arduino\libraries\ArduinoHttpClient\src/ArduinoHttpClient.h:8,
from c:\Users\XXXXX\Documents\Arduino\libraries\ThingsBoard\src\Arduino_HTTP_Client.h:10:
c:\Users\XXXXX\Documents\Arduino\libraries\ArduinoHttpClient\src/HttpClient.h:39:7: note: because the following virtual functions are pure within 'HttpClient':
39 | class HttpClient : public Client
| ^~~~~~~~~~
In file included from C:\Users\XXXXX\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.0-RC1\cores\esp32/Arduino.h:197,
from c:\Users\XXXXX\Documents\Arduino\libraries\ArduinoHttpClient\src/HttpClient.h:8:
C:\Users\XXXXX\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.0-RC1\cores\esp32/Client.h:29:15: note: 'virtual int Client::connect(IPAddress, uint16_t, int32_t)'
29 | virtual int connect(IPAddress ip, uint16_t port, int32_t timeout) = 0;
| ^~~~~~~
C:\Users\XXXXX\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.0-RC1\cores\esp32/Client.h:31:15: note: 'virtual int Client::connect(const char*, uint16_t, int32_t)'
31 | virtual int connect(const char *host, uint16_t port, int32_t timeout) = 0;
| ^~~~~~~
exit status 1
Compilation error: exit status 1
Thanks for the help.
Interesting it seems that the HttpClient is not up to date with the interface. The underlying client interface has an additional method that is pure virtual, meaning it has no implementation and need to be implemented by the abstract class.
And that implementation is not done by the HttpClient causing the aformentioned compilation issues. To fix that could you go into the HttpClient and write an implementation for the int connect(const char *host, uint16_t port, int32_t timeout);
method.
If that fixed your issue you would probably need to forward this issue in the GitHub issues of the ArduinoHttpClient instead.
Noted. Thanks for the help but I think I will try another tool first before continuing with thingsboard... in search for my optimal setting prototype :)
Hi, I am absolutely newbie in this field can trying to get a grasp about thingsboard. I made several sensors connected using my arduino ide 2.3.3. Currently I am trying to get those data into a dashboard, which i pick thingsboard. I already followed instructions from https://components.espressif.com/components/thingsboard/thingsboard/versions/0.14.0
I even copy pasted the code there and change the access accordingly. but i still get this error
cannot declare field 'Arduino_HTTP_Client::m_http_client' to be of abstract type 'HttpClient'
I found in issues no 17, there are similar case but it seems that those are quite old issues and not related anymore. Can anyone please help me with this issue ?
This is what i installed in arduino IDE 2.3.3: