@@ -891,6 +891,83 @@ async def check_node_update(self, node_id: int) -> dict | None:
891
891
892
892
return await self ._check_node_update (node_id )
893
893
894
+ async def _initialize_ota_provider (self , ota_provider : ExternalOtaProvider ) -> None :
895
+ """Commissions the OTA Provider."""
896
+
897
+ if self .chip_controller is None :
898
+ raise RuntimeError ("Device Controller not initialized." )
899
+
900
+ # The OTA Provider has not been commissioned yet, let's do it now.
901
+ LOGGER .info ("Commissioning the built-in OTA Provider App." )
902
+ try :
903
+ ota_provider_node = await self .commission_on_network (
904
+ ota_provider .get_passcode (),
905
+ # TODO: Filtering by long discriminator seems broken
906
+ # filter_type=FilterType.LONG_DISCRIMINATOR,
907
+ # filter=ota_provider.get_descriminator(),
908
+ )
909
+ ota_provider_node_id = ota_provider_node .node_id
910
+ except NodeCommissionFailed :
911
+ LOGGER .error ("Failed to commission OTA Provider App!" )
912
+ return
913
+
914
+ LOGGER .info (
915
+ "OTA Provider App commissioned with node id %d." ,
916
+ ota_provider_node_id ,
917
+ )
918
+
919
+ # Adjust ACL of OTA Requestor such that Node peer-to-peer communication
920
+ # is allowed.
921
+ try :
922
+ read_result = await self .chip_controller .ReadAttribute (
923
+ ota_provider_node_id , [(0 , Clusters .AccessControl .Attributes .Acl )]
924
+ )
925
+ acl_list = cast (
926
+ list ,
927
+ read_result [0 ][Clusters .AccessControl ][
928
+ Clusters .AccessControl .Attributes .Acl
929
+ ],
930
+ )
931
+
932
+ # Add new ACL entry...
933
+ acl_list .append (
934
+ Clusters .AccessControl .Structs .AccessControlEntryStruct (
935
+ fabricIndex = 1 ,
936
+ privilege = Clusters .AccessControl .Enums .AccessControlEntryPrivilegeEnum .kOperate ,
937
+ authMode = Clusters .AccessControl .Enums .AccessControlEntryAuthModeEnum .kCase ,
938
+ subjects = Types .NullValue ,
939
+ targets = [
940
+ Clusters .AccessControl .Structs .AccessControlTargetStruct (
941
+ cluster = Clusters .OtaSoftwareUpdateProvider .id ,
942
+ endpoint = 0 ,
943
+ deviceType = Types .NullValue ,
944
+ )
945
+ ],
946
+ )
947
+ )
948
+
949
+ # And write. This is persistent, so only need to be done after we commissioned
950
+ # the OTA Provider App.
951
+ write_result : Attribute .AttributeWriteResult = (
952
+ await self .chip_controller .WriteAttribute (
953
+ ota_provider_node_id ,
954
+ [(0 , Clusters .AccessControl .Attributes .Acl (acl_list ))],
955
+ )
956
+ )
957
+ if write_result [0 ].Status != Status .Success :
958
+ logging .error (
959
+ "Failed writing adjusted OTA Provider App ACL: Status %s." ,
960
+ str (write_result [0 ].Status ),
961
+ )
962
+ await self .remove_node (ota_provider_node_id )
963
+ raise UpdateError ("Error while setting up OTA Provider." )
964
+ except ChipStackError as ex :
965
+ logging .exception ("Failed adjusting OTA Provider App ACL." , exc_info = ex )
966
+ await self .remove_node (ota_provider_node_id )
967
+ raise UpdateError ("Error while setting up OTA Provider." ) from ex
968
+
969
+ ota_provider .set_node_id (ota_provider_node_id )
970
+
894
971
@api_command (APICommand .UPDATE_NODE )
895
972
async def update_node (self , node_id : int , software_version : int ) -> dict | None :
896
973
"""
@@ -918,7 +995,9 @@ async def update_node(self, node_id: int, software_version: int) -> dict | None:
918
995
await self ._ota_provider .download_update (update )
919
996
920
997
ota_provider_node_id = self ._ota_provider .get_node_id ()
921
- if ota_provider_node_id not in self ._nodes :
998
+ if ota_provider_node_id is None :
999
+ LOGGER .info ("Initializing OTA Provider" )
1000
+ elif ota_provider_node_id not in self ._nodes :
922
1001
LOGGER .warning (
923
1002
"OTA Provider node id %d no longer exists! Resetting..." ,
924
1003
ota_provider_node_id ,
@@ -928,82 +1007,17 @@ async def update_node(self, node_id: int, software_version: int) -> dict | None:
928
1007
929
1008
# Make sure any previous instances get stopped
930
1009
await self ._ota_provider .stop ()
931
- self ._ota_provider .start ()
1010
+ await self ._ota_provider .start ()
932
1011
933
1012
# Wait for OTA provider to be ready
934
1013
# TODO: Detect when OTA provider is ready
935
1014
await asyncio .sleep (2 )
936
1015
937
1016
if not ota_provider_node_id :
938
- # The OTA Provider has not been commissioned yet, let's do it now.
939
- LOGGER .info ("Commissioning the built-in OTA Provider App." )
940
- try :
941
- ota_provider_node = await self .commission_on_network (
942
- self ._ota_provider .get_passcode (),
943
- # TODO: Filtering by long discriminator seems broken
944
- # filter_type=FilterType.LONG_DISCRIMINATOR,
945
- # filter=self._ota_provider.get_descriminator(),
946
- )
947
- ota_provider_node_id = ota_provider_node .node_id
948
- except NodeCommissionFailed :
949
- LOGGER .error ("Failed to commission OTA Provider App!" )
950
- return None
951
- LOGGER .info (
952
- "OTA Provider App commissioned with node id %d." ,
953
- ota_provider_node_id ,
954
- )
955
-
956
- # Adjust ACL of OTA Requestor such that Node peer-to-peer communication
957
- # is allowed.
958
- try :
959
- read_result = await self .chip_controller .ReadAttribute (
960
- ota_provider_node_id , [(0 , Clusters .AccessControl .Attributes .Acl )]
961
- )
962
- acl_list = cast (
963
- list ,
964
- read_result [0 ][Clusters .AccessControl ][
965
- Clusters .AccessControl .Attributes .Acl
966
- ],
967
- )
968
-
969
- # Add new ACL entry...
970
- acl_list .append (
971
- Clusters .AccessControl .Structs .AccessControlEntryStruct (
972
- fabricIndex = 1 ,
973
- privilege = 3 ,
974
- authMode = 2 ,
975
- subjects = Types .NullValue ,
976
- targets = [
977
- Clusters .AccessControl .Structs .AccessControlTargetStruct (
978
- cluster = 41 , endpoint = 0 , deviceType = Types .NullValue
979
- )
980
- ],
981
- )
982
- )
983
-
984
- # And write. This is persistent, so only need to be done after we commissioned
985
- # the OTA Provider App.
986
- write_result : Attribute .AttributeWriteResult = (
987
- await self .chip_controller .WriteAttribute (
988
- ota_provider_node_id ,
989
- [(0 , Clusters .AccessControl .Attributes .Acl (acl_list ))],
990
- )
991
- )
992
- if write_result [0 ].Status != Status .Success :
993
- logging .error (
994
- "Failed writing adjusted OTA Provider App ACL: Status %s." ,
995
- str (write_result [0 ].Status ),
996
- )
997
- await self .remove_node (ota_provider_node_id )
998
- raise UpdateError ("Error while setting up OTA Provider." )
999
- except ChipStackError as ex :
1000
- logging .exception ("Failed adjusting OTA Provider App ACL." , exc_info = ex )
1001
- await self .remove_node (ota_provider_node_id )
1002
- raise UpdateError ("Error while setting up OTA Provider." ) from ex
1003
-
1004
- self ._ota_provider .set_node_id (ota_provider_node_id )
1017
+ await self ._initialize_ota_provider (self ._ota_provider )
1005
1018
1006
- # Notify node about the new update!
1019
+ # Notify update node about the availability of the OTA Provider. It will query
1020
+ # the OTA provider and start the update.
1007
1021
try :
1008
1022
await self .chip_controller .SendCommand (
1009
1023
nodeid = node_id ,
0 commit comments