1#ifndef OTA_Firmware_Update_h
2#define OTA_Firmware_Update_h
13char constexpr NO_FW_REQUEST_RESPONSE[] =
"Did not receive requested shared attribute firmware keys. Ensure keys exist and device is connected";
33char constexpr NO_FW[] =
"Missing shared attribute firmware keys. Ensure you assigned an OTA update with binary";
34char constexpr EMPTY_FW[] =
"Received shared attribute firmware keys were NULL";
35char constexpr FW_NOT_FOR_US[] =
"Received firmware title (%s) is different and not meant for this device (%s)";
37char constexpr NOT_ENOUGH_RAM[] =
"Temporary allocating more internal client buffer failed, decrease OTA chunk size or decrease overall heap usage";
38char constexpr RESETTING_FAILED[] =
"Preparing for OTA firmware updates failed, attributes might be NULL";
39#if THINGSBOARD_ENABLE_DEBUG
40char constexpr PAGE_BREAK[] =
"=================================";
41char constexpr NEW_FW[] =
"A new Firmware is available:";
42char constexpr FROM_TOO[] =
"(%s) => (%s)";
43char constexpr DOWNLOADING_FW[] =
"Attempting to download over MQTT...";
50template <
typename Logger = DefaultLogger>
52#if THINGSBOARD_ENABLE_DYNAMIC
67 : m_subscribe_api_callback()
68 , m_send_json_callback()
69 , m_send_json_string_callback()
70 , m_subscribe_topic_callback()
71 , m_unsubscribe_topic_callback()
72 , m_get_receive_size_callback()
73 , m_get_send_size_callback()
74 , m_set_buffer_size_callback()
75 , m_get_request_id_callback()
77 , m_previous_buffer_size(0U)
78 , m_changed_buffer_size(false)
80 , m_ota(std::bind(&
OTA_Firmware_Update::Publish_Chunk_Request, this, std::placeholders::_1, std::placeholders::_2), std::bind(&
OTA_Firmware_Update::Firmware_Send_State, this, std::placeholders::_1, std::placeholders::_2), std::bind(&
OTA_Firmware_Update::Firmware_OTA_Unsubscribe, this))
85 , m_fw_attribute_update()
86 , m_fw_attribute_request()
92#if !THINGSBOARD_ENABLE_STL
93 m_subscribedInstance =
nullptr;
112 if (!Prepare_Firmware_Settings(callback)) {
119#if THINGSBOARD_ENABLE_STL
120 Request_Callback_Value const fw_request_callback(std::bind(&OTA_Firmware_Update::Firmware_Shared_Attribute_Received,
this, std::placeholders::_1), request_timeout.Get_Timeout(), std::bind(&OTA_Firmware_Update::Request_Timeout,
this), array + 0U, array +
OTA_ATTRIBUTE_KEYS_AMOUNT);
131 m_ota.Stop_Firmware_Update();
147 if (!Prepare_Firmware_Settings(callback)) {
153#if THINGSBOARD_ENABLE_STL
162 return API_Process_Type::RAW;
168 m_ota.Process_Firmware_Packet(chunk, payload, length);
176 return strncmp(m_response_topic, topic, strlen(m_response_topic)) == 0;
185 return Firmware_OTA_Subscribe();
188#if !THINGSBOARD_USE_ESP_TIMER
195 m_subscribe_api_callback.
Call_Callback(m_fw_attribute_update);
196 m_subscribe_api_callback.
Call_Callback(m_fw_attribute_request);
199 void Set_Client_Callbacks(
Callback<void, IAPI_Implementation &>::function subscribe_api_callback,
Callback<bool, char const * const, JsonDocument const &>::function send_json_callback,
Callback<bool, char const * const, char const * const>::function send_json_string_callback,
Callback<bool, char const * const>::function subscribe_topic_callback,
Callback<bool, char const * const>::function unsubscribe_topic_callback,
Callback<uint16_t>::function get_receive_size_callback,
Callback<uint16_t>::function get_send_size_callback,
Callback<bool, uint16_t, uint16_t>::function set_buffer_size_callback,
Callback<size_t *>::function get_request_id_callback)
override {
200 m_subscribe_api_callback.
Set_Callback(subscribe_api_callback);
202 m_send_json_string_callback.Set_Callback(send_json_string_callback);
203 m_subscribe_topic_callback.Set_Callback(subscribe_topic_callback);
204 m_unsubscribe_topic_callback.Set_Callback(unsubscribe_topic_callback);
205 m_get_receive_size_callback.
Set_Callback(get_receive_size_callback);
206 m_get_send_size_callback.
Set_Callback(get_send_size_callback);
207 m_set_buffer_size_callback.
Set_Callback(set_buffer_size_callback);
208 m_get_request_id_callback.
Set_Callback(get_request_id_callback);
217 bool Firmware_Send_Info(
char const * current_fw_title,
char const * current_fw_version) {
218 StaticJsonDocument<JSON_OBJECT_SIZE(2U)> current_firmware_info;
230 bool Firmware_Send_State(
char const * current_fw_state,
char const * fw_error =
"") {
231 StaticJsonDocument<JSON_OBJECT_SIZE(2U)> current_firmware_state;
233 current_firmware_state[
FW_STATE_KEY] = current_fw_state;
248 else if (!Firmware_Send_Info(current_fw_title, current_fw_version)) {
252 size_t * p_request_id = m_get_request_id_callback.
Call_Callback();
253 if (p_request_id ==
nullptr) {
257 auto & request_id = *p_request_id;
259 m_fw_callback = callback;
267 bool Firmware_OTA_Subscribe() {
274 bool Firmware_OTA_Unsubscribe() {
278 if (m_changed_buffer_size) {
290 bool Publish_Chunk_Request(
size_t const & request_id,
size_t const & request_chunck) {
294 (void)snprintf(size,
sizeof(size),
NUMBER_PRINTF, chunk_size);
298 return m_send_json_string_callback.Call_Callback(topic, size);
303 void Request_Timeout() {
311 void Firmware_Shared_Attribute_Received(JsonObjectConst
const & data) {
314 Logger::printfln(
NO_FW);
328 if (fw_title ==
nullptr || fw_version ==
nullptr || curr_fw_title ==
nullptr || curr_fw_version ==
nullptr || fw_algorithm ==
nullptr || fw_checksum ==
nullptr) {
335 else if (strncmp(curr_fw_title, fw_title, strlen(curr_fw_title)) == 0U && strncmp(curr_fw_version, fw_version, strlen(curr_fw_version)) == 0U) {
341 else if (strncmp(curr_fw_title, fw_title, strlen(curr_fw_title)) != 0U) {
342 char message[strlen(
FW_NOT_FOR_US) + strlen(fw_title) + strlen(curr_fw_title) + 3U] = {};
343 (void)snprintf(message,
sizeof(message),
FW_NOT_FOR_US, fw_title, curr_fw_title);
344 Logger::printfln(message);
352 fw_checksum_algorithm = mbedtls_md_type_t::MBEDTLS_MD_MD5;
355 fw_checksum_algorithm = mbedtls_md_type_t::MBEDTLS_MD_SHA256;
358 fw_checksum_algorithm = mbedtls_md_type_t::MBEDTLS_MD_SHA384;
361 fw_checksum_algorithm = mbedtls_md_type_t::MBEDTLS_MD_SHA512;
366 Logger::printfln(message);
372 bool const result = Firmware_OTA_Subscribe();
378#if THINGSBOARD_ENABLE_DEBUG
379 Logger::printfln(PAGE_BREAK);
380 Logger::printfln(NEW_FW);
381 char firmware[strlen(FROM_TOO) + strlen(curr_fw_version) + strlen(fw_version) + 3U] = {};
382 (void)snprintf(firmware,
sizeof(firmware), FROM_TOO, curr_fw_version, fw_version);
383 Logger::printfln(firmware);
384 Logger::printfln(DOWNLOADING_FW);
390 m_previous_buffer_size = m_get_receive_size_callback.
Call_Callback();
391 m_changed_buffer_size = m_previous_buffer_size < (chunk_size + 50U);
394 if (m_changed_buffer_size && !m_set_buffer_size_callback.
Call_Callback(chunk_size + 50U, m_get_send_size_callback.
Call_Callback())) {
401 m_ota.Start_Firmware_Update(m_fw_callback, fw_size, fw_checksum, fw_checksum_algorithm);
404#if !THINGSBOARD_ENABLE_STL
405 static void onStaticFirmwareReceived(JsonDocument
const & data) {
406 if (m_subscribedInstance ==
nullptr) {
409 m_subscribedInstance->Firmware_Shared_Attribute_Received(data);
412 static void onStaticRequestTimeout() {
413 if (m_subscribedInstance ==
nullptr) {
416 m_subscribedInstance->Request_Timeout();
419 static bool staticPublishChunk(
size_t const & request_id,
size_t const & request_chunck) {
420 if (m_subscribedInstance ==
nullptr) {
423 return m_subscribedInstance->Publish_Chunk_Request(request_id, request_chunck);
426 static bool staticFirmwareSend(
char const * current_fw_state,
char const * fw_error =
nullptr) {
427 if (m_subscribedInstance ==
nullptr) {
430 return m_subscribedInstance->Firmware_Send_State(current_fw_state, fw_error);
433 static bool staticUnsubscribe() {
434 if (m_subscribedInstance ==
nullptr) {
437 return m_subscribedInstance->Firmware_OTA_Unsubscribe();
454 uint16_t m_previous_buffer_size = {};
455 bool m_changed_buffer_size = {};
458 Update_Callback_Container m_fw_attribute_update = {};
459 Request_Callback_Container m_fw_attribute_request = {};
462#if !THINGSBOARD_ENABLE_STL
API_Process_Type
Possible processing types an API Implementation uses to handle responses from the server.
Definition: API_Process_Type.h:19
#define THINGSBOARD_ENABLE_STL
Definition: Configuration.h:42
char constexpr TELEMETRY_TOPIC[]
Definition: IAPI_Implementation.h:33
char constexpr REQUEST_ID_NULL[]
Definition: IAPI_Implementation.h:24
char constexpr FW_VER_KEY[]
Definition: OTA_Firmware_Update.h:22
uint8_t constexpr OTA_ATTRIBUTE_KEYS_AMOUNT
Definition: OTA_Firmware_Update.h:12
char constexpr FW_STATE_KEY[]
Definition: OTA_Firmware_Update.h:21
char constexpr FW_SIZE_KEY[]
Definition: OTA_Firmware_Update.h:26
char constexpr NOT_ENOUGH_RAM[]
Definition: OTA_Firmware_Update.h:37
char constexpr FW_NOT_FOR_US[]
Definition: OTA_Firmware_Update.h:35
char constexpr NUMBER_PRINTF[]
Definition: OTA_Firmware_Update.h:32
char constexpr FW_TITLE_KEY[]
Definition: OTA_Firmware_Update.h:23
char constexpr CHECKSUM_AGORITM_SHA256[]
Definition: OTA_Firmware_Update.h:28
uint8_t constexpr MAX_FW_TOPIC_SIZE
Definition: OTA_Firmware_Update.h:11
char constexpr RESETTING_FAILED[]
Definition: OTA_Firmware_Update.h:38
char constexpr FIRMWARE_REQUEST_TOPIC[]
Definition: OTA_Firmware_Update.h:16
char constexpr CURR_FW_TITLE_KEY[]
Definition: OTA_Firmware_Update.h:18
char constexpr FW_ERROR_KEY[]
Definition: OTA_Firmware_Update.h:20
char constexpr CHECKSUM_AGORITM_SHA384[]
Definition: OTA_Firmware_Update.h:29
char constexpr NO_FW[]
Definition: OTA_Firmware_Update.h:33
char constexpr CHECKSUM_AGORITM_SHA512[]
Definition: OTA_Firmware_Update.h:30
char constexpr NO_FW_REQUEST_RESPONSE[]
Definition: OTA_Firmware_Update.h:13
char constexpr EMPTY_FW[]
Definition: OTA_Firmware_Update.h:34
char constexpr FW_CHKS_ALGO_KEY[]
Definition: OTA_Firmware_Update.h:25
char constexpr FIRMWARE_RESPONSE_TOPIC[]
Definition: OTA_Firmware_Update.h:15
char constexpr FW_CHKS_KEY[]
Definition: OTA_Firmware_Update.h:24
char constexpr CURR_FW_VER_KEY[]
Definition: OTA_Firmware_Update.h:19
char constexpr CHECKSUM_AGORITM_MD5[]
Definition: OTA_Firmware_Update.h:27
char constexpr FW_CHKS_ALGO_NOT_SUPPORTED[]
Definition: OTA_Firmware_Update.h:36
char constexpr FW_STATE_FAILED[]
Definition: OTA_Handler.h:22
char constexpr FW_STATE_UPDATED[]
Definition: OTA_Handler.h:23
Client-side or shared attributes request callback wrapper, contains the needed configuration settings...
Definition: Attribute_Request_Callback.h:25
Handles the internal implementation of the ThingsBoard client and shared Attribute Request API....
Definition: Attribute_Request.h:43
bool Shared_Attributes_Request(Callback_Value const &callback)
Requests one shared attribute, which will call the passed callback. If the key-value pair from the se...
Definition: Attribute_Request.h:80
General purpose safe callback wrapper. Expects either c-style or c++ style function pointer,...
Definition: Callback.h:30
std::function< return_type(argument_types... arguments)> function
Callback signature.
Definition: Callback.h:34
void Set_Callback(function callback)
Sets the callback method that will be called upon data arrival with the given data that was received....
Definition: Callback.h:72
return_type Call_Callback(argument_types const &... arguments) const
Calls the callback that was subscribed, when this class instance was initally created.
Definition: Callback.h:62
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 bool String_IsNull_Or_Empty(char const *str)
Returns wheter the given string is either a nullptr or is an empty string, meaning it only contains a...
Definition: Helper.cpp:27
static size_t Split_Topic_Into_Request_ID(char const *received_topic, size_t const &end_position)
Splits the topic at the given position and extracts the request id parameter from the remaining strin...
Definition: Helper.cpp:31
Base functionality required by all API implementation.
Definition: IAPI_Implementation.h:37
Handles the internal implementation of the ThingsBoard over the air firmware update API....
Definition: OTA_Firmware_Update.h:51
void Process_Response(char const *topic, uint8_t *payload, uint32_t length) override
Process callback that will be called upon response arrival.
Definition: OTA_Firmware_Update.h:165
bool Start_Firmware_Update(OTA_Update_Callback const &callback)
Requests the current assigned firmware information on the connected device.
Definition: OTA_Firmware_Update.h:111
void Set_Client_Callbacks(Callback< void, IAPI_Implementation & >::function subscribe_api_callback, Callback< bool, char const *const, JsonDocument const & >::function send_json_callback, Callback< bool, char const *const, char const *const >::function send_json_string_callback, Callback< bool, char const *const >::function subscribe_topic_callback, Callback< bool, char const *const >::function unsubscribe_topic_callback, Callback< uint16_t >::function get_receive_size_callback, Callback< uint16_t >::function get_send_size_callback, Callback< bool, uint16_t, uint16_t >::function set_buffer_size_callback, Callback< size_t * >::function get_request_id_callback) override
Sets the underlying callbacks that are required for the different API Implementation to communicate w...
Definition: OTA_Firmware_Update.h:199
void Initialize() override
Method that allows to construct internal objects, after the required callback member methods have bee...
Definition: OTA_Firmware_Update.h:194
bool Unsubscribe() override
Unsubcribes all callbacks, to clear up any ongoing subscriptions and stop receiving information over ...
Definition: OTA_Firmware_Update.h:179
void Process_Json_Response(char const *topic, JsonDocument const &data) override
Process callback that will be called upon response arrival.
Definition: OTA_Firmware_Update.h:171
bool Is_Response_Topic_Matching(char const *topic) const override
Compares received response topic and the topic this api implementation handles responses on,...
Definition: OTA_Firmware_Update.h:175
bool Resubscribe_Permanent_Subscriptions() override
Forwards the call to let the API clear up any ongoing single-event subscriptions (Provision,...
Definition: OTA_Firmware_Update.h:184
OTA_Firmware_Update()
Constructor.
Definition: OTA_Firmware_Update.h:66
void loop() override
Internal loop method to update inernal timers for API calls that can timeout.
Definition: OTA_Firmware_Update.h:189
~OTA_Firmware_Update() override=default
void Stop_Firmware_Update()
Stops any currently ongoing firmware update.
Definition: OTA_Firmware_Update.h:130
bool Subscribe_Firmware_Update(OTA_Update_Callback const &callback)
Subscribes to any changes of the assigned firmware information on the connected device.
Definition: OTA_Firmware_Update.h:146
API_Process_Type Get_Process_Type() const override
Returns the way the server response should be processed.
Definition: OTA_Firmware_Update.h:161
Handles the complete processing of received binary firmware data including writing the data into some...
Definition: OTA_Handler.h:50
Over the air firmware update callback wrapper.
Definition: OTA_Update_Callback.h:19
Timeoutable_Request & Get_Request_Timeout()
Gets the request timeout callback.
Definition: OTA_Update_Callback.cpp:83
void Set_Request_ID(size_t const &request_id)
Sets the unique request identifier that is connected to the original request.
Definition: OTA_Update_Callback.cpp:47
uint16_t Get_Chunk_Size() const
Gets the size of the chunks that the firmware binary data will be split into.
Definition: OTA_Update_Callback.cpp:75
size_t const & Get_Request_ID() const
Gets the unique request identifier that is connected to the original request.
Definition: OTA_Update_Callback.cpp:43
char const * Get_Firmware_Version() const
Gets the current firmware version.
Definition: OTA_Update_Callback.cpp:27
void Call_Update_Starting_Callback() const
Calls the update starting callback that was subscribed, when this class instance was initally created...
Definition: OTA_Update_Callback.cpp:59
char const * Get_Firmware_Title() const
Gets the current firmware title.
Definition: OTA_Update_Callback.cpp:19
Shared attribute update callback wrapper, contains the needed configuration settings to create the re...
Definition: Shared_Attribute_Callback.h:20
Handles the internal implementation of the ThingsBoard shared Attribute Update API....
Definition: Shared_Attribute_Update.h:26
bool Shared_Attributes_Subscribe(InputIterator const &first, InputIterator const &last)
Subscribes shared attribute callbacks, that will be called if an update for the containing shared att...
Definition: Shared_Attribute_Update.h:55