nRF ios Provision localElements Publish setting

I am using nrf provision ios library to write an iOS app for our ble mesh nrf based device. 

I have everything working, but to publish from the phone to the device, the local node has to be configured. The localElements of the MeshNetworkManager are not loaded with after reloading the saved network info. This makes it so that I have to repopulate the localElements on app load every time.

This is slow because I have to send Config messages for all my elements to my local node (on phone). Is there any way to set the publish values of the local elements without having to publish a message to the phone? It seems like the node.publish() setting is not accessible, even for the local node.

  • Let me put it this way, why is the Model.delegate property a `let` instead of `var`?

    Whenever I start my app I feel like I should only have to run:
    ```

        func repopulateElements(_ network: MeshNetwork) {

            print("Repopulating local elements")

            guard let localNode = network.localProvisioner?.node else {

                print("Local node is nil")

                return

            }

            self.meshNetworkManager.localElements = localNode.elements

            // Update delegate for existing local Elements and Models

            for element in self.meshNetworkManager.localElements {

                for model in element.models {

                    let delegate: ModelDelegate?

                    switch model.modelIdentifier {

                    case .genericLevelClientModelId:

                        delegate = GenericLevelClientDelegate(meshNetworkManager: self.meshNetworkManager)

                    case .genericOnOffClientModelId:

                        delegate = GenericOnOffClientDelegate(meshNetworkManager: self.meshNetworkManager)

                    default:

                        delegate = nil

                    }

                    

                    model.delegate = delegate

                }

            }

        }

    ```


    Instead I have to run this code:


    ```

        func repopulateElements(_ network: MeshNetwork) {

            print("Repopulating local elements")

            

            guard let localNode = network.localProvisioner?.node else {

                print("Local node is nil")

                return

            }

            

            var rebuiltElements: [Element] = []

            

            func rebuildModel(models: [Model]) -> [Model] {

                var rebuiltModels: [Model] = []

                

                for model in models {

                    let delegate: ModelDelegate

                    switch model.modelIdentifier {

                    case .genericLevelClientModelId:

                        delegate = GenericLevelClientDelegate(meshNetworkManager: self.meshNetworkManager)

                    case .genericOnOffClientModelId:

                        delegate = GenericOnOffClientDelegate(meshNetworkManager: self.meshNetworkManager)

                    default:

                        continue

                    }

                    

                    let rebuiltModel = Model(sigModelId: model.modelIdentifier, delegate: delegate)

                    rebuiltModels.append(rebuiltModel)

                }

                

                return rebuiltModels

            }

            // First, rebuild all Elements and Models

            for element in localNode.elements {

                let rebuiltModels = rebuildModel(models: element.models)

                if !rebuiltModels.isEmpty {

                    // Assuming you can create a new Element with models

                    let rebuiltElement = Element(name: element.name, location: .first, models: rebuiltModels)

                    rebuiltElements.append(rebuiltElement)

                }

            }

            self.meshNetworkManager.localElements = rebuiltElements

            _ = self.meshNetworkManager.save()

            

            // Function to run setup sequentially

            func runSequentialSetup(for models: [Model], completion: @escaping () -> Void) {

                var remainingModels = models

                func nextSetup() {

                    guard !remainingModels.isEmpty else {

                        completion()

                        return

                    }

                    

                    let model = remainingModels.removeFirst()

                    

                    guard let publicationAddress = model.publish?.publicationAddress else {

                        print("ERROR: no publish object found for model \(model.modelIdentifier)")

                        nextSetup() // Continue with the next model setup

                        return

                    }

                    print("Running setup for model \(model.modelIdentifier)")

                    let setup = GenericModelLocalClientSetup(

                        model: model,

                        publicationAddress: publicationAddress,

                        onSetupComplete: {

                            nextSetup() // Continue with the next model setup when this one is complete

                        },

                        manager: self.meshNetworkManager

                    )

                    self.storedDelegate = setup

                    self.meshNetworkManager.delegate = setup

                    setup.startSetup()

                }

                

                nextSetup()

            }

            

            // Run setup sequentially for each Element

            var remainingElements = rebuiltElements

            func runSetupForNextElement() {

                guard !remainingElements.isEmpty else {

                    print("Local Models/Elements rebuilt and setup")

                    return

                }

                

                let element = remainingElements.removeFirst()

                runSequentialSetup(for: element.models) {

                    runSetupForNextElement()

                }

            }

            

            runSetupForNextElement()

        }

    class GenericModelLocalClientSetup: MeshNetworkDelegate {

        

        var onSetupComplete: (() -> Void)?

        private var address: MeshAddress

        private var model: Model

        private var manager: MeshNetworkManager

        

        init(model: Model, publicationAddress: MeshAddress, onSetupComplete: @escaping () -> Void, manager: MeshNetworkManager) {

            self.address = publicationAddress

            self.model = model

            self.onSetupComplete = onSetupComplete

            self.manager = manager

        }

        

        func startSetup() {

            // NEED TO ADD THE MODEL TO THE PARENT ELEMENT BEFORE SENDING THESE

            let bind = ConfigModelAppBind(applicationKey: manager.meshNetwork!.applicationKeys.first!, to: model)!

            try! manager.sendToLocalNode(bind)

        }

        func meshNetworkManager(_ manager: MeshNetworkManager,

                                didReceiveMessage message: MeshMessage,

                                sentFrom source: Address,

                                to destination: Address) {

            print("Generic Model Setup received message: " + String(message.opCode) + " ModelId " + String(self.model.modelId))

            switch message {

            case _  as ConfigModelAppStatus:

                let publicationMessage = ConfigModelPublicationSet(

                    Publish(

                        to: address,

                        using: manager.meshNetwork!.applicationKeys.first!,

                        usingFriendshipMaterial: false, ttl: 5,

                        period: .disabled,

                        retransmit: Publish.Retransmit(1, timesWithInterval: 0.2)

                    ),

                    to: model)!

                try! manager.sendToLocalNode(publicationMessage)

            case _ as ConfigModelPublicationStatus:

                print("Completed local client model setup! ModelId " + String(self.model.modelId))

                onSetupComplete?()

            default:

                print("UNCHECKED MESSAGE")

            }

            print(message)

        }

        func meshNetworkManager(_ manager: MeshNetworkManager,

                                failedToSendMessage message: MeshMessage,

                                from localElement: Element,

                                to destination: Address,

                                error: Error) {

            print("MESH NETWORK ERROR MESSAGE")

            print(message)

            print(error)

        }

    }

    ```

  • Hi. 

    Forwarded your request to our mobile developers. 

    Will get back to you when I receive some feedback from them. 

    Br,
    Joakim

  • Hi.

    Sorry, I don't have anything for you yet. I'll ping our developers.

    Br,
    Joakim

Related