From 213746f50fb180f19a7f94d988eea4431e8cfe4b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 1 Jul 2021 15:28:18 +0200 Subject: [PATCH] Prep MQTT file upload/download for TasMesh --- tasmota/xdrv_02_1_mqtt_file.ino | 115 +++++++++++------- ...mo_9.4.0.4.dmp => Config_demo_9.5.0.1.dmp} | Bin 4096 -> 4096 bytes tools/mqtt-file/download-settings.py | 5 +- tools/mqtt-file/upload-ota.py | 7 +- tools/mqtt-file/upload-settings.py | 7 +- 5 files changed, 82 insertions(+), 52 deletions(-) rename tools/mqtt-file/{Config_demo_9.4.0.4.dmp => Config_demo_9.5.0.1.dmp} (74%) diff --git a/tasmota/xdrv_02_1_mqtt_file.ino b/tasmota/xdrv_02_1_mqtt_file.ino index d6205b73f..7c6ddc63c 100644 --- a/tasmota/xdrv_02_1_mqtt_file.ino +++ b/tasmota/xdrv_02_1_mqtt_file.ino @@ -37,6 +37,7 @@ struct FMQTT { uint32_t file_pos = 0; // MQTT file position during upload/download uint32_t file_size = 0; // MQTT total file size uint32_t file_type = 0; // MQTT File type (See UploadTypes) + uint32_t chunk_size; uint8_t* file_buffer = nullptr; // MQTT file buffer const char* file_password = nullptr; // MQTT password MD5Builder md5; // MQTT md5 @@ -48,6 +49,41 @@ struct FMQTT { const uint32_t FileTransferHeaderSize = 21; // {"Id":116,"Data":""} +void MqttFileValidate(uint32_t error) { + if (error) { + FMqtt.file_buffer = nullptr; + + MqttDisableLogging(false); + + if (4 == error) { + ResponseCmndChar(PSTR(D_JSON_ABORTED)); + } else { + char error_txt[20]; + snprintf_P(error_txt, sizeof(error_txt), PSTR(D_JSON_ERROR " %d"), error); + ResponseCmndChar(error_txt); + } + } +} + +void MqttFilePublish(void) { + if (!FMqtt.file_buffer) { + MqttDisableLogging(false); + + FMqtt.file_id = 0; + FMqtt.file_size = 0; + FMqtt.file_type = 0; + FMqtt.file_binary = false; + FMqtt.file_md5 = (const char*) nullptr; // Force deallocation of the String internal memory + FMqtt.file_password = nullptr; + } + MqttPublishPrefixTopic_P(STAT, XdrvMailbox.command); + ResponseClear(); +} + +/*********************************************************************************************\ + * MQTT Upload to device +\*********************************************************************************************/ + uint32_t MqttFileUploadValidate(uint32_t rcv_id) { if (XdrvMailbox.grpflg) { return 5; } // No grouptopic supported @@ -105,6 +141,25 @@ uint32_t MqttFileUploadValidate(uint32_t rcv_id) { ResponseCmndChar(PSTR(D_JSON_STARTED)); MqttPublishPrefixTopic_P(STAT, XdrvMailbox.command); // Enforce stat/wemos10/FILEUPLOAD + + /* + The upload chunk size is the data size of the payload. + The PubSubClient upload buffer with length MQTT_MAX_PACKET_SIZE contains + - Header of 5 bytes (MQTT_MAX_HEADER_SIZE) + - Topic string terminated with a zero (stat/demo/FILEUPLOAD) + - Payload ({"Id":116,"Data":""}) or () + */ + const uint32_t PubSubClientHeaderSize = 5; // MQTT_MAX_HEADER_SIZE + FMqtt.chunk_size = MqttClient.getBufferSize() - PubSubClientHeaderSize - FMqtt.topic_size -1; +#ifdef USE_TASMESH + if (MESHroleNode()) { + // TasMesh default payload size (topic+payload) is 160 + if (MESHmaxPayloadSize() < FMqtt.chunk_size) { + FMqtt.chunk_size = MESHmaxPayloadSize(); + } + } +#endif // USE_TASMESH + } else if (((FMqtt.file_id > 0) && (FMqtt.file_id != rcv_id)) || (0 == XdrvMailbox.payload)) { // Error receiving data @@ -130,37 +185,6 @@ uint32_t MqttFileUploadValidate(uint32_t rcv_id) { return 0; // No error } -void MqttFileValidate(uint32_t error) { - if (error) { - FMqtt.file_buffer = nullptr; - - MqttDisableLogging(false); - - if (4 == error) { - ResponseCmndChar(PSTR(D_JSON_ABORTED)); - } else { - char error_txt[20]; - snprintf_P(error_txt, sizeof(error_txt), PSTR(D_JSON_ERROR " %d"), error); - ResponseCmndChar(error_txt); - } - } -} - -void MqttFilePublish(void) { - if (!FMqtt.file_buffer) { - MqttDisableLogging(false); - - FMqtt.file_id = 0; - FMqtt.file_size = 0; - FMqtt.file_type = 0; - FMqtt.file_binary = false; - FMqtt.file_md5 = (const char*) nullptr; // Force deallocation of the String internal memory - FMqtt.file_password = nullptr; - } - MqttPublishPrefixTopic_P(STAT, XdrvMailbox.command); - ResponseClear(); -} - void CmndFileUpload(void) { /* Upload bytes chunks of data either base64 encoded or binary with MD5 hash @@ -257,20 +281,11 @@ void CmndFileUpload(void) { if ((FMqtt.file_pos < FMqtt.file_size) || (FMqtt.file_md5.length() != 32)) { MqttDisableLogging(true); - /* - The upload chunk size is the data size of the payload. - The PubSubClient upload buffer with length MQTT_MAX_PACKET_SIZE contains - - Header of 5 bytes (MQTT_MAX_HEADER_SIZE) - - Topic string terminated with a zero (stat/demo/FILEUPLOAD) - - Payload ({"Id":116,"Data":""}) or () - */ - const uint32_t PubSubClientHeaderSize = 5; // MQTT_MAX_HEADER_SIZE - uint32_t chunk_size = MqttClient.getBufferSize() - PubSubClientHeaderSize - FMqtt.topic_size -1; - if (!binary_data) { - chunk_size = (((chunk_size - FileTransferHeaderSize) / 4) * 3) -2; // Calculate base64 chunk size + if (!binary_data && !FMqtt.file_pos) { + FMqtt.chunk_size = (((FMqtt.chunk_size - FileTransferHeaderSize) / 4) * 3) -2; // Calculate base64 chunk size } // {"Id":116,"MaxSize":"765"} - Response_P(PSTR("{\"Id\":%d,\"MaxSize\":%d}"), FMqtt.file_id, chunk_size); + Response_P(PSTR("{\"Id\":%d,\"MaxSize\":%d}"), FMqtt.file_id, FMqtt.chunk_size); } else { FMqtt.md5.calculate(); if (strcasecmp(FMqtt.file_md5.c_str(), FMqtt.md5.toString().c_str())) { @@ -310,6 +325,10 @@ void CmndFileUpload(void) { MqttFilePublish(); } +/*********************************************************************************************\ + * MQTT Download from device +\*********************************************************************************************/ + uint32_t MqttFileDownloadValidate(void) { if (XdrvMailbox.grpflg) { return 5; } // No grouptopic supported @@ -377,9 +396,6 @@ void CmndFileDownload(void) { */ if (FMqtt.file_buffer) { if (FMqtt.file_pos < FMqtt.file_size) { -#ifdef USE_TASMESH - uint32_t chunk_size = 2048; -#else uint32_t chunk_size = 4096; if (!FMqtt.file_binary) { /* @@ -389,7 +405,12 @@ void CmndFileDownload(void) { */ chunk_size = (((ResponseSize() - FileTransferHeaderSize) / 4) * 3) -2; } -#endif +#ifdef USE_TASMESH + if (MESHroleNode() && (chunk_size > 2048)) { + chunk_size = 2048; + } +#endif // USE_TASMESH + uint32_t bytes_left = FMqtt.file_size - FMqtt.file_pos; uint32_t write_bytes = (bytes_left < chunk_size) ? bytes_left : chunk_size; uint8_t* buffer = FMqtt.file_buffer + FMqtt.file_pos; diff --git a/tools/mqtt-file/Config_demo_9.4.0.4.dmp b/tools/mqtt-file/Config_demo_9.5.0.1.dmp similarity index 74% rename from tools/mqtt-file/Config_demo_9.4.0.4.dmp rename to tools/mqtt-file/Config_demo_9.5.0.1.dmp index 4456b7b5e8feeaf7b71b676a5c2cbaa45013dd4b..b265d202924829477a7d5c88c89f77bb313f015a 100644 GIT binary patch delta 795 zcmV+$1LXXGAb=o$2@+gQXrHj zgrAt*?W(!8qOI1%!>;$dufM3HsI9tE0Rkp;cVl5;aW5n(d0~HfayL8_adUci87dnr z9cq44OifosRwig}Zz^PBEqY*gc7Ap=eR+F)IbKvzNKFnvGAk!4BsFzNc}h!6O-@fx zQBqS>RaRF#SXo*OIWRFSQBh)JWMyV&XlZI|Y;A6DaB*^Tbai%jczJqzd^#Hu<@4*{ z(Cy>sh>41ejN0qs|Kg*gvpNk}0ke_j#Tr*pLTQ);oRbMt#NlPsf0%~??Y+`PFa0+i@4R~&1 z0}>Wubb4Za92$Odd2w-I4h&-u015(S0UjQHe{BmD1_B%%8v=J67J3aG4{d)%HzO}G zAVWtjCoUu+O(7vrB{x4YSUw{yOGsEKI5RKB)5F)%*TbjG#;X18|G%%b$J5_`!O*j} z-PhjK(!J5qfc59^;fU_@{hOGGCv9hLWMZ?^3nl{z Z6I4|VP+Rj_TayA0_6VJ+fiX6K^X}&6rT^{z*w%Wh5u&b=m;o^&sk(S+z zhKHV?+`*23nBDV`nwx@)$ojvkxUHZiF*I8QK~O?lR$o|2Uk(p7VPJN0d~Px~JZ^Ms zbbUGxAx1_?N+uU587f~*UPC}cP(d?$b8t6zcRFu#dU6Ya;^_S5^Tqo1`<0fLn3>J~@$&7ikh4bt3xz){{P+9&miYFW?*8!jllPRA z@bc$@gOHepgN2ywih%HklY!^;^MRR_kDmGcn~|ihth0#-dI7To4E6#EGgMU#P+Rj_ RSd#(|_6X4G^EE=NRz)g<1I_>d diff --git a/tools/mqtt-file/download-settings.py b/tools/mqtt-file/download-settings.py index 0b4f644fc..6953f8737 100644 --- a/tools/mqtt-file/download-settings.py +++ b/tools/mqtt-file/download-settings.py @@ -145,13 +145,16 @@ def on_message(client, userdata, msg): Ack_flag = False def wait_for_ack(): - timeout = 100 + global Err_flag + + timeout = 500 while Ack_flag and Err_flag == False and timeout > 0: time.sleep(0.01) timeout = timeout -1 if 0 == timeout: print("Error: Timeout") + Err_flag = True return Ack_flag diff --git a/tools/mqtt-file/upload-ota.py b/tools/mqtt-file/upload-ota.py index 0300940f5..ed9f962e1 100644 --- a/tools/mqtt-file/upload-ota.py +++ b/tools/mqtt-file/upload-ota.py @@ -50,7 +50,7 @@ myfiletype = 1 # Tasmota firmware file type # **** End of User Configuration Section -use_base64 = False +use_base64 = True # Derive fulltopic from broker LWT message mypublish = "cmnd/"+mytopic+"/fileupload" @@ -104,13 +104,16 @@ def on_message(client, userdata, msg): Ack_flag = False def wait_for_ack(): - timeout = 100 + global Err_flag + + timeout = 500 while Ack_flag and Err_flag == False and timeout > 0: time.sleep(0.01) timeout = timeout -1 if 0 == timeout: print("Error: Timeout") + Err_flag = True return Ack_flag diff --git a/tools/mqtt-file/upload-settings.py b/tools/mqtt-file/upload-settings.py index facfeb28f..fe782f04c 100644 --- a/tools/mqtt-file/upload-settings.py +++ b/tools/mqtt-file/upload-settings.py @@ -44,7 +44,7 @@ broker_port = 1883 # MQTT broker port mypassword = "" # Tasmota MQTT password mytopic = "demo" # Tasmota MQTT topic -myfile = "Config_demo_9.4.0.4.dmp" # Tasmota Settings file name +myfile = "Config_demo_9.5.0.1.dmp" # Tasmota Settings file name myfiletype = 2 # Tasmota Settings file type # **** End of User Configuration Section @@ -103,13 +103,16 @@ def on_message(client, userdata, msg): Ack_flag = False def wait_for_ack(): - timeout = 100 + global Err_flag + + timeout = 500 while Ack_flag and Err_flag == False and timeout > 0: time.sleep(0.01) timeout = timeout -1 if 0 == timeout: print("Error: Timeout") + Err_flag = True return Ack_flag