This document lists the channels used by the plugin, as well as their respective methods and errors
All methods can throw a notImplemented
error if the native plugin doesn't listen to it.
The methods that requires parameters can throw two more errors:
missingArguments
errorDecoding
await widget.nordicNrfMesh.platformVersion;
This method returns a string e.g. "iOS 11.0"
Loads the Mesh Network configuration from the storage.
meshManagerApi.loadMeshNetwork();
This method returns nothing
Format :
{
eventName: onNetworkLoaded
id: $network.meshUUID
}
Format :
{
eventName: onNetworkLoadFailed
error: $error
}
-
loading fails
-
add appKey fails (when generating)
- MeshNetworkError.invalidKey
- MeshNetworkError.noNetworkKey
- MeshNetworkError.keyIndexOutOfRange
-
saving network fails (when generating)
-
network is null after loading or generating (should not happen)
case dataCorrupted(DecodingError.Context) An indication that the data is corrupted or otherwise invalid.
case keyNotFound(CodingKey, DecodingError.Context) An indication that a keyed decoding container was asked for an entry for the given key, but did not contain one.
case typeMismatch(Any.Type, DecodingError.Context) An indication that a value of the given type could not be decoded because it did not match the type of what was found in the encoded payload.
case valueNotFound(Any.Type, DecodingError.Context) An indication that a non-optional value of the given type was expected, but a null value was found.
Imports the Mesh Network configuration from the given Data.
await meshManagerApi.importMeshNetworkJson(json);
This method returns nothing
{
json: String
}
Format :
{
eventName: onNetworkImported
id: $network.meshUUID
}
Format :
{
eventName: onNetworkImportFailed
error: $error
}
Possible errors :
case dataCorrupted(DecodingError.Context)
An indication that the data is corrupted or otherwise invalid.
case keyNotFound(CodingKey, DecodingError.Context)
An indication that a keyed decoding container was asked for an entry for the given key, but did not contain one.
case typeMismatch(Any.Type, DecodingError.Context)
An indication that a value of the given type could not be decoded because it did not match the type of what was found in the encoded payload.
case valueNotFound(Any.Type, DecodingError.Context)
An indication that a non-optional value of the given type was expected, but a null value was found.
🚧🚧🚧 Not implemented in sample app 🚧🚧🚧
Use this to delete the local database
This method returns nothing
{
id: String
}
🚧🚧🚧 Delete callbacks not implemented 🚧🚧🚧
Returns the exported Mesh Network configuration as a string UTF8 encoded. The returned Data can be transferred to another application and imported. The JSON is compatible with Bluetooth Mesh scheme.
meshManagerApi.exportMeshNetwork();
🚧🚧🚧 Export callbacks not implemented 🚧🚧🚧
JSONEncoder.encode() errors :
case invalidValue(Any, EncodingError.Context)
An indication that an encoder or its containers could not encode the given value.
This method initializes the provisioning of the device.
{
serviceUuid: String
}
Possible errors :
-
create ProvisioningManager :
MeshNetworkError.noNetwork
-
identify :
// Does the Bearer support provisioning? guard bearer.supports(.provisioningPdu) else { logger?.e(.provisioning, "Bearer does not support provisioning PDU") throw BearerError.pduTypeNotSupported } // Has the provisioning been restarted? if case .fail = state { reset() } // Is the Provisioner Manager in the right state? guard case .ready = state else { logger?.e(.provisioning, "Provisioning manager is in invalid state") throw ProvisioningError.invalidState } // Is the Bearer open? guard bearer.isOpen else { logger?.e(.provisioning, "Bearer closed") throw BearerError.bearerClosed }
-
send provisioningInvite :
guard supports(type) else { throw BearerError.pduTypeNotSupported } guard isOpen else { throw BearerError.bearerClosed } guard let dataInCharacteristic = dataInCharacteristic else { throw GattBearerError.deviceNotSupported }
Callback called when a packet has been received using the Bearer.
meshManagerApi.handleNotifications(event.mtu, event.pdu);
This method returns nothing
{
mtu: Int
pdu: Data
}
Possible errors :
🚧 Not implemented 🚧
- we could have an unknownPdu error, but nothing else on iOS side. The native method doesn't throw and returns void.
This method returns nothing
{
mtuSize: Int
}
🚧 Useless on iOS ? To verify 🚧
This method reset the unprovisionedDevices list from the current provisioner.
This method returns nothing, no errors are thrown
This method starts the provisioning of the device. 'identifyNode' must be called prior to this to receive the device capabilities
CFErrors on calculateSharedSecret() if needed, not implemented for now
/// Thrown when the ProvisioningManager is in invalid state.
case invalidState
/// The received PDU is invalid.
case invalidPdu
/// Thrown when an unsupported algorighm has been selected for provisioning.
case unsupportedAlgorithm
/// Thrown when the Unprovisioned Device is not supported by the manager.
case unsupportedDevice
/// Thrown when the provided alphanumberic value could not be converted into
/// bytes using ASCII encoding.
case invalidOobValueFormat
/// Thrown when no available Unicast Address was found in the Provisioner's
/// range that could be allocated for the device.
case noAddressAvailable
/// Throws when the Unicast Address has not been set.
case addressNotSpecified
/// Throws when the Network Key has not been set.
case networkKeyNotSpecified
/// Thrown when confirmation value received from the device does not match
/// calculated value. Authentication failed.
case confirmationFailed
/// Thrown when the remove device sent a failure indication.
case remoteError(_ error: RemoteProvisioningError)
/// Thrown when the key pair generation has failed.
case keyGenerationFailed(_ error: OSStatus)
🚧🚧🚧 Uniformiser ou retirer si inutile 🚧🚧🚧
case .capabilitiesReceived(_):
return "PROVISIONING_CAPABILITIES"
case .ready:
return "PROVISIONER_READY"
case .requestingCapabilities:
return "REQUESTING_CAPABILITIES"
case .provisioning:
return "PROVISIONING"
default:
return ""
Errors :
-
Custom :
DoozProvisioningManagerError.provisioningManagerDoesNotExist
-
All the bearer.send errors
guard supports(type) else { throw BearerError.pduTypeNotSupported } guard isOpen else { throw BearerError.bearerClosed } guard let dataInCharacteristic = dataInCharacteristic else { throw GattBearerError.deviceNotSupported } guard let networkManager = networkManager, let meshNetwork = meshNetwork else { print("Error: Mesh Network not created") throw MeshNetworkError.noNetwork } guard let localNode = meshNetwork.localProvisioner?.node, let source = localElement ?? localNode.elements.first else { print("Error: Local Provisioner has no Unicast Address assigned") throw AccessError.invalidSource } guard source.parentNode == localNode else { print("Error: The Element does not belong to the local Node") throw AccessError.invalidElement } guard initialTtl == nil || initialTtl == 0 || (2...127).contains(initialTtl!) else { print("Error: TTL value \(initialTtl!) is invalid") throw AccessError.invalidTtl }
✅ createMeshPduForConfigCompositionDataGet(_ data: CreateMeshPduForConfigCompositionDataGetArguments)
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
dest: Int16
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigCompositionDataStatus"
source: UInt16
message: {
source: UInt16
destination: UInt16
}
}
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
dest: Int16
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigAppKeyStatus"
source: UInt16
message: {
source: UInt16
destination: UInt16
}
}
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
nodeId: Int16
elementId: Int16
modelId: UInt32
appKeyIndex: Int16
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigModelAppStatus"
elementAddress: UInt16
modelId: UInt16
appKeyIndex: UInt16
}
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
address: Int16
level: Int16
keyIndex: Int16
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onGenericLevelStatus"
level: Int16
targetLevel: Int16 // default is 0 ❌
source: UInt16
destination: UInt16
}
🚧🚧🚧 Standardize source + destination with key "message: {source:destination:}" as in other messages callbacks ? 🚧🚧🚧
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
address: Int16
value: Bool
keyIndex: Int16
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigModelAppStatus"
elementAddress: UInt16
modelId: UInt16
appKeyIndex: UInt16
}
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
address: Int16
elementAddress: Int16
subscriptionAddress: Int16
modelIdentifier: UInt32
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigModelAppStatus"
elementAddress: UInt16
modelId: UInt16
appKeyIndex: UInt16
}
This method returns nothing
🚧🚧🚧 Standardize name "create" vs "send" between different messages methods ? 🚧🚧🚧
{
address: Int16
elementAddress: Int16
subscriptionAddress: Int16
modelIdentifier: UInt32
}
Listen to onMeshPduCreated
to get the message to send via FlutterBlue
Format :
{
eventName: "onConfigModelAppStatus"
elementAddress: UInt16
modelId: UInt16
appKeyIndex: UInt16
}
Returns sequence number of the element with specified address
{
address: Int16
}
Errors :
network does not exist node with specified address does not exist
If method isn't implemented in native part
notImplemented
Errors on arguments:
missingArguments
errorDecoding
await meshManagerApi.meshNetwork.meshUUID;
Returns meshNetwork.meshUUID as String or null ❌
No errors thrown
await meshManagerApi.meshNetwork.name;
Returns meshNetwork.name as String or null ❌
No errors thrown
await meshManagerApi.meshNetwork.highestAllocatableAddress;
Returns the highestAllocatableAddress as Int. Default is 0. ❌
No errors thrown
await meshManagerApi.meshNetwork.nodes;
Returns an array of provisioned nodes uuid
Format :
[
{
uuid: String
},
{
...
}
]
EventSinkKeys.network.uuid.rawValue: device.node.uuid.uuidString
No errors thrown
await widget.meshManagerApi.meshNetwork.selectedProvisionerUuid();
Returns meshNetwork.localProvisioner.uuid.uuidString as String or null ❌
No errors thrown
await widget.meshManagerApi.meshNetwork.addGroupWithName(name)
Adds a new Group to the network.
{
name: String
}
Returns the newly added group infos
Format :
{
group: {
name: String,
address: UInt16,
addressLabel: String,
parentAddress: UInt16,
parentAddressLabel: String
},
successfullyAdded: Bool
}
Errors:
throw MeshNetworkError.groupAlreadyExists
await meshManagerApi.meshNetwork.groups;
Returns an array of the meshNetwork groups infos
Format :
[
group: {
name: String,
address: UInt16,
addressLabel: String,
parentAddress: UInt16,
parentAddressLabel: String
},
{
...
}
]
No errors thrown
Remove the Group from the network.
await widget.meshManagerApi.meshNetwork.removeGroup(parameters)
Returns a boolean (true if removed, false otherwise)
{
groupAddress: Int16
}
Errors:
throw MeshNetworkError.groupInUse group does not exist 🚧 Not implemented 🚧
await meshNetwork.elementsForGroup(parameters)
Returns an array of the designated group elements infos
{
address: Int16
}
🚧🚧🚧 Standardize key between getElementsForGroup and removeGroup (address vs groupAddress) 🚧🚧🚧
Errors:
throw MeshNetworkError.groupInUse group does not exist 🚧 Not implemented, that's a possibility 🚧
await node.unicastAddress;
Returns the unicastAddress of the node as UInt16
No errors thrown
Set the name of a node
await node.nodeName(parameters);
{
address: Int16
}
Returns nothing
No errors thrown
🚧🚧🚧 We should return a boolean indicating if the method succeed or failed (can we know it ?) 🚧🚧🚧
await node.name;
Returns the name of the node as String ❌ default is null
No errors thrown
await node.elements;
Returns an array of the node's elements infos
Format :
[
key: UInt8, // Numeric order of the Element within this Node.
address: UInt16,
locationDescriptor: UInt16,
models: [
key: UInt8,
modelId: UInt16,
subscribedAddresses: [
UInt16,
...
],
boundAppKey: [
UInt8,
...
]
],
...
]
No errors thrown
🚧 Not implemented 🚧
await unprovisionedMeshNode.getNumberOfElements();
Returns the number of elements of this unprovisionedDevice as UInt8
Format :
{
eventName: onMeshPduCreated
pdu: $data
}
Response :
bleMeshManager.callbacks.onDataReceived(mtu, pdu)
This call is dispatched to handleNotification for native processing
The native part is responding through the methods calls respective response (onConfigModelAppStatus / onConfigCompositionDataStatus etc...)
See each method documentation for information about the response event name.
Possible errors :
-
All the errors priori to bearer.send :
guard let networkManager = networkManager, let meshNetwork = meshNetwork else { print("Error: Mesh Network not created") throw MeshNetworkError.noNetwork } guard let localNode = meshNetwork.localProvisioner?.node, let source = localElement ?? localNode.elements.first else { print("Error: Local Provisioner has no Unicast Address assigned") throw AccessError.invalidSource } guard source.parentNode == localNode else { print("Error: The Element does not belong to the local Node") throw AccessError.invalidElement } guard initialTtl == nil || initialTtl == 0 || (2...127).contains(initialTtl!) else { print("Error: TTL value \(initialTtl!) is invalid") throw AccessError.invalidTtl }
public enum MeshNetworkError: Error {
/// Thrown when any allocated range of the new Provisioner overlaps
/// with existing one.
case overlappingProvisionerRanges
/// Thrown when trying to add a Provisioner that is already a part
/// of another mesh network.
case provisionerUsedInAnotherNetwork
/// Thrown when a new Provisioner has the same UUID as one node that
/// is already in the mesh network.
case nodeAlreadyExist
/// Thrown when a node cannot be added due to lack of available
/// addresses in Provisioner's range.
case noAddressAvailable
/// Thrown when the address cannot be assigne as it is being used by
/// another node.
case addressNotAvailable
/// Thrown when the address is of a wrong type.
case invalidAddress
/// Thrown when a node cannot be added due to its address not being
/// inside Provisioner's unicast address range.
case addressNotInAllocatedRange
/// Thrown when the requested Provisioner is not in the Mesh Network.
case provisionerNotInNetwork
/// Thrown when the range to be allocated is of invalid type.
case invalidRange
/// Thrown when the provided key is not 128-bit long.
case invalidKey
/// Thrown when trying to remove a key that is being used by some node.
case keyInUse
/// Thrown when a new Group is being added with the same address as one
/// that is already in the network.
case groupAlreadyExists
/// Throw when trying to remove a Group that is either a parent of another
/// Group, or set as publication or subcription address for any Model.
case groupInUse
/// Thrown when the given Key Index is not valid.
case keyIndexOutOfRange
/// Thrown when Network Key is required to continue with the operation.
case noNetworkKey
/// Thrown when Application Key is required to continue with the operation.
case noApplicationKey
/// Thrown when trying to send a mesh message before setting up the mesh network.
case noNetwork
}
public enum MeshMessageError: Error {
case invalidAddress
case invalidPdu
case invalidOpCode
}
public enum LowerTransportError: Error {
/// The segmented message has not been acknowledged before the timeout occurred.
case timeout
/// The target device is busy at the moment and could not accept the message.
case busy
/// Thrown internally when a possible replay attack was detected.
/// This error is not propagated to higher levels, the packet is
/// being discarded.
case replayAttack
}
public enum GattBearerError: Error {
/// The connected device does not have services required
/// by the Bearer.
case deviceNotSupported
}
public enum BearerError: Error {
/// Thrown when the Central Manager is not in ON state.
case centralManagerNotPoweredOn
/// Thrown when the given PDU type is not supported
/// by the Bearer.
case pduTypeNotSupported
/// Thrown when the Bearer is not ready to send data.
case bearerClosed
}
public enum AccessError: Error {
/// Error thrown when the local Provisioner does not have
/// a Unicast Address specified and is not able to send
/// requested message.
case invalidSource
/// Thrown when trying to send a message using an Element
/// that does not belong to the local Provisioner's Node.
case invalidElement
/// Throwm when the given TTL is not valid. Valid TTL must
/// be 0 or in range 2...127.
case invalidTtl
/// Thrown when the destination Address is not known and the
/// library cannot determine the Network Key to use.
case invalidDestination
/// Thrown when trying to send a message from a Model that
/// does not have any Application Key bound to it.
case modelNotBoundToAppKey
/// Error thrown when the Provisioner is trying to delete
/// the last Network Key from the Node.
case cannotDelete
/// Thrown, when the acknowledgment has not been received until
/// the time run out.
case timeout
}
enum FlutterCallError: Error{
case missingArguments
case notImplemented
case errorDecoding
}
enum DoozMeshManagerApiError: Error{
case errorLoadingMeshNetwork
case errorSavingMeshNetwork
}