蓝牙 Mesh(涂鸦)

更新时间: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。创建前,请判断下是否已经创建,若尚未创建可以通过此方法进行创建。

蓝牙 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 时,如果 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);
}];

查询家庭中的 Mesh 列表

接口说明

通过初始化 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);
}];

查询蓝牙 Mesh 实例

接口说明

+ (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 网的操作,该过程需要开启蓝牙。

接口说明

  • 若操作为配网,填入默认的 Mesh namepassword,此时只会通过 ThingBLEMeshManagerDelegate 中的
    - (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device; 返回扫描结果。

  • 若操作为入网,填入已创建的 Mesh namepassword,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 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 子设备。例如灯、插座、低功耗等,可以理解为只要不带网关,就是普通蓝牙设备。
  • 一种是对 Mesh 网关配网。

蓝牙 Mesh 的操作类集中在 ThingBLEMeshManager 中,且此类为单例。

重置设备

处于重置状态的设备,默认名字为 out_of_mesh,默认密码为 123456。下表列举了常用设备的重置方式:

产品类型 重置操作 可配网现象
照明 连续开关三次 灯快闪
插座 长按开关 3 秒 插座指示灯快闪
网关 长按开关 3 秒 红灯和蓝灯快闪
低功耗设备 长按开关 3 秒 再按一次出现长亮即可配网,且配网需在灯亮期间完成
报警器 长按开关 3 秒 灯快闪

扫描待配网子设备

为了简化扫描以及后续的配网操作,涂鸦将所有的操作统一封装在一个接口中进行操作。

  • 若操作为配网,填入默认的 Mesh namepassword,此时只会通过 ThingBLEMeshManagerDelegate 中的
    - (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device; 返回扫描结果。

  • 若操作为入网,填入已创建的 Mesh namepassword,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 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 激活中的错误

Mesh 网关查询配网 Token

若激活的为网关设备,需要在收到回调 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 操作失败回调

Mesh 网关配网

传入配网 Token、路由器热点名称、路由器热点密码信息,进行 Mesh 网关配网。需要实现激活网关后,收到 ThingBLEMeshManagerDelegateactiveWifiDeviceWithName 回调,方可以调用此方法。

接口说明

- (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 已有设备通过蓝牙入网,来决定使用何种方式下发控制命令和操作命令。

// 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 的以下方法。

创建 Mesh 群组

  • 创建时,群组地址的 localId0x8001 开始,依次叠加。

  • 群组的大小类和设备一样,传入表示此群组约定此类设备组建为群组

  • 目前每个 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
    }];

添加子设备到 Mesh 群组

向群组内加设备,需要经过本地和云端双重验证,才能算作一个设备成功加入到群组。添加设备时,请一个一个地进行,并按顺序执行。不要并发进行。

添加流程

蓝牙 Mesh(涂鸦)

接口说明

// 本地连接
// 添加设备到群组方法,该方法执行后会通过 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) {
            }];
    }
}

从 Mesh 群组中移除子设备

和向群组添加设备操作流程类似,从群组内删除设备,需要经过本地和云端双重验证,才能算作一个设备从群组内删除。移除设备时,请一个一个地进行,并按顺序执行。不要并发进行。

移除流程

蓝牙 Mesh(涂鸦)

接口说明

// 本地连接
// 删除群组内某个设备方法,该方法执行后会通过 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) {
            }];
    }
}

查询 Mesh 群组实例

接口说明

+ (instancetype)meshGroupWithGroupId:(NSInteger)groupId;

参数说明

参数 说明
groupId 群组 ID

此处的 groupId 并非上面所述 localId,是由添加群组成功之后,云端返回的群组 ID。并且注意,所有的群组操作下发的地址都只是和 localId 有关。

重命名 Mesh 群组

接口说明

- (void)updateMeshGroupName:(NSString *)meshGroupName success:(ThingSuccessHandler)success failure:(ThingFailureError)failure;

参数说明

参数 说明
meshGroupName Mesh 群组名称
success 操作成功回调
failure 操作失败回调

删除 Mesh 群组

删除群组和添加或者移除设备一样,都需要经过本地删除和云端删除。

接口说明

// 本地删除
- (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) {
	}];
}

查询 Mesh 群组内设备

接口说明

- (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 namepassword,此时只会通过 ThingBLEMeshManagerDelegate 中的
    - (void)bleMeshManager:(ThingBLEMeshManager *)manager didScanedDevice:(ThingBleMeshDeviceModel *)device; 返回扫描结果。

  • 若操作为入网,填入已创建的 Mesh namepassword,此信息来自云端接口返回,可以自动进行连接、入网。并自动查询一次 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"
其中格式可以按照之前的文档格式进行下发设置