@@ -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
110118class 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