2 import paho.mqtt.client
as mqtt
14 resultTopic =
"/result/#"
15 sleepSetTopic =
"/set/sleeptime"
16 sleepResultTopic =
"/result/sleeptime"
17 otaSetTopic =
"/set/ota"
18 otaResultTopic =
"/result/ota"
19 otaOutOfSequenceError =
"OTA out of sequence error"
20 otaOK =
"OTA finished OK"
25 OTA_OUT_OF_SEQUENCE = 4
33 print(
"Connected with result code " + str(rc))
34 mqtt.Client.connected_flag =
True
36 print(
"Error connecting. Code =" + str(rc))
39 sleep_topic = args.baseTopic +
"/" + args.address + resultTopic
40 client.subscribe(sleep_topic)
46 global idx, otaFinished
48 payload = json.loads(msg.payload)
50 if msg.topic.find(sleepResultTopic) >= 0
and payload[
'sleeptime'] == 0:
52 print(msg.topic +
" " + str(msg.payload))
56 if msg.topic.find(otaResultTopic) >= 0:
58 if payload[
'status'] == OTA_OUT_OF_SEQUENCE:
59 print(payload[
'last_chunk'], end=
'')
60 idx = int(payload[
'last_chunk'])
62 elif payload[
'status'] == OTA_FINISHED:
63 print(
" OTA Finished ", end=
'')
72 opt = argparse.ArgumentParser(description=
'This program allows updating EnigmaIOT node over the air using'
74 opt.add_argument(
"-f",
"--file",
77 default=
"program.bin",
78 help=
"File to program into device")
79 opt.add_argument(
"-d",
"--daddress",
82 help=
"Device address")
83 opt.add_argument(
"-t",
"--topic",
87 help=
"Base topic for MQTT messages")
88 opt.add_argument(
"-u",
"--user",
92 help=
"MQTT server username")
93 opt.add_argument(
"-P",
"--password",
97 help=
"MQTT server user password")
98 opt.add_argument(
"-S",
"--server",
102 help=
"MQTT server address or name")
103 opt.add_argument(
"-p",
"--port",
107 help=
"MQTT server port")
108 opt.add_argument(
"-s",
"--secure",
111 help=
"Use secure TLS in MQTT connection. Normally you should use port 8883")
112 opt.add_argument(
"--unsecure",
113 action=
"store_false",
116 help=
"Use secure plain TCP in MQTT connection. Normally you should use port 1883")
117 opt.add_argument(
"-D",
"--speed",
121 help=
"OTA update speed profile: 'fast', 'medium' or 'slow' Throttle this down in case of"
122 "problems with OTA update. Default: %default")
125 args = opt.parse_args()
128 opt.error(
'Destination address not supplied')
132 ota_topic = args.baseTopic +
"/" + args.address + otaSetTopic
133 mqttclientname =
"EnigmaIoTUpdate"
135 ota_length = os.stat(args.filename).st_size
137 delay_options = {
"fast": 0.02,
"medium": 0.06,
"slow": 0.18}
138 packet_delay = delay_options.get(args.otaSpeed, 0.07)
140 with open(args.filename,
"rb")
as binary_file:
145 for chunk
in iter(
lambda: binary_file.read(n), b
""):
146 chunked_file.append(chunk)
147 for chunk
in chunked_file:
148 encoded_string.append(base64.b64encode(bytes(chunk)).decode(
'ascii'))
151 hash_md5 = hashlib.md5()
152 for chunk
in iter(
lambda: binary_file.read(4096), b
""):
153 hash_md5.update(chunk)
158 mqtt.Client.connected_flag =
False
159 client = mqtt.Client(mqttclientname,
True)
160 client.username_pw_set(username=args.mqttUser, password=args.mqttPass)
163 client.on_connect = on_connect
164 client.on_message = on_message
166 client.connect(host=args.mqttServer, port=args.mqttPort)
167 while not client.connected_flag:
168 print(
"Connecting to MQTT server")
173 sleep_topic = args.baseTopic +
"/" + args.address + sleepSetTopic
174 client.publish(sleep_topic,
"0")
177 print(
"Waiting for non sleepy confirmation")
181 print(
"Sending hash: " + hash_md5.hexdigest())
182 md5_str = hash_md5.hexdigest()
185 print(
"Sending %d bytes in %d chunks" % (ota_length,len(encoded_string)))
186 client.publish(ota_topic,
"0," + str(ota_length) +
"," + str(len(encoded_string)) +
"," + md5_str)
189 print(
"Sending file: " + args.filename)
195 while idx < len(encoded_string):
197 time.sleep(packet_delay)
201 client.publish(ota_topic, str(i) +
"," + encoded_string[idx])
212 print(
" %.f%%" % (i / len(encoded_string) * 100))
213 if i == len(encoded_string):
214 for i
in range(0, 40):
218 print(
" OTA OK ", end=
'')
226 if __name__ ==
'__main__':