更新时间:2024-06-05 09:39:06下载pdf
通俗地讲,蓝牙 Mesh 就是把多个蓝牙单点设备组成一个 Mesh 网络,每个节点可以和别的节点自由通讯。通过手机直连 Mesh 网中任意一个设备,即能访问控制 Mesh 网中所有的设备。本文介绍涂鸦自研的蓝牙拓扑通信相关实现,更多有关蓝牙 Mesh 的概念介绍,请参考 蓝牙 Mesh(SIG)。
类名 | 说明 |
---|---|
ThingBLEMeshManager | 蓝牙 Mesh 封装 |
开启蓝牙 Mesh。
// 设置 SDK 开启 Mesh,需要在初始化的时候设置。
[[ThingSmartSDK sharedInstance] setValue:@(YES) forKey:@"bleMeshEnable"];
蓝牙 Mesh 的主要操作类都在 ThingSmartBleMesh.h
文件中。
一个家庭里可以拥有多个蓝牙 Mesh,但建议只创建一个 Mesh。创建前,请判断下是否已经创建,若尚未创建可以通过此方法进行创建。
蓝牙 Mesh 中所有操作都建立在家庭数据已经初始化的基础上。完全初始化家庭操作,请参考 家庭管理。
接口说明
+ (void)createBleMeshWithMeshName:(NSString *)meshName
homeId:(long long)homeId
success:(void(^)(ThingSmartBleMeshModel *meshModel))success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
meshName | Mesh 名字,用户自定义 |
homeId | 家庭 ID |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
ThingSmartHome *home = #<上文初始化的 home 实例>;
long long homeId = home.homeModel.homeId;
[ThingSmartBleMesh createBleMeshWithMeshName:@"yourMeshName" homeId:homeId success:^(ThingSmartBleMeshModel *meshModel) {
// success do...
} failure:^(NSError *error) {
NSLog(@"create mesh error: %@", error);
}];
此方法的 meshName
为自定义参数。建议您使用唯一参数进行设置,例如 mesh+<时间戳>
的形式。
接口说明
删除 Mesh 时,如果 Mesh 组里有子设备,会被同时移除。同时,Wi-Fi 连接器也一并移除掉。
- (void)removeMeshWithSuccess:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
self.mesh = #<ThingSmartBleMesh 实例>;
[self.mesh removeMeshWithSuccess:^{
// success do...
} failure:^(NSError *error) {
XCTFail(@"test remove mesh failure: %@", error);
}];
接口说明
通过初始化 home
实例后,可以查询到对应家庭下的 mesh
列表。
- (void)getMeshListWithSuccess:(void(^)(NSArray <ThingSmartBleMeshModel *> *list))success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
ThingSmartHome *home = #<home 实例>
[home getMeshListWithSuccess:^(NSArray<ThingSmartBleMeshModel *> *list) {
// success do
} failure:^(NSError *error) {
NSLog(@"get mesh list error: %@", error);
}];
接口说明
+ (instancetype)bleMeshWithMeshId:(NSString *)meshId homeId:(long long)homeId;
参数说明
参数 | 说明 |
---|---|
meshId | Mesh ID |
homeId | 当前家庭 ID |
示例代码
通过家庭(ThingSmartHome
实例)home
可以查询到类下的 meshModel
,再通过此进行创建。并且,在创建完成之后,赋值给当前的 ThingSmartUser
中,SDK 中以及上层封装以 ThingSmartUser
是否有值为判断基准。
// 如果还未查询 Mesh
if ([ThingSmartUser sharedInstance].meshModel == nil) {
ThingSmartHome *home = #<home 实例>
[home getMeshListWithSuccess:^(NSArray<ThingSmartBleMeshModel *> *list) {
if (list.count > 0) {
// 赋值
[ThingSmartUser sharedInstance].meshModel = home.meshModel;
[ThingSmartUser sharedInstance].mesh = [ThingSmartBleMesh bleMeshWithMeshId:home.meshModel.meshId homeId:home.meshModel.homeId];
// 接下来的操作
} else {
// 如果云端没有 Mesh 信息,则为用户创建 Mesh
NSTimeInterval interval = [[NSDate date] timeIntervalSince1970];
NSString *meshName = [NSString stringWithFormat:@"tymesh%.0f", interval];
[ThingSmartBleMesh createBleMeshWithMeshName:meshName homeId:home.homeModel.homeId success:^(ThingSmartBleMeshModel *meshModel) {
// 赋值
[ThingSmartUser sharedInstance].meshModel = meshModel;
[ThingSmartUser sharedInstance].mesh = [ThingSmartBleMesh bleMeshWithMeshId:meshModel.meshId homeId:home.homeModel.homeId];
// 接下来的操作
} failure:^(NSError *error) {
// 错误处理
}];
}
} failure:^(NSError *error) {
// 错误处理
}];
} else {
// 接下来的操作
}
入网是对通过已配网设备连入蓝牙 Mesh 网的操作,该过程需要开启蓝牙。
接口说明
若操作为配网,填入默认的 Mesh name
和 password
,此时只会通过 ThingBLEMeshManagerDelegate
中的
- (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device;
返回扫描结果。
若操作为入网,填入已创建的 Mesh name
和 password
,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 Mesh 网中的各个设备在线情况。
- (void)startScanWithName:(NSString *)name
pwd:(NSString *)pwd
active:(BOOL)active
wifiAddress:(uint32_t)wifiAddress
otaAddress:(uint32_t)otaAddress;
参数说明
参数 | 说明 |
---|---|
name | Mesh 名称 |
pwd | Mesh 密码 |
active | 是否为配网激活 |
wifiAddress | Wi-Fi 地址,网关配网需要,其余情况传 0 |
otaAddress | 待 OTA 升级的设备地址,OTA 升级时需要使用该参数,其余情况传 0 |
回调接口
入网成功会自动查询 Mesh 网中设备的在线状态,并触发 ThingSmartHomeDelegate
代理方法进行回调信息.
// 设备信息更新,例如 name
- (void)home:(ThingSmartHome *)home deviceInfoUpdate:(ThingSmartDeviceModel *)device;
示例代码
// 注意,此时的 active、wifiAddress、otaAddress 参数赋值情况
[[ThingBLEMeshManager sharedInstance] startScanWithName:[ThingSmartUser sharedInstance].meshModel.code pwd:[ThingSmartUser sharedInstance].meshModel.password active:NO wifiAddress:0 otaAddress:0];
// 设备信息更新,例如 name
- (void)home:(ThingSmartHome *)home deviceInfoUpdate:(ThingSmartDeviceModel *)device {
// 收到回调操作
}
配网指的是将处于重置状态、未入网的设备,添加到蓝牙 Mesh 网中。蓝牙 Mesh 配网主要分为两种:
蓝牙 Mesh 的操作类集中在 ThingBLEMeshManager
中,且此类为单例。
处于重置状态的设备,默认名字为 out_of_mesh
,默认密码为 123456
。下表列举了常用设备的重置方式:
产品类型 | 重置操作 | 可配网现象 |
---|---|---|
照明 | 连续开关三次 | 灯快闪 |
插座 | 长按开关 3 秒 | 插座指示灯快闪 |
网关 | 长按开关 3 秒 | 红灯和蓝灯快闪 |
低功耗设备 | 长按开关 3 秒 | 再按一次出现长亮即可配网,且配网需在灯亮期间完成 |
报警器 | 长按开关 3 秒 | 灯快闪 |
为了简化扫描以及后续的配网操作,涂鸦将所有的操作统一封装在一个接口中进行操作。
若操作为配网,填入默认的 Mesh name
和 password
,此时只会通过 ThingBLEMeshManagerDelegate
中的
- (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device;
返回扫描结果。
若操作为入网,填入已创建的 Mesh name
和 password
,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 Mesh 网中的各个设备在线情况。
接口说明
- (void)startScanWithName:(NSString *)name
pwd:(NSString *)pwd
active:(BOOL)active
wifiAddress:(uint32_t)wifiAddress
otaAddress:(uint32_t)otaAddress;
参数说明
参数 | 说明 |
---|---|
name | Mesh 名称 |
pwd | Mesh 密码 |
wifiAddress | Wi-Fi 地址,网关配网需要,其余情况传 0 |
otaAddress | 待 OTA 升级的设备地址,OTA 升级时需要使用该参数,其余情况传 0 |
回调接口
若传入的 name
为默认值 out_of_mesh
,且为激活操作,会扫描周围待配网的设备。扫描的结果会以 ThingBLEMeshManagerDelegate
中的方法进行回调。
如果为入网操作,则会自动进行后续操作,不会回调。调用入网接口的示例,可参考 Mesh 的连接与断开。
- (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device;
参数说明
参数 | 说明 |
---|---|
manager | Mesh 管理器 |
device | 待配网设备信息 |
示例代码
// 开始扫描待配网的设备
[[ThingBLEMeshManager sharedInstance] startScanWithName:@"out_of_mesh" pwd:@"123456" active:YES wifiAddress:0 otaAddress:0];
// ThingBLEMeshManagerDelegate 扫描回调方法
- (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device {
// 扫描到的网关设备和子设备都会通过此方法进行回调
// 通过 device.type 和 device.vendorInfo 来判定是否为 Mesh 网关
if (device.type == [TPUtils getIntValueByHex:@"0x0108"] || ([TPUtils getIntValueByHex:[device.vendorInfo substringWithRange:NSMakeRange(0, 2)]] & 0x08) == 0x08) {
// Mesh 网关
return;
} else {
// Mesh 子设备
}
}
// getIntValueByHex 实现
+ (uint32_t)getIntValueByHex:(NSString *)getStr
{
NSScanner *tempScaner=[[NSScanner alloc] initWithString:getStr];
uint32_t tempValue;
[tempScaner scanHexInt:&tempValue];
return tempValue;
}
接口说明
- (void)activeMeshDeviceIncludeGateway:(BOOL)includeGateway;
参数说明
参数 | 说明 |
---|---|
includeGateway | 是否激活网关,若为 yes ,则会激活已记录扫描到设备中的网关设备,其余子设备不激活。反之,激活所有已扫描的普通 Mesh 子设备,不激活网关 |
回调接口
- (void)activeDeviceSuccessWithName:(NSString *)name deviceId:(NSString *)deviceId error:(NSError *)error;
参数说明
参数 | 说明 |
---|---|
name | 设备名称 |
deviceId | 设备 ID |
error | 激活中的错误,若发生错误,name 以及 deviceId 为空 |
接口说明
- (void)activeMeshDevice:(ThingBleMeshDeviceModel *)deviceModel;
参数说明
参数 | 说明 |
---|---|
deviceModel | 设备模型 |
配网结果会通过 ThingBLEMeshManagerDelegate
进行回调。
回调接口
- (void)activeWifiDeviceWithName:(NSString *)name address:(NSInteger)address mac:(NSInteger)mac error:(NSError *)error;
参数说明
参数 | 说明 |
---|---|
name | 设备名称 |
address | 设备地址 |
mac | 网关 Mac |
error | 激活中的错误 |
若激活的为网关设备,需要在收到回调 activeWifiDeviceWithName
方法过后,需要再进行与 Wi-Fi 模组进行配网。这时,您需要调用 ThingSmartActivator
中方法执行操作。
接口说明
配网 Token 的有效期为 10 分钟。
- (void)getTokenWithMeshId:(NSString *)meshId
nodeId:(NSString *)nodeId
productId:(NSString *)productId
uuid:(NSString *)uuid
authKey:(NSString *)authKey
version:(NSString *)version
success:(ThingSuccessString)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
meshId | Mesh ID |
nodeId | Node ID |
productId | 产品的 ID,即 PID(Product ID) |
uuid | 设备 uuid |
authKey | 设备 authKey |
success | 操作成功回调,返回配网 Token |
failure | 操作失败回调 |
传入配网 Token、路由器热点名称、路由器热点密码信息,进行 Mesh 网关配网。需要实现激活网关后,收到 ThingBLEMeshManagerDelegate
的 activeWifiDeviceWithName
回调,方可以调用此方法。
接口说明
- (void)startBleMeshConfigWiFiWithSsid:(NSString *)ssid
password:(NSString *)password
token:(NSString *)token
timeout:(NSTimeInterval)timeout;
参数说明
参数 | 说明 |
---|---|
ssid | 路由器热点名称 |
password | 路由器热点密码 |
token | 配网 Token |
timeout | 超时时间,默认为 100 秒 |
示例代码
// Mesh 子设备(不带网关的设备)入网
// 1. 激活子设备
[[ThingBLEMeshManager sharedInstance] activeMeshDeviceIncludeGateway:NO];
// 2. ThingBLEMeshManagerDelegate 回调
- (void)activeDeviceSuccessWithName:(NSString *)name deviceId:(NSString *)deviceId error:(NSError *)error {
if (error) {
NSLog(@"error : %@", error);
return;
}
// 3. 激活成功,至此,一个子设备激活完成
}
// 网关激活
// 1. 激活子设备
[[ThingBLEMeshManager sharedInstance] activeMeshDeviceIncludeGateway:NO];
// 2. ThingBLEMeshManagerDelegate 回调
- (void)activeWifiDeviceWithName:(NSString *)name address:(NSInteger)address mac:(NSInteger)mac error:(NSError *)error {
if (error) {
NSLog(@"error : %@", error);
return;
}
// 激活网关成功,目前只成功蓝牙模组,还需要继续配置 Wi-Fi 模组激活
// 3. 用户输入密码再去重连,重连成功后再发送 ssid, pwd, token,
// !注意,一定要做此操作,不然会影响 Wi-Fi 信息写入导致配网失败
[ThingBLEMeshManager sharedInstance].wifiMac = (int)mac;
// 4. 查询 token
NSString *nodeId = [NSString stringWithFormat:@"%02x", (int)address];
[[ThingSmartActivator sharedInstance] getTokenWithMeshId:[ThingSmartUser sharedInstance].meshModel.meshId
nodeId:nodeId
productId:[ThingBLEMeshManager sharedInstance].productId
uuid:[ThingBLEMeshManager sharedInstance].uuid
authKey:[ThingBLEMeshManager sharedInstance].authKey
version:[ThingBLEMeshManager sharedInstance].version
success:^(NSString *token) {
// 5. 设置配网代理,通过代理接收激活结果
[ThingSmartActivator sharedInstance].delegate = self;
// 6. 开始 Wi-Fi 配网
[[ThingSmartActivator sharedInstance] startBleMeshConfigWiFiWithSsid:@"Wi-Fi 名称" password:@"Wi-Fi 密码" token:token timeout:100];
} failure:^(NSError *error) {
NSLog(@"error: %@", error);
}];
}
- (void)meshActivator:(ThingSmartActivator *)activator didReceiveDeviceId:(NSString *)deviceId meshId:(NSString *)meshId error:(NSError *)error {
// 7. 收到激活结果
}
在操作的过程中,会经常判断是否是 Mesh 已有设备通过蓝牙入网,来决定使用何种方式下发控制命令和操作命令。
// Mesh 本地连接标识,有设备通过蓝牙连接,此属性为 yes
BOOL isLogin = [ThingBLEMeshManager sharedInstance].isLogin;
错误码 | 说明 |
---|---|
3088 | 激活设备失败 |
3090 | Mesh name 和 password 错误 |
3091 | 登录失败 |
3092 | 登录解密失败 |
3093 | 查询 auth key 失败 |
3094 | 地址超出限制 |
3095 | 修改地址失败 |
3096 | 写入 mesh 信息失败 |
3097 | Mesh 信息为空 |
3098 | Mesh 未入网 |
3099 | 写入失败 |
4000 | Wi-Fi 信息有误 |
4001 | Wi-Fi 配网 Token 错误 |
4010 | 登录超时 |
4011 | 查询 auth key 超时 |
4012 | 修改地址超时 |
4013 | 写入 Mesh 信息超时 |
4014 | 设置 Wi-Fi 信息超时 |
设备类是 ThingSmartDevice
,里面的 ThingSmartDeviceModel
中的 deviceType
信息可以区分设备类型。其中,Mesh 设备对应 deviceType
类型为 ThingSmartDeviceModelTypeSIGMeshSubDev
。
接口说明
- (void)renameMeshSubDeviceWithDeviceId:(NSString *)deviceId name:(NSString *)name success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
deviceId | 设备 ID |
name | 新的名字 |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
[[ThingSmartUser sharedInstance].mesh renameMeshSubDeviceWithDeviceId:self.device.devId name:name success:^{
// success do
} failure:^(NSError *error) {
// failure do
}];
向 Mesh 网络中加入设备(设备入网 2.0)
SDK 中配网时已自动处理,若无特殊必要,可忽略。
- (void)addSubDeviceWithUuid:(NSString *)uuid
homeId:(long long)homeId
authKey:(NSString *)authKey
nodeId:(NSString *)nodeId
productKey:(NSString *)productKey
ver:(NSString *)ver
success:(void (^)(NSString *devId, NSString *name))success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
uuid | 蓝牙子设备短地址标识 |
authKey | 授权 |
nodeId | Mesh 节点 ID(短地址) |
productKey | 产品 ID |
ver | 版本号 |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
[[ThingSmartUser sharedInstance].mesh addSubDeviceWithUuid:_uuid homeId:[ThingSmartUser sharedInstance].meshModel.homeId authKey:_authKey nodeId:nodeHex productKey:_selectedPeripheral.productId ver:_selectedPeripheral.version success:^(NSString *devId, NSString *name) {
// success do
} failure:^(NSError *error) {
// failure do
}];
Mesh 子设备的本地连接为在线情况的一种。手机蓝牙开启且 Mesh 子设备通过蓝牙进行连接控制,下发命令通过蓝牙完成。判断条件为 deviceModel.isOnline && deviceModel.isMeshBleOnline
。
Mesh 子设备的网关连接为在线情况的一种。手机蓝牙未开启或距离设备远,Mesh 设备通过网关进行连接控制,下发命令通过 Wi-Fi 完成。判断条件为 deviceModel.isOnline && !deviceModel.isMeshBleOnline
。
移除设备需要同时在云端和本地删除设备。
本地删除
// 通过蓝牙
- (void)kickoutLightWithAddress:(uint32_t)address type:(NSString *)type;
// 通过网关
- (NSString *)rawDataKickoutLightWithAddress:(uint32_t)address type:(NSString *)type;
/**
给设备发送透传指令
@param raw 透传值
@param success 操作成功的回调
@param failure 操作失败的回调
*/
- (void)publishRawDataWithRaw:(NSString *)raw
pcc:(NSString *)pcc
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
云端删除
- (void)removeMeshSubDeviceWithDeviceId:(NSString *)deviceId success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
deviceId | 设备 ID |
success | 操作成功回调 |
failure | 操作失败回调 |
代码示例
int address = [smartDevice.deviceModel.nodeId intValue] << 8;
// 1. 云端删除
[[ThingSmartUser sharedInstance].mesh removeMeshSubDeviceWithDeviceId:[smartDevice.deviceModel.devId success:^{
} failure:^(NSError *error) {
}];
// 2. 本地删除
// 判断连接情况,使用网关还是蓝牙
if ([ThingBLEMeshManager sharedInstance].isLogin) {
[[ThingBLEMeshManager sharedInstance] kickoutLightWithAddress:address type:[smartDevice.deviceModel.pcc];
} else {
[[ThingSmartUser sharedInstance].mesh publishRawDataWithRaw:[[ThingBLEMeshManager sharedInstance] rawDataKickoutLightWithAddress:address type:[smartDevice.deviceModel.pcc] pcc:[smartDevice.deviceModel.pcc success:^{
} failure:^(NSError *error) {
}];
}
接口说明
- (void)getDeviceStatusAllWithAddress:(uint32_t)address
type:(NSString *)type;
参数说明
参数 | 说明 |
---|---|
address | 设备地址 |
type | 设备的大小类 |
在蓝牙 Mesh 网中,可以将一些设备组成群组,使用群组命令控制群组中的设备。例如,将所有灯组添加到某个群组中,通过控制群组的开关、颜色等,直接控制群组中所有的灯具有相同的属性。
管理群组可以调用 ThingSmartBleMeshGroup
的以下方法。
创建时,群组地址的 localId
从 0x8001
开始,依次叠加。
群组的大小类和设备一样,传入表示此群组约定此类设备组建为群组
目前每个 Mesh 最多支持添加 255 个群组,1 个设备最多只能加入 8 个群组。
建议不要将不同品类的设备加入到同一个群组,否则,可能会因为设备功能的不同导致控制失败。
接口说明
+ (void)createMeshGroupWithGroupName:(NSString *)groupName
meshId:(NSString *)meshId
localId:(NSString *)localId
pcc:(NSString *)pcc
success:(ThingSuccessInt)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
groupName | Mesh 群组名字 |
meshId | Mesh ID |
localId | 群组的本地短地址 |
pcc | 群组设备大小类 |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
NSInteger localId = 0x8001;
[ThingSmartBleMeshGroup createMeshGroupWithGroupName:@<群组名称> meshId:[ThingSmartUser sharedInstance].meshModel.meshId localId:[NSString stringWithFormat:@"%lx", localId] pcc:#<群组的大小类> success:^(int result) {
// success do
// 可以查询到 group 实例
self.meshGroup = [ThingSmartBleMeshGroup meshGroupWithGroupId:result];
} failure:^(NSError *error) {
// failure do
}];
向群组内加设备,需要经过本地和云端双重验证,才能算作一个设备成功加入到群组。添加设备时,请一个一个地进行,并按顺序执行。不要并发进行。
添加流程
接口说明
// 本地连接
// 添加设备到群组方法,该方法执行后会通过 ThingBLEMeshManagerDelegate 方法回调
- (void)addDeviceAddress:(uint32_t)deviceAddress type:(NSString *)type groupAddress:(uint32_t)groupAddress;
// ThingBLEMeshManagerDelegate
- (void)deviceAddGroupAddress:(uint32_t)address error:(NSError *)error;
// 网关连接
// 查询添加设备到群组命令 raw
- (NSString *)rawDataAddDeviceAddress:(uint32_t)deviceAddress groupAddress:(uint32_t)groupAddress type:(NSString *)type;
接口说明
给设备发送透传指令。
- (void)publishRawDataWithRaw:(NSString *)raw
pcc:(NSString *)pcc
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
//发送的 raw 消息会通过 `ThingSmartBleMeshDelegate` - (void)bleMeshReceiveRawData:(NSString *)raw 回调
// ThingSmartBleMeshDelegate
- (void)bleMeshReceiveRawData:(NSString *)raw;
参数说明
参数 | 说明 |
---|---|
raw | 透传值 |
success | 操作成功回调 |
failure | 操作失败回调 |
接口说明
待到上述验证完成后,可通过此方法将操作记录到云端后,可以进行下一个设备的操作。
- (void)addDeviceWithDeviceId:(NSString *)deviceId success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
- (void)addDeviceToGroup:(ThingSmartDeviceModel *)model {
int nodeId = [model.nodeId intValue] << 8;
// 记录当前设备的地址,作为后续判断
_address = nodeId >> 8;
if ([ThingBLEMeshManager sharedInstance].isLogin) {
// ble
[[ThingBLEMeshManager sharedInstance] addDeviceAddress:nodeId type:self.meshGroup.meshGroupModel.pcc groupAddress:[self.meshGroup.meshGroupModel.localId intValue]];
} else {
// wifi
[[ThingSmartUser sharedInstance].mesh publishRawDataWithRaw:[[ThingBLEMeshManager sharedInstance] rawDataAddDeviceAddress:nodeId groupAddress:[self.meshGroup.meshGroupModel.localId intValue] type:self.meshGroup.meshGroupModel.pcc] pcc:self.meshGroup.meshGroupModel.pcc success:^{
} failure:^(NSError *error) {
}];
}
// 标记当前操作为新增
_isAdd = YES;
// 这里可以自己做超时,建议为 5s 未收到表示失败,执行下一个
}
#pragma mark - ThingBLEMeshManagerDelegate
- (void)deviceAddGroupAddress:(uint32_t)address; {
NSLog(@" --- deviceAddGroupAddress %d ", address);
if (_address == address) {
[self.meshGroup addDeviceWithDeviceId:_devId success:^{
// 操作成功,执行下一个
} failure:^(NSError *error) {
}];
}
}
#pragma mark - ThingSmartBleMeshDelegate
// 网关连接下,组建群组会触发此方法
- (void)bleMeshReceiveRawData:(NSString *)raw {
if ([[raw substringWithRange:NSMakeRange(4, 2)] isEqualToString:@"d4"] && _address == [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(0, 2)]]) {
if (raw.length < 14) {
NSLog(@"raw 长度错误");
return;
}
BOOL isNewProtocol = [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(10, 2)]] == 255;
if (isNewProtocol) {
int state = [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(12, 2)]];
if (state == 1 || state == 255) {
NSLog(@"设备群组操作成功");
} else {
// 操作失败执行下一个
return;
}
}
[self.meshGroup addDeviceWithDeviceId:_devId success:^{
// 操作成功,执行下一个
} failure:^(NSError *error) {
}];
}
}
和向群组添加设备操作流程类似,从群组内删除设备,需要经过本地和云端双重验证,才能算作一个设备从群组内删除。移除设备时,请一个一个地进行,并按顺序执行。不要并发进行。
移除流程
接口说明
// 本地连接
// 删除群组内某个设备方法,该方法执行后会通过 ThingBLEMeshManagerDelegate 方法回调
- (void)deleteDeviceAddress:(uint32_t)deviceAddress type:(NSString *)type groupAddress:(uint32_t)groupAddress;
// ThingBLEMeshManagerDelegate
- (void)deviceAddGroupAddress:(uint32_t)address error:(NSError *)error;
// 网关连接
// 查询删除群组内设备命令 raw
- (NSString *)rawDataDeleteDeviceAddress:(uint32_t)deviceAddress groupAddress:(uint32_t)groupAddress type:(NSString *)type;
接口说明
- (void)publishRawDataWithRaw:(NSString *)raw
pcc:(NSString *)pcc
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
//发送的 raw 消息会通过 `ThingSmartBleMeshDelegate` - (void)bleMeshReceiveRawData:(NSString *)raw 回调
// ThingSmartBleMeshDelegate
- (void)bleMeshReceiveRawData:(NSString *)raw;
参数说明
参数 | 说明 |
---|---|
raw | 透传值 |
success | 操作成功回调 |
failure | 操作失败回调 |
接口说明
待到上述验证完成后,可通过此方法将操作记录到云端后,可以进行下一个设备的操作。
- (void)removeDeviceWithDeviceId:(NSString *)deviceId success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
deviceId | 设备 ID |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
- (void)deleteDeviceFromGroup:(ThingSmartDeviceModel *)model {
int nodeId = [model.nodeId intValue] << 8;
// 记录当前操作的设备地址,用于后续回调判断
_address = nodeId >> 8;
if ([ThingBLEMeshManager sharedInstance].isLogin) {
// ble
[[ThingBLEMeshManager sharedInstance] deleteDeviceAddress:nodeId type:self.meshGroup.meshGroupModel.pcc groupAddress:[self.meshGroup.meshGroupModel.localId intValue]];
} else {
// wifi
[[ThingSmartUser sharedInstance].mesh publishRawDataWithRaw:[[ThingBLEMeshManager sharedInstance] rawDataDeleteDeviceAddress:nodeId groupAddress:[self.meshGroup.meshGroupModel.localId intValue] type:self.meshGroup.meshGroupModel.pcc] pcc:self.meshGroup.meshGroupModel.pcc success:^{
} failure:^(NSError *error) {
}];
}
// 标记当前操作为删除
_isAdd = NO;
// 这里可以自己做超时,建议为 5s 未收到表示失败,执行下一个
}
#pragma mark - ThingBLEMeshManagerDelegate
- (void)deviceAddGroupAddress:(uint32_t)address; {
NSLog(@" --- deviceAddGroupAddress %d ", address);
if (_address == address) {
[self.meshGroup removeDeviceWithDeviceId:_devId success:^{
// 操作成功,执行下一个
} failure:^(NSError *error) {
}];
}
}
#pragma mark - ThingSmartBleMeshDelegate
// 网关连接下,组建群组会触发此方法
- (void)bleMeshReceiveRawData:(NSString *)raw {
if ([[raw substringWithRange:NSMakeRange(4, 2)] isEqualToString:@"d4"] && _address == [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(0, 2)]]) {
if (raw.length < 14) {
NSLog(@"raw 长度错误");
return;
}
BOOL isNewProtocol = [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(10, 2)]] == 255;
if (isNewProtocol) {
int state = [TPUtils getIntValueByHex:[raw substringWithRange:NSMakeRange(12, 2)]];
if (state == 1 || state == 255) {
NSLog(@"设备群组操作成功");
} else {
// 操作失败执行下一个
return;
}
}
[self.meshGroup removeDeviceWithDeviceId:_devId success:^{
// 删除成功,执行下一个
} failure:^(NSError *error) {
}];
}
}
接口说明
+ (instancetype)meshGroupWithGroupId:(NSInteger)groupId;
参数说明
参数 | 说明 |
---|---|
groupId | 群组 ID |
此处的 groupId
并非上面所述 localId
,是由添加群组成功之后,云端返回的群组 ID。并且注意,所有的群组操作下发的地址都只是和 localId
有关。
接口说明
- (void)updateMeshGroupName:(NSString *)meshGroupName success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
meshGroupName | Mesh 群组名称 |
success | 操作成功回调 |
failure | 操作失败回调 |
删除群组和添加或者移除设备一样,都需要经过本地删除和云端删除。
接口说明
// 本地删除
- (void)deleteGroupAddress:(uint32_t)groupAddress type:(NSString *)type;
// 网关连接
- (NSString *)rawDataDeleteGroupAddress:(uint32_t)groupAddress type:(NSString *)type
接口说明
// 给设备发送透传指令
- (void)publishRawDataWithRaw:(NSString *)raw
pcc:(NSString *)pcc
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
raw | 透传值 |
success | 操作成功回调 |
failure | 操作失败回调 |
接口说明
// 云端删除
- (void)removeMeshGroupWithSuccess:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
[self.meshGroup removeMeshGroupWithSuccess:^{
// 云端删除成功
} failure:^(NSError *error) {
// 云端删除失败
}];
// 如果是本地连接
if ([ThingBLEMeshManager sharedInstance].isLogin) {
// 通过蓝牙命令删除群组
[[ThingBLEMeshManager sharedInstance] deleteGroupAddress:[self.meshGroup.meshGroupModel.localId intValue] type:self.meshGroup.meshGroupModel.pcc];
} else {
// wifi
// 通过网关删除群组
[[ThingSmartUser sharedInstance].mesh publishRawDataWithRaw:[[ThingBLEMeshManager sharedInstance] rawDataDeleteGroupAddress:[self.meshGroup.meshGroupModel.localId intValue] type:self.meshGroup.meshGroupModel.pcc] pcc:self.meshGroup.meshGroupModel.pcc success:^{
} failure:^(NSError *error) {
}];
}
接口说明
- (void)getDeviveListInfoWithSuccess:(void (^)(NSArray <ThingSmartDeviceModel *> *deviceList))success failure:(ThingFailureError)failure;
示例代码
[self.meshGroup getDeviveListInfoWithSuccess:^(NSArray<ThingSmartDeviceModel *> *deviceList) {
// 查询成功
} failure:^(NSError *error) {
// 查询失败
}];
由于涂鸦使用 DP 管理设备的功能,因此,蓝牙 Mesh 相关的控制是根据设备的 DP 信息来进行操作。
Mesh 指令下发是根据设备的 DP 信息来进行操作。
发送控制指令按照以下格式:{"(dpId)" : "(dpValue)"}
, 如 @{@"101" : @"44"}
。DP 指令详情,请参考 设备控制。
接口说明
- (void)publishNodeId:(NSString *)nodeId
pcc:(NSString *)pcc
dps:(NSDictionary *)dps
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
nodeId | 蓝牙子设备短地址标识 |
pcc | 大小类标示 |
dps | 命令字典 |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
int address = [[self.smartDevice deviceModel].nodeId intValue] << 8;
[self.mesh publishNodeId:[NSString stringWithFormat:@"%d", address] pcc:self.smartDevice.deviceModel.pcc dps:@{@"1":@(1)} success:^{
// success do
} failure:^(NSError *error) {
// error do
}];
接口说明
- (void)multiPublishWithLocalId:(NSString *)localId
pcc:(NSString *)pcc
dps:(NSDictionary *)dps
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
localId | 群组的本地短地址 |
pcc | 大小类标示 |
dps | 命令字典 |
success | 操作成功回调 |
failure | 操作失败回调 |
示例代码
int address = [[self.meshGroup meshGroupModel].localId intValue];
[self.mesh multiPublishWithLocalId:[NSString stringWithFormat:@"%d", address] pcc:self.meshGroup.meshGroupModel.pcc dps:@{@"1":@(1)} success:^{
// success do
} failure:^(NSError *error) {
// error do
}];
ThingBLEMeshManager
类头中提供了一些设备的透传(raw)命令。
接口说明
- (void)publishRawDataWithRaw:(NSString *)raw
pcc:(NSString *)pcc
success:(ThingSuccessHandler)success
failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
raw | 透传值 |
success | 操作成功回调 |
failure | 操作失败回调 |
发送命令后,如果是有返回的命令,设备的数据回复通过 ThingSmartHomeDelegate
中代理回调。
接口说明
// 设备 DP 数据更新
- (void)home:(ThingSmartHome *)home device:(ThingSmartDeviceModel *)device dpsUpdate:(NSDictionary *)dps;
接口说明
- (void)getFirmwareUpgradeInfo:(void (^)(NSArray <ThingSmartFirmwareUpgradeModel *> *upgradeModelList))success failure:(ThingFailureError)failure;
/**
升级的信息会通过结果值返回,可以根据 type 信息去确定是否需要升级
0 升级中
1 无升级
2 有强制或提醒升级
3 有检测升级
判断为需要升级后,具体的固件地址在返回值中,下载之后转成 data 进行后续操作
*/
升级前需要确保蓝牙已开启,然后连接目标设备,准备升级。
若操作为配网,填入默认的 Mesh name
和 password
,此时只会通过 ThingBLEMeshManagerDelegate
中的
- (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device;
返回扫描结果。
若操作为入网,填入已创建的 Mesh name
和 password
,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 Mesh 网中的各个设备在线情况。
接口说明
- (void)startScanWithName:(NSString *)name
pwd:(NSString *)pwd
active:(BOOL)active
wifiAddress:(uint32_t)wifiAddress
otaAddress:(uint32_t)otaAddress;
参数说明
参数 | 说明 |
---|---|
name | Mesh 名称 |
pwd | Mesh 密码 |
active | 是否为配网激活 |
wifiAddress | Wi-Fi 地址,网关配网需要,其余情况传 0 |
otaAddress | 待 OTA 升级的设备地址,OTA 升级时需要使用该参数,其余情况传 0 |
设置后,会进行连接,通过 ThingBLEMeshManagerDelegate
代理方法可以收到连接情况。
接口说明
升级时,已成功连接到 Mesh 网。
- (void)notifyLoginSuccessWithAddress:(uint32_t)address;
参数说明
参数 | 说明 |
---|---|
address | 设备地址 |
收到回调后发送升级包
- (void)sendOTAPackWithAddress:(NSInteger)address version:(NSString *)version otaData:(NSData *)otaData success:(ThingSuccessHandler)success failure:(ThingFailureHandler)failure;
参数说明
参数 | 说明 |
---|---|
address | 设备地址 |
version | 版本号 |
otaData | 升级数据 |
success | 成功回调 |
failure | 失败回调 |
向云端更新版本号
- (void)updateDeviceVersion:(NSString *)version type:(NSInteger)type success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;
参数说明
参数 | 说明 |
---|---|
version | 版本号 |
type | 固件类型 |
success | 成功回调 |
failure | 失败回调 |
示例代码
1. 准备升级
int otaAddress = [self.device.deviceModel.nodeId intValue] << 8;
// 直连
[[ThingBLEMeshManager sharedInstance] startScanWithName:[ThingSmartUser sharedInstance].meshModel.code pwd:[ThingSmartUser sharedInstance].meshModel.password active:NO wifiAddress:0 otaAddress:otaAddress];
[ThingBLEMeshManager sharedInstance].delegate = self;
2. 回调并发送升级包
- (void)notifyLoginSuccessWithAddress:(uint32_t)address {
[[ThingBLEMeshManager sharedInstance] sendOTAPackWithAddress:address version:@"升级号" otaData:_otaData success:^{
[self updateVersion];
} failure:^{
NSLog(@"ota failure!");
}];
}
3. 向云端更新版本号
- (void)updateVersion {
WEAKSELF_AT
[self.smartDevice updateDeviceVersion:_upgradeModel.version type:_upgradeModel.type success:^{
// success do..
} failure:^(NSError *error) {
// error do..
}];
}
使用前,请先确定固件支持场景。
场景 1 到场景 4 是静彩模式。更改场景 1:
{set_scene1="0ff808000000000E0"}
0:表示是静彩模式
ff:R
80:G
80:B
00:W 暖
00:C 冷
00:L 亮度值
00:S step (暂时都设置为 0)
E0:V 有效性 (表示上方 RGBWCLS 的有效性 ) RGB 有效是 E0 WCL 有效是 1C
场景 5 到场景 8 是炫彩模式。更改场景 5:
{set_scene5="180ff560055AA0055AA"}
1:表示是炫彩模式
80:对于 HLS 中 L 亮度
ff:对应 HLS 中 S 饱和度
56:二进制 01010110,高 5bit 为渐变时间 time=10(单位为 200ms),对应真实时间为 10*200ms=2s;低 3bit 为渐变组数 group=6 组
00、55、AA、00、55、AA:对应 HLS 中 H 色相 6 组
根据上面的 L 和 S,再加上每组的 H,一共可以计算出六组 RGB 数据。
0 c7 ed cc c8 37 64 00 e0
进入场景 发送 null 查询 查询场景具体值
{set_scene1=null}
切换白光:109 = "white"
切换彩光:可以直接发 rgb 命令,也可发 109 = "colour"
切换场景 1:109 = "scene_1"
切换场景 2:109 = "scene_2"
切换场景 3:109 = "scene_3"
...
切换场景 8:109 = "scene_8"
设置场景 1 - 8:DP 依次为 111 - 118
例如设置场景 5:115 = "0f19ec27f806400e0"
其中格式可以按照之前的文档格式进行下发设置
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈