diff --git a/tools/mqtt-file/Config_demo_9.4.0.3.dmp b/tools/mqtt-file/Config_demo_9.4.0.3.dmp index 7bed4efce..e195bbb48 100644 Binary files a/tools/mqtt-file/Config_demo_9.4.0.3.dmp and b/tools/mqtt-file/Config_demo_9.4.0.3.dmp differ diff --git a/tools/mqtt-file/download-settings.py b/tools/mqtt-file/download-settings.py new file mode 100644 index 000000000..247af2a88 --- /dev/null +++ b/tools/mqtt-file/download-settings.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + download-settings.py - Upload Tasmota settings file + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Requirements: + - Python 3.x and Pip: + sudo apt-get install python3 python3-pip + pip3 install paho-mqtt json + +Instructions: + Edit file and change parameters in User Configuration Section + + Then execute command download-settings.py + +""" + +import paho.mqtt.client as mqtt +import time +import base64 +import hashlib +import json + +# **** Start of User Configuration Section + +broker = "domus1" # MQTT broker ip address or name +broker_port = 1883 # MQTT broker port + +mytopic = "demo" # Tasmota MQTT topic +myfiletype = 2 # Tasmota Settings file type + +# **** End of User Configuration Section + +# Derive fulltopic from broker LWT message +mypublish = "cmnd/"+mytopic+"/filedownload" +mysubscribe = "stat/"+mytopic+"/FILEDOWNLOAD" # Case sensitive + +# Tasmota currently supports MQTT message size of 1040 characters. Base64 adds 0.25 chars +chucksize = 700 # Tasmota max chunk size +Ack_flag = False + +file_name = "" +file_id = 0 +file_type = 0 +file_size = 0 +file_md5 = "" + +# The callback for when mysubscribe message is received +def on_message(client, userdata, msg): + global Ack_flag + global Run_flag + global file_name + global file_id + global file_type + global file_size + global file_md5 + global in_hash_md5 + + base64_data = "" + rcv_id = 0 + +# print("Received message =",str(msg.payload.decode("utf-8"))) + + root = json.loads(msg.payload.decode("utf-8")) + if "File" in root: file_name = root["File"] + if "Id" in root: rcv_id = root["Id"] + if "Type" in root: file_type = root["Type"] + if "Size" in root: file_size = root["Size"] + if "Data" in root: base64_data = root["Data"] + if "Md5" in root: file_md5 = root["Md5"] + + if file_id == 0 and rcv_id > 0 and file_size > 0 and file_type > 0 and file_name: + file_id = rcv_id + fi = open(file_name,"wb") + fi.close() + + else: + if file_id > 0 and file_id != rcv_id: + Run_flag = False + return + + if file_md5 == "" and base64_data: + base64_decoded_data = base64_data.encode('utf-8') + chunk = base64.decodebytes(base64_decoded_data) + in_hash_md5.update(chunk) # Update hash + + fi = open(file_name,"ab") + fi.write(chunk) + fi.close() + + if file_md5 != "": + md5_hash = in_hash_md5.hexdigest() + if md5_hash != file_md5: + print("Error: MD5 mismatch") + Run_flag = False + + Ack_flag = False + +def wait_for_ack(): + global Ack_flag + global Run_flag + if Run_flag == False: + print("Error: Transmission") + return True + + timeout = 100 + while Ack_flag and timeout > 0: + time.sleep(0.01) + timeout = timeout -1 + + if Ack_flag: + print("Error: Timeout") + + return Ack_flag + +client = mqtt.Client() +client.on_message = on_message +client.connect(broker, broker_port) +client.loop_start() # Start loop to process received messages +client.subscribe(mysubscribe) + +time_start = time.time() +print("Downloading file from "+mytopic+" ...") + +in_hash_md5 = hashlib.md5() + +Err_flag = False + +client.publish(mypublish, str(myfiletype)) +Ack_flag = True + +Run_flag = True +while Run_flag: + if wait_for_ack(): # We use Ack here + Err_flag = True + Run_flag = False + + else: + if file_md5 == "": + client.publish(mypublish, "?") + Ack_flag = True + + else: + Run_flag = False + +if Err_flag: + client.publish(mypublish, "0") # Abort any failed download + +time_taken = time.time() - time_start + +file_type_name = " Data" +if file_type == 2: + file_type_name = " Settings" + +print("Downloaded"+file_type_name+" saved as "+file_name) +print("Done in "+str("%.2f"%time_taken)+" seconds") + +client.disconnect() # Disconnect +client.loop_stop() # Stop loop diff --git a/tools/mqtt-file/upload-example1.py b/tools/mqtt-file/upload-example1.py deleted file mode 100644 index 5a541cb79..000000000 --- a/tools/mqtt-file/upload-example1.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" - upload-example1.py - Upload Tasmota settings file - - Copyright (C) 2021 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Requirements: - - Python 3.x and Pip: - sudo apt-get install python3 python3-pip - pip3 install paho-mqtt - -Instructions: - Edit file and change parameters in User Configuration Section - - Then execute command upload-example1.py - -""" - -import paho.mqtt.client as mqtt -import time -import base64 -import hashlib - -# **** Start of User Configuration Section - -broker = "domus1" # MQTT broker ip address or name -broker_port = 1883 # MQTT broker port - -mytopic = "demo" # Tasmota MQTT topic -myfile = "Config_demo_9.4.0.3.dmp" # Tasmota Settings file name -myfiletype = 2 # Tasmota Settings file type - -# **** End of User Configuration Section - -# Derive from myfile -myfilesize = 4096 - -# Derive from time epoch -myid = 1620484815 - -# Derive fulltopic from broker LWT message -mypublish = "cmnd/"+mytopic+"/fileupload" - -# Tasmota currently supports MQTT message size of 1040 characters. Base64 adds 0.25 chars -chucksize = 700 # Tasmota max chunk size - -# Example does not use feedback Acknowledge -sleeptime = 0.2 - -client = mqtt.Client() -client.connect(broker, broker_port) - -time_start = time.time() -print("Uploading file "+myfile+" to "+mytopic+" ...") - -client.publish(mypublish, "{\"File\":\""+myfile+"\",\"Id\":"+str(myid)+",\"Type\":"+str(myfiletype)+",\"Size\":"+str(myfilesize)+"}") - -out_hash_md5 = hashlib.md5() - -fo = open(myfile,"rb") -Run_flag = True -while Run_flag: - time.sleep(sleeptime) # We do not use Ack here - - chunk = fo.read(chucksize) - if chunk: - out_hash_md5.update(chunk) # Update hash - base64_encoded_data = base64.b64encode(chunk) - base64_data = base64_encoded_data.decode('utf-8') - client.publish(mypublish, "{\"Id\":"+str(myid)+",\"Data\":\""+base64_data+"\"}") - - else: - md5_hash = out_hash_md5.hexdigest() - client.publish(mypublish, "{\"Id\":"+str(myid)+",\"Md5\":\""+md5_hash+"\"}") - Run_flag=False - -fo.close() - -time_taken = time.time() - time_start -print("Done in "+str("%.2f"%time_taken)+" seconds") - -client.disconnect() # Disconnect diff --git a/tools/mqtt-file/upload-example2.py b/tools/mqtt-file/upload-settings.py similarity index 97% rename from tools/mqtt-file/upload-example2.py rename to tools/mqtt-file/upload-settings.py index 6adfc7beb..548669df4 100644 --- a/tools/mqtt-file/upload-example2.py +++ b/tools/mqtt-file/upload-settings.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ - upload-example2.py - Upload Tasmota settings file + upload-settings.py - Upload Tasmota settings file Copyright (C) 2021 Theo Arends @@ -27,7 +27,7 @@ Requirements: Instructions: Edit file and change parameters in User Configuration Section - Then execute command upload-example2.py + Then execute command upload-settings.py """