Skip to content

Commit 9c02968

Browse files
Added firmware update exposed to user
1 parent d925979 commit 9c02968

File tree

1 file changed

+46
-25
lines changed

1 file changed

+46
-25
lines changed

tb_device_mqtt.py

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ class TBSendMethod(Enum):
106106
PUBLISH = 1
107107
UNSUBSCRIBE = 2
108108

109+
class TBFirmwareState(Enum):
110+
IDLE = "IDLE"
111+
DOWNLOADING = "DOWNLOADING"
112+
DOWNLOADED = "DOWNLOADED"
113+
VERIFIED = "VERIFIED"
114+
UPDATING = "UPDATING"
115+
UPDATED = "UPDATED"
116+
FAILED = "FAILED"
109117

110118
class TBPublishInfo:
111119
TB_ERR_AGAIN = -1
@@ -474,7 +482,7 @@ class TBDeviceMqttClient:
474482
def __init__(self, host, port=1883, username=None, password=None, quality_of_service=None, client_id="",
475483
chunk_size=0, messages_rate_limit="DEFAULT_MESSAGES_RATE_LIMIT",
476484
telemetry_rate_limit="DEFAULT_TELEMETRY_RATE_LIMIT",
477-
telemetry_dp_rate_limit="DEFAULT_TELEMETRY_DP_RATE_LIMIT", max_payload_size=8196, **kwargs):
485+
telemetry_dp_rate_limit="DEFAULT_TELEMETRY_DP_RATE_LIMIT", max_payload_size=8196, on_firmware_received=None, **kwargs):
478486
# Added for compatibility with old versions
479487
if kwargs.get('rate_limit') is not None or kwargs.get('dp_rate_limit') is not None:
480488
messages_rate_limit = messages_rate_limit if kwargs.get('rate_limit') == "DEFAULT_RATE_LIMIT" else kwargs.get('rate_limit', messages_rate_limit) # noqa
@@ -523,37 +531,45 @@ def __init__(self, host, port=1883, username=None, password=None, quality_of_ser
523531
self.current_firmware_info = {
524532
"current_" + FW_TITLE_ATTR: "Initial",
525533
"current_" + FW_VERSION_ATTR: "v0",
526-
FW_STATE_ATTR: "IDLE"
534+
FW_STATE_ATTR: TBFirmwareState.IDLE.value,
527535
}
528536
self.__request_id = 0
529537
self.__firmware_request_id = 0
530538
self.__chunk_size = chunk_size
531539
self.firmware_received = False
540+
self.set_on_firmware_received_function(on_firmware_received)
532541
self.rate_limits_received = False
533542
self.__request_service_configuration_required = False
534543
self.__service_loop = Thread(target=self.__service_loop, name="Service loop", daemon=True)
535544
self.__service_loop.start()
536545
self.__messages_limit_reached_set_time = (0,0)
537546
self.__datapoints_limit_reached_set_time = (0,0)
538547

548+
def update_firmware_info(self, title = None, version = None, state: TBFirmwareState = None, error = None):
549+
if title is not None:
550+
self.current_firmware_info["current_" + FW_TITLE_ATTR] = title
551+
552+
if version is not None:
553+
self.current_firmware_info["current_" + FW_VERSION_ATTR] = version
554+
555+
if state is not None:
556+
self.current_firmware_info[FW_STATE_ATTR] = state.value
557+
558+
self.send_telemetry(self.current_firmware_info)
559+
560+
def set_on_firmware_received_function(self, on_firmware_received):
561+
if on_firmware_received is not None:
562+
self.__on_firmware_received = on_firmware_received
563+
else:
564+
self.__on_firmware_received = self.__on_firmware_received_default
565+
539566
def __service_loop(self):
540567
while not self.stopped:
541568
if self.__request_service_configuration_required:
542569
self.request_service_configuration(self.service_configuration_callback)
543570
self.__request_service_configuration_required = False
544571
elif self.firmware_received:
545-
self.current_firmware_info[FW_STATE_ATTR] = "UPDATING"
546-
self.send_telemetry(self.current_firmware_info)
547-
sleep(1)
548-
549-
self.__on_firmware_received(self.firmware_info.get(FW_VERSION_ATTR))
550-
551-
self.current_firmware_info = {
552-
"current_" + FW_TITLE_ATTR: self.firmware_info.get(FW_TITLE_ATTR),
553-
"current_" + FW_VERSION_ATTR: self.firmware_info.get(FW_VERSION_ATTR),
554-
FW_STATE_ATTR: "UPDATED"
555-
}
556-
self.send_telemetry(self.current_firmware_info)
572+
self.__on_firmware_received(self, self.firmware_data, self.firmware_info.get(FW_VERSION_ATTR))
557573
self.firmware_received = False
558574
sleep(0.05)
559575

@@ -758,8 +774,7 @@ def _on_decoded_message(self, content, message):
758774
self.firmware_data = b''
759775
self.__current_chunk = 0
760776

761-
self.current_firmware_info[FW_STATE_ATTR] = "DOWNLOADING"
762-
self.send_telemetry(self.current_firmware_info)
777+
self.update_firmware_info(state = TBFirmwareState.DOWNLOADING)
763778
sleep(1)
764779

765780
self.__firmware_request_id = self.__firmware_request_id + 1
@@ -769,22 +784,19 @@ def _on_decoded_message(self, content, message):
769784
self.__get_firmware()
770785

771786
def __process_firmware(self):
772-
self.current_firmware_info[FW_STATE_ATTR] = "DOWNLOADED"
773-
self.send_telemetry(self.current_firmware_info)
787+
self.update_firmware_info(state = TBFirmwareState.DOWNLOADED)
774788
sleep(1)
775789

776790
verification_result = verify_checksum(self.firmware_data, self.firmware_info.get(FW_CHECKSUM_ALG_ATTR),
777791
self.firmware_info.get(FW_CHECKSUM_ATTR))
778792

779793
if verification_result:
780794
log.debug('Checksum verified!')
781-
self.current_firmware_info[FW_STATE_ATTR] = "VERIFIED"
782-
self.send_telemetry(self.current_firmware_info)
795+
self.update_firmware_info(state = TBFirmwareState.VERIFIED)
783796
sleep(1)
784797
else:
785798
log.debug('Checksum verification failed!')
786-
self.current_firmware_info[FW_STATE_ATTR] = "FAILED"
787-
self.send_telemetry(self.current_firmware_info)
799+
self.update_firmware_info(state = TBFirmwareState.FAILED)
788800
self.__request_firmware_info()
789801
return
790802
self.firmware_received = True
@@ -796,10 +808,19 @@ def __get_firmware(self):
796808
f"v2/fw/request/{self.__firmware_request_id}/chunk/{self.__current_chunk}",
797809
payload=payload, qos=1)
798810

799-
def __on_firmware_received(self, version_to):
811+
def __on_firmware_received_default(self, client, firmware_data, version_to):
812+
self.update_firmware_info(state = TBFirmwareState.UPDATING)
813+
sleep(1)
814+
800815
with open(self.firmware_info.get(FW_TITLE_ATTR), "wb") as firmware_file:
801-
firmware_file.write(self.firmware_data)
802-
log.info('Firmware is updated!\n Current firmware version is: %s' % version_to)
816+
firmware_file.write(firmware_data)
817+
log.warning(f"Firmware was received and stored under {self.firmware_info.get(FW_TITLE_ATTR)},"
818+
"but 'on_firmware_received' callback is not defined. No OTA update applied."
819+
"Call 'set_on_firmware_received_function' to handle properly firmware update.")
820+
821+
self.update_firmware_info(title = self.firmware_info.get(FW_TITLE_ATTR),
822+
version = self.firmware_info.get(FW_VERSION_ATTR),
823+
state = TBFirmwareState.UPDATED)
803824

804825
@staticmethod
805826
def _decode(message):

0 commit comments

Comments
 (0)