ThingsBoard Client SDK 0.16.0
Client SDK to connect with ThingsBoard IoT Platform from IoT devices (Arduino, Espressif, etc.)
Loading...
Searching...
No Matches
ThingsBoardHttp.h
Go to the documentation of this file.
1#ifndef ThingsBoard_Http_h
2#define ThingsBoard_Http_h
3
4// Local includes.
5#include "Constants.h"
6#include "Telemetry.h"
7#include "Helper.h"
8#include "IHTTP_Client.h"
9#include "DefaultLogger.h"
10
11
12// HTTP topics.
13char constexpr HTTP_TELEMETRY_TOPIC[] = "/api/v1/%s/telemetry";
14char constexpr HTTP_ATTRIBUTES_TOPIC[] = "/api/v1/%s/attributes";
15char constexpr HTTP_POST_PATH[] = "application/json";
18
19// Log messages.
20char constexpr POST[] = "POST";
21char constexpr GET[] = "GET";
22char constexpr HTTP_FAILED[] = "(%s) failed HTTP response (%d)";
23
24
30template<typename Logger = DefaultLogger>
32 public:
54 ThingsBoardHttpSized(IHTTP_Client & client, char const * access_token, char const * host, uint16_t port = 80U, bool keep_alive = true, size_t const & max_stack_size = DEFAULT_MAX_STACK_SIZE)
55 : m_client(client)
56 , m_max_stack(max_stack_size)
57 , m_token(access_token)
58 {
59 m_client.set_keep_alive(keep_alive);
60 if (m_client.connect(host, port) != 0) {
61 Logger::printfln(CONNECT_FAILED);
62 }
63 }
64
72 void Set_Maximum_Stack_Size(size_t const & max_stack_size) {
73 m_max_stack = max_stack_size;
74 }
75
78 size_t const & Get_Maximum_Stack_Size() const {
79 return m_max_stack;
80 }
81
89 bool Send_Json(char const * topic, JsonDocument const & source) {
90 // Check if allocating needed memory failed when trying to create the JsonDocument,
91 // if it did the isNull() method will return true. See https://arduinojson.org/v6/api/jsonvariant/isnull/ for more information
92 if (source.isNull()) {
93 Logger::printfln(UNABLE_TO_ALLOCATE_JSON);
94 return false;
95 }
96 // Check if inserting any of the internal values failed because the JsonDocument was too small,
97 // if it did the overflowed() method will return true. See https://arduinojson.org/v6/api/jsondocument/overflowed/ for more information
98 if (source.overflowed()) {
99 Logger::printfln(JSON_SIZE_TO_SMALL);
100 return false;
101 }
102 bool result = false;
103
104 size_t const json_size = Helper::Measure_Json(source);
105 if (json_size > Get_Maximum_Stack_Size()) {
106 char * json = new char[json_size]();
107 if (serializeJson(source, json, json_size) < json_size - 1) {
108 Logger::printfln(UNABLE_TO_SERIALIZE_JSON);
109 }
110 else {
111 result = Send_Json_String(topic, json);
112 }
113 delete[] json;
114 json = nullptr;
115 }
116 else {
117 char json[json_size] = {};
118 if (serializeJson(source, json, json_size) < json_size - 1) {
119 Logger::printfln(UNABLE_TO_SERIALIZE_JSON);
120 return result;
121 }
122 result = Send_Json_String(topic, json);
123 }
124 return result;
125 }
126
133 bool Send_Json_String(char const * topic, char const * json) {
134 if (json == nullptr || m_token == nullptr) {
135 return false;
136 }
137
138 char path[Helper::Calculate_Print_Size(topic, m_token)] = {};
139 (void)snprintf(path, sizeof(path), topic, m_token);
140 return Post_Message(path, json);
141 }
142
143 //----------------------------------------------------------------------------
144 // Telemetry API
145
153 template<typename T>
154 bool Send_Telemetry_Data(char const * key, T const & value) {
155 return Send_Key_Value_Pair(key, value);
156 }
157
169#if THINGSBOARD_ENABLE_DYNAMIC
170 template<typename InputIterator>
171#else
172 template<size_t MaxKeyValuePairAmount, typename InputIterator>
173#endif // THINGSBOARD_ENABLE_DYNAMIC
174 bool Send_Telemetry(InputIterator const & first, InputIterator const & last) {
175#if THINGSBOARD_ENABLE_DYNAMIC
176 return Send_Data_Array(first, last, true);
177#else
178 return Send_Data_Array<MaxKeyValuePairAmount>(first, last, true);
179#endif // THINGSBOARD_ENABLE_DYNAMIC
180 }
181
187 bool Send_Telemetry_String(char const * json) {
189 }
190
196 bool Send_Telemetry_Json(JsonDocument const & source) {
197 return Send_Json(HTTP_TELEMETRY_TOPIC, source);
198 }
199
200 //----------------------------------------------------------------------------
201 // Attribute API
202
210 template<typename T>
211 bool Send_Attribute_Data(char const * key, T const & value) {
212 return Send_Key_Value_Pair(key, value, false);
213 }
214
226#if THINGSBOARD_ENABLE_DYNAMIC
227 template<typename InputIterator>
228#else
231 template<size_t MaxKeyValuePairAmount, typename InputIterator>
232#endif // THINGSBOARD_ENABLE_DYNAMIC
233 bool Send_Attributes(InputIterator const & first, InputIterator const & last) {
234#if THINGSBOARD_ENABLE_DYNAMIC
235 return Send_Data_Array(first, last, false);
236#else
237 return Send_Data_Array<MaxKeyValuePairAmount>(first, last, false);
238#endif // THINGSBOARD_ENABLE_DYNAMIC
239 }
240
246 bool Send_Attribute_String(char const * json) {
248 }
249
255 bool Send_Attribute_Json(JsonDocument const & source) {
256 return Send_Json(HTTP_ATTRIBUTES_TOPIC, source);
257 }
258
259 //----------------------------------------------------------------------------
260 // Generic HTTP API
261
267#if THINGSBOARD_ENABLE_STL
268 bool Send_Get_Request(char const * path, std::string & response) {
269#else
270 bool Send_Get_Request(char const * path, String& response) {
271#endif // THINGSBOARD_ENABLE_STL
272 return Get_Message(path, response);
273 }
274
279 bool Send_Post_Request(char const * path, char const * json) {
280 return Post_Message(path, json);
281 }
282
283 private:
285 void Clear_Connection() {
286 m_client.stop();
287 }
288
295 bool Post_Message(char const * path, char const * json) {
296 bool success = m_client.post(path, HTTP_POST_PATH, json) == 0;
297 int const status = m_client.get_response_status_code();
298
299 if (!success || status < HTTP_RESPONSE_SUCCESS_RANGE_START || status > HTTP_RESPONSE_SUCCESS_RANGE_END) {
300 Logger::printfln(HTTP_FAILED, POST, status);
301 success = false;
302 }
303
304 Clear_Connection();
305 return success;
306 }
307
313#if THINGSBOARD_ENABLE_STL
314 bool Get_Message(char const * path, std::string& response) {
315#else
316 bool Get_Message(char const * path, String& response) {
317#endif // THINGSBOARD_ENABLE_STL
318 bool success = m_client.get(path);
319 int const status = m_client.get_response_status_code();
320
321 if (!success || status < HTTP_RESPONSE_SUCCESS_RANGE_START || status > HTTP_RESPONSE_SUCCESS_RANGE_END) {
322 Logger::printfln(HTTP_FAILED, GET, status);
323 success = false;
324 goto cleanup;
325 }
326 response = m_client.get_response_body();
327
328 cleanup:
329 Clear_Connection();
330 return success;
331 }
332
344#if THINGSBOARD_ENABLE_DYNAMIC
345 template<typename InputIterator>
346#else
347 template<size_t MaxKeyValuePairAmount, typename InputIterator>
348#endif // THINGSBOARD_ENABLE_DYNAMIC
349 bool Send_Data_Array(InputIterator const & first, InputIterator const & last, bool telemetry) {
350 auto const size = Helper::distance(first, last);
351#if THINGSBOARD_ENABLE_DYNAMIC
352 TBJsonDocument json_buffer(JSON_OBJECT_SIZE(size));
353#else
354 if (size > MaxKeyValuePairAmount) {
355 Logger::printfln(TOO_MANY_JSON_FIELDS, size, "MaxKeyValuePairAmount", MaxKeyValuePairAmount);
356 return false;
357 }
358 StaticJsonDocument<JSON_OBJECT_SIZE(MaxKeyValuePairAmount)> json_buffer;
359#endif // THINGSBOARD_ENABLE_DYNAMIC
360
361#if THINGSBOARD_ENABLE_STL
362 if (std::any_of(first, last, [&json_buffer](Telemetry const & data) { return !data.SerializeKeyValue(json_buffer); })) {
363 Logger::printfln(UNABLE_TO_SERIALIZE);
364 return false;
365 }
366#else
367 for (auto it = first; it != last; ++it) {
368 auto const & data = *it;
369 if (!data.SerializeKeyValue(json_buffer)) {
370 Logger::printfln(UNABLE_TO_SERIALIZE);
371 return false;
372 }
373 }
374#endif // THINGSBOARD_ENABLE_STL
375 return telemetry ? Send_Telemetry_Json(json_buffer) : Send_Attribute_Json(json_buffer);
376 }
377
384 template<typename T>
385 bool Send_Key_Value_Pair(char const * key, T value, bool telemetry = true) {
386 Telemetry const t(key, value);
387 if (t.IsEmpty()) {
388 // Message is ignored and not sent at all.
389 return false;
390 }
391
392 StaticJsonDocument<JSON_OBJECT_SIZE(1)> json_buffer;
393 if (!t.SerializeKeyValue(json_buffer)) {
394 Logger::printfln(UNABLE_TO_SERIALIZE);
395 return false;
396 }
397 return telemetry ? Send_Telemetry_Json(json_buffer) : Send_Attribute_Json(json_buffer);
398 }
399
400 IHTTP_Client& m_client = {}; // HttpClient instance
401 size_t m_max_stack = {}; // Maximum stack size we allocate at once on the stack.
402 char const *m_token = {}; // Access token used to connect with
403};
404
406
407#endif // ThingsBoard_Http_h
char constexpr TOO_MANY_JSON_FIELDS[]
Definition: Constants.h:32
char constexpr JSON_SIZE_TO_SMALL[]
Definition: Constants.h:38
char constexpr UNABLE_TO_ALLOCATE_JSON[]
Definition: Constants.h:37
char constexpr UNABLE_TO_SERIALIZE_JSON[]
Definition: Constants.h:36
char constexpr UNABLE_TO_SERIALIZE[]
Definition: Constants.h:34
uint16_t constexpr DEFAULT_MAX_STACK_SIZE
Definition: Constants.h:21
char constexpr CONNECT_FAILED[]
Definition: Constants.h:35
char constexpr HTTP_FAILED[]
Definition: ThingsBoardHttp.h:22
char constexpr GET[]
Definition: ThingsBoardHttp.h:21
char constexpr HTTP_POST_PATH[]
Definition: ThingsBoardHttp.h:15
char constexpr HTTP_TELEMETRY_TOPIC[]
Definition: ThingsBoardHttp.h:13
int constexpr HTTP_RESPONSE_SUCCESS_RANGE_END
Definition: ThingsBoardHttp.h:17
char constexpr POST[]
Definition: ThingsBoardHttp.h:20
char constexpr HTTP_ATTRIBUTES_TOPIC[]
Definition: ThingsBoardHttp.h:14
int constexpr HTTP_RESPONSE_SUCCESS_RANGE_START
Definition: ThingsBoardHttp.h:16
static size_t Calculate_Print_Size(char const *format, Args const &... args)
Returns the total amount of bytes needed to store the formatted string with null termination,...
Definition: Helper.h:32
static size_t distance(InputIterator const &first, InputIterator const &last)
Calculates the distance between two iterators.
Definition: Helper.h:85
static size_t Measure_Json(TSource const &source)
Calculates the total size of the string the serializeJson method would produce including the null end...
Definition: Helper.h:73
HTTP Client interface that contains the method that a class that can be used to send and receive data...
Definition: IHTTP_Client.h:22
virtual int post(char const *url_path, char const *content_type, char const *request_body)=0
Connects to the server and sends a POST request with a body and content type.
virtual void stop()=0
Disconnects the given device from the current host and clears about any remaining bytes still in the ...
virtual int get(const char *url_path)=0
Connects to the server and sends a GET request.
virtual std::string get_response_body()=0
Returns the response body of a previously sent message as a string object, skips any response headers...
virtual void set_keep_alive(bool keep_alive)=0
Sets whether to close the HTTP connection for every single request and reconnect once a new request i...
virtual int connect(char const *host, uint16_t port)=0
Connects to the given server instance over the defined port.
virtual int get_response_status_code()=0
Gets the HTTP status code contained in the server response.
Telemetry record class, allows to store different data using a common interface.
Definition: Telemetry.h:16
bool SerializeKeyValue(TSource &source) const
Serializes a key-value pair or only a value, depending on the constructor used.
Definition: Telemetry.h:82
Wrapper around the ArduinoHttpClient to allow connecting and sending / retrieving data from ThingsBoa...
Definition: ThingsBoardHttp.h:31
bool Send_Attribute_Data(char const *key, T const &value)
Sends the given key-value pair as attribute data. See https://thingsboard.io/docs/user-guide/attribut...
Definition: ThingsBoardHttp.h:211
bool Send_Json(char const *topic, JsonDocument const &source)
Sends key-value pairs from the given JsonDocument over the given topic.
Definition: ThingsBoardHttp.h:89
bool Send_Json_String(char const *topic, char const *json)
Sends key-value pairs from the given json string over the given topic.
Definition: ThingsBoardHttp.h:133
bool Send_Telemetry_Json(JsonDocument const &source)
Send key-value pairs as telemetry data. See https://thingsboard.io/docs/user-guide/telemetry/ for mor...
Definition: ThingsBoardHttp.h:196
size_t const & Get_Maximum_Stack_Size() const
Returns the maximum amount of bytes that we want to allocate on the stack, before the memory is alloc...
Definition: ThingsBoardHttp.h:78
bool Send_Telemetry_Data(char const *key, T const &value)
Sends the given key-value pair as telemetry data. See https://thingsboard.io/docs/user-guide/telemetr...
Definition: ThingsBoardHttp.h:154
bool Send_Post_Request(char const *path, char const *json)
Attempts to send a POST request over HTTP or HTTPS.
Definition: ThingsBoardHttp.h:279
bool Send_Attribute_Json(JsonDocument const &source)
Send key-value pairs as attribute data. See https://thingsboard.io/docs/user-guide/attribute/ for mor...
Definition: ThingsBoardHttp.h:255
bool Send_Attribute_String(char const *json)
Send string containing json as attribute data. See https://thingsboard.io/docs/user-guide/attribute/ ...
Definition: ThingsBoardHttp.h:246
bool Send_Telemetry_String(char const *json)
Send string containing json as telemetry data. See https://thingsboard.io/docs/user-guide/telemetry/ ...
Definition: ThingsBoardHttp.h:187
bool Send_Get_Request(char const *path, std::string &response)
Attempts to send a GET request over HTTP or HTTPS.
Definition: ThingsBoardHttp.h:268
bool Send_Attributes(InputIterator const &first, InputIterator const &last)
Send aggregated key-value pair as attribute data.
Definition: ThingsBoardHttp.h:233
void Set_Maximum_Stack_Size(size_t const &max_stack_size)
Sets the maximum amount of bytes that we want to allocate on the stack, before the memory is allocate...
Definition: ThingsBoardHttp.h:72
ThingsBoardHttpSized(IHTTP_Client &client, char const *access_token, char const *host, uint16_t port=80U, bool keep_alive=true, size_t const &max_stack_size=DEFAULT_MAX_STACK_SIZE)
Constructs a instance with the given network client that should be used to establish the connection t...
Definition: ThingsBoardHttp.h:54
bool Send_Telemetry(InputIterator const &first, InputIterator const &last)
Send aggregated key-value pair as telemetry data.
Definition: ThingsBoardHttp.h:174