1. 蓝牙 Mesh (SIG)

涂鸦蓝牙有三条技术线路。蓝牙设备与手机一对一相连的蓝牙单点设备 SingleBLE,涂鸦自研的蓝牙拓扑通信 TuyaMesh 和蓝牙技术联盟发布的蓝牙拓扑通信 SigMesh。除了以上三种之外,还有一些多协议设备也会使用到蓝牙技术,比如同时具备 Wi-Fi 能力和 BLE 能力的 双模设备,也可以使用蓝牙进行配网,当然 Wi-Fi 设备原本的配网仍然可用。

蓝牙技术分类 产品举例
SingleBLE 体脂秤、手环、温控器、电动牙刷、门锁等
SigMesh 一路、二路、五路等灯泡、插座、传感器等 Sigmesh 子设备
TuyaMesh 与 Sigmesh 产品类似,协议为 Tuya 自研
双模设备 Sigmesh 网关、IPC 设备以及新版多协议 Wi-Fi 设备等均有可能

双模配网的蓝牙配网部分,使用的是 SingleBLE 技术为设备配网,将放到 SingleBLE 章节进行说明。

提示

开发蓝牙 Mesh 时,请先熟悉 TuyaHomeSdk。Mesh 的所有操作都建立在家庭数据已经初始化的基础上。 一个家庭里可以拥有多个 Mesh(建议一个家庭只创建一个)

1.1. 准备

手机系统要求

BLE 使用需要 Android 4.3 以及以上版本,TuyaHomesdk 从 Android 4.4 开始支持。

Manifest 的权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

使用蓝牙前需要检测权限已被授予

  • APP 在使用蓝牙连接或者扫描操作前 需要检查 APP 定位权限是否被允许。
  • 检查蓝牙状态是否为开启。

该部分检查逻辑,TuyaHomeSdk 未提供 API,开发者可自行检测。每次扫描和连接前都要进行检测,否则 APP 无法正常使用蓝牙。

1.2. 部分基础概念

大小类介绍

设备类别值由 设备类型 + 大类 + 小类组成后小端排列。

设备类型

标准型 Tuya 设备 : 1
透传型 Tuya 设备 : 2
......

SigMesh 产品目前分为三大类

灯大类(01): 1-5 路 RGBWC 彩灯
电工类(02): 1-6 路插座
遥控器(05): 1-6 个按键

小类编号

1-5路灯(1-51-6路排插(1-6) 
1-6个遥控器按键(1-6.....

举例

产品 类别值 说明
标准五路灯 1510 小端转换后得到 1015:
1:tuya设备
01:灯
5:5路灯
标准四路插座 2410 小端转换后得到 1024:
1:tuya设备
02:插座
5:4路插座
透传型设备 xx20 小端转换后得到 20xx:
2:透传设备

Mesh 节点 NodeId, 2 字节

NodeId 用于区分每个 Mesh 设备在 Mesh 网中的「唯一标识」,比如想控制某个设备就向 Mesh 网发此设备对应的 NodeId 命令即可。

Mesh 群组 localId,2 字节

LocalId 用于区分每个 Mesh 群组在 Mesh 网中的「唯一标识」,比如想控制某个群组中的设备就向 Mesh 网发此群组对应的 LocalId 命令即可。

设备操作需要多步操作

因为设备的操作,例如增删操作、群组操作,都需要本地蓝牙命令执行一次、云端记录一次 向本地 Mesh 网同步操作信息的同时也需要向云端同步操作信息。

本地连接和网关连接

本地连接:已配网设备通过蓝牙连接,来控制 Mesh 和指令操作。

网关连接:已配网设备通过网关连接(网关需和设备在一起,距离不能太远),来控制 Mesh 和指令操作。

1.3. 管理

1.3.1. 创建 SIG Mesh

由云端分配 MeshId,一个家庭下只能创建一个 Mesh。

接口方法

void createSigMesh(ITuyaResultCallback<SigMeshBean> callback);

示例代码

TuyaHomeSdk.newHomeInstance("homeIdxxxx")
  .createSigMesh(new ITuyaResultCallback<SigMeshBean>() {
    @Override
    public void onError(String errorCode, String errorMsg) {
    }

    @Override
    public void onSuccess(SigMeshBean sigMeshBean) {
    }
});

1.3.2. 删除 SIG Mesh

删除 SIG Mesh MeshId

接口方法

void removeMesh(IResultCallback callback);

示例代码

TuyaHomeSdk.newSigMeshDeviceInstance(meshId).removeMesh(new IResultCallback() {
    @Override
    public void onError(String errorCode, String errorMsg) {
    }

    @Override
    public void onSuccess() {
    }
});

1.3.3. 获取家庭下的 SIG Mesh 列表

接口说明

List<SigMeshBean> getSigMeshList();

示例代码

ITuyaHome mTuyaHome = TuyaHomeSdk.newHomeInstance("homeIdxxxx");
if (mTuyaHome.getHomeBean() != null){
    List<SigMeshBean> meshList = TuyaHomeSdk.getSigMeshInstance().getSigMeshList()
}

1.3.4. 获取 Mesh 下的子设备列表

接口说明

List<DeviceBean> getMeshSubDevList();

示例代码

List<DeviceBean> meshSubDevList = TuyaHomeSdk.newSigMeshDeviceInstance("meshIdxxxxx").getMeshSubDevList();

1.3.5. 获取 SIG Mesh 实例

建议在家庭切换的时候 销毁当前 Mesh 然后重新初始化家庭中的 Mesh。

接口说明

void initMesh(String meshId);

示例代码

TuyaHomeSdk.getTuyaSigMeshClient().initMesh("meshIdxxxxx");

1.3.6. SIG Mesh 销毁

接口说明

void destroyMesh();

示例代码

TuyaHomeSdk.getTuyaSigMeshClient().destroyMesh();

1.3.7. SIG Mesh 子设备连接和断开

ITuyaBlueMeshClient 提供 开始连接、断开连接、开启扫描、停止扫描

代码示例

// 开启连接
TuyaHomeSdk.getTuyaSigMeshClient().startClient(mSigMeshBean);
// 开启连接 指定扫描的时间 
TuyaHomeSdk.getTuyaSigMeshClient().startClient(mSigMeshBean,searchTime);

//断开连接
TuyaHomeSdk.getTuyaSigMeshClient().stopClient();

//开启扫描
TuyaHomeSdk.getTuyaSigMeshClient().startSearch()

//停止扫描
TuyaHomeSdk.getTuyaSigMeshClient().stopSearch();

注意事项

  • startClient(mSigMeshBean) 开启连接后,会在后台不断的去扫描周围可连接设备,直到连接成功为止。
  • startClient(mSigMeshBean,searchTime) 开启连接后, searchTime 时间内没有扫描到设备就停止扫描.
  • 后台一直扫描会消耗资源,可以通过通过开启扫描和停止扫描来控制后台的扫描
  • 当未 startClient() 时候,调用 startSearch()stopSearch() 是没有效果的
  • 当已经连接到 Mesh 网的时候,调用 startSearchstopSearch 是没有效果的

1.4. 配网

1.4.1. 扫描待配网子设备

扫描前需要检查蓝牙和位置权限 ;扫描附近符合 SIG 标准的蓝牙设备

接口说明

//开启扫描
void startSearch();
//停止扫描
void stopSearch();

示例代码

ITuyaBlueMeshSearchListener iTuyaBlueMeshSearchListener=new ITuyaBlueMeshSearchListener() {
    @Override
    public void onSearched(SearchDeviceBean deviceBean) {

    }

    @Override
    public void onSearchFinish() {

    }
};
// 待配网的SigMesh设备UUID是固定的
UUID[] MESH_PROVISIONING_UUID = {UUID.fromString("00001827-0000-1000-8000-00805f9b34fb")};
SearchBuilder searchBuilder = new SearchBuilder()
                                .setServiceUUIDs(MESH_PROVISIONING_UUID)    //SigMesh的UUID是固定值
                .setTimeOut(100)        //扫描时长 单位秒
                .setTuyaBlueMeshSearchListener(iTuyaBlueMeshSearchListener).build();

ITuyaBlueMeshSearch mMeshSearch = TuyaHomeSdk.getTuyaBlueMeshConfig().newTuyaBlueMeshSearch(searchBuilder);

//开启扫描
mMeshSearch.startSearch();

//停止扫描
mMeshSearch.stopSearch();

1.4.2. SIG Mesh 子设备蓝牙配网

子设备入网有两种方式,一种是通过 App 蓝牙入网,另一种是通过网关直接配子设备入网。

接口说明

//开启配网
void startActivator();
//停止配网
void stopActivator();

示例代码

TuyaSigMeshActivatorBuilder tuyaSigMeshActivatorBuilder = new TuyaSigMeshActivatorBuilder()
            .setSearchDeviceBeans(mSearchDeviceBeanList)
            .setSigMeshBean(sigMeshBean) // Sigmesh基本信息
            .setTimeOut(timeout)  //超时时间
            .setTuyaBlueMeshActivatorListener(new ITuyaBlueMeshActivatorListener() {
     @Override
     public void onSuccess(String mac, DeviceBean deviceBean) {
         L.d(TAG, "subDevBean onSuccess: " + deviceBean.getName());
     }
     @Override
     public void onError(String mac, String errorCode, String errorMsg) {
         L.d(TAG, "config mesh error" + errorCode + " " + errorMsg);
     }
     @Override
     public void onFinish() {
      L.d(TAG, "config mesh onFinish: ");
     });

ITuyaBlueMeshActivator iTuyaBlueMeshActivator = TuyaHomeSdk.getTuyaBlueMeshConfig().newSigActivator(tuyaSigMeshActivatorBuilder);

//开启配网
iTuyaBlueMeshActivator.startActivator();
//停止配网
iTuyaBlueMeshActivator.stopActivator();

入参说明

参数 说明
mSearchDeviceBeanList 待配网的设备集合,通过 startSearch 扫描得到的
timeout 配网的超时时间设置,默认是 100s(配网设备过多时,需要增加时间)
sigMeshBean SigMeshBean

出参说明

DeviceBeanDeviceBean数据模型

errorCode 见错误码

1.4.3. SIG Mesh 网关配网

SigMesh 网关 本质上为双模设备;

可以使用 Wi-Fi设备的配网 同 Wifi EZ 配网模式

也可以使用单点蓝牙双模配网 双模设备配网

1.4.4. SIG Mesh 子设备网关配网

SIG Mesh 子设备可以通过网关直接给子设备配网,配网的方式与 Zigbee 子设备入网方法一致,参考 ZigBee 子设备配网

1.4.5. 配网错误码

Code MSG
21002 invite 失败
21004 provision 失败
21006 send public key 失败
21008 conform 失败
210010 random conform 失败
210014 send data 失败
210016 composition data 失败
210018 add appkey 失败
210020 bind model 失败
210022 publication model 失败
210024 network transmit 失败
210026 云端注册失败
210027 设备地址分配已满
210034 notify 失败
20021 配网超时

1.5. 设备

ITuyaBlueMeshDevice 类封装了对指定 Mesh 内所有设备的操作

1.5.1. 获取设备实例

ITuyaBlueMeshDevice  mTuyaBlueMeshDevice = TuyaHomeSdk.newSigMeshDeviceInstance(meshId);

1.5.2. SIG Mesh 本地连接和网关连接

示例代码

DeviceBean deviceBean=TuyaHomeSdk.getDataInstance().getDeviceBean(mDevId);
DeviceBean gwBean=TuyaHomeSdk.getDataInstance().getDeviceBean(deviceBean.getParentId());

//综合在线状态  (包括本地在线和网关在线)
boolean online=deviceBean.getIsOnline()
//设备本地蓝牙在线状态
boolean localOnline=deviceBean.getIsLocalOnline()
//设备网关在线状态  (需要网关在线且子设备在线 才认为网关真实在线)
boolean wifiOnline=deviceBean.isCloudOnline() && gwBean.getIsOnline()

1.5.3. SIG Mesh 设备和网关判断方法

示例代码

DeviceBean deviceBean=TuyaHomeSdk.getDataInstance().getDeviceBean(mDevId);
// 判读是否是 sigmesh 设备 (子设备+网关)
if(deviceBean.isSigMesh()){
    L.d(TAG, "This device is sigmesh device");
}

// 判读是否是 sigmesh 网关设备
if(deviceBean.isSigMeshWifi()){
    L.d(TAG, "This device is sigmesh wifi device");
}

1.5.4. SIG Mesh 子设备重命名

接口说明

void renameMeshSubDev(String devId, String name, IResultCallback callback);

参数说明

参数 说明
devId 设备 Id
name 重命名名称
callback 回调

示例代码

mTuyaBlueMesh.renameMeshSubDev(devBean.getDevId(),"设备名称", new IResultCallback() {
     @Override
     public void onError(String code, String errorMsg) {
     }

     @Override
     public void onSuccess() {
     }
});

1.5.5. SIG Mesh 子设备状态查询

云端获取到的 dp 点数据可能不是当前设备实时的数据,可以通过该命令去查询设备的当前数据值,结果通过 IMeshDevListeneronDpUpdate 方法返回

接口说明

void querySubDevStatusByLocal(String pcc, final String nodeId, final IResultCallback callback);

参数说明

参数 说明
pcc 设备大小类
nodeId 设备 nodeId
callback 回调

示例代码

mTuyaBlueMeshDevice.querySubDevStatusByLocal(devBean.getCategory(), devBean.getNodeId(), new IResultCallback() {
            @Override
            public void onError(String code, String errorMsg) {
            }
            @Override
            public void onSuccess() {
            }
        });

1.5.6. SIG Mesh 子设备移除

接口说明

void removeMeshSubDev(String devId, IResultCallback callback);

参数说明

参数 说明
devId 设备 Id
pcc 设备大小类
callback 回调

示例代码

mTuyaBlueMesh.removeMeshSubDev(devBean.getDevId(),devBean.getCategory(), new IResultCallback() {
            @Override
            public void onError(String code, String errorMsg) {
            }
            @Override
            public void onSuccess() {
            }
        });

1.6. 群组

ITuyaGroup 类提供了对 SIG Mesh 群组的操作

1.6.1. SIG Mesh 群组判断方法

描述

可以通过群组中是否具备 MeshId 来区分 Mesh 群组和普通 WiFi 群组

代码示例

GroupBean groupBean=TuyaHomeSdk.getDataInstance().getGroupBean("groupId");
if(!TextUtils.isEmpty(groupBean.getMeshId())){    
   L.d(TAG, "This group is mesh group");
}

1.6.2. 添加群组

描述

一个 Mesh 网内支持创建 16128 个群组 返回时 id 范围 C000 - FEFF (16 进制) 由本地进行维护

接口说明

void addGroup(String name, String pcc, String localId,IAddGroupCallback callback);

参数说明

参数 说明
name 群组名称
pcc 群组中设备的大小类 (支持跨小类创建)
localId 群组的 localId (范围 C000 - FEFF 16 进制字符串)
callback 回调

代码示例

ITuyaBlueMeshDevice mTuyaSigMeshDevice= TuyaHomeSdk.newSigMeshDeviceInstance("meshId");
mTuyaSigMeshDevice.addGroup("群组名称","大小类", "8001", new IAddGroupCallback() {
            @Override
     public void onError(String errorCode, String errorMsg) {
     }

     @Override
     public void onSuccess(long groupId) {
     }
});

1.6.3. 将设备加入群组

接口说明

void addDevice(String devId,IResultCallback callback);

参数说明

参数 说明
devId 设备 Id
callback 回调

代码示例

ITuyaGroup mGroup = TuyaHomeSdk.newSigMeshGroupInstance(groupId);
mGroup.addDevice("devId", new IResultCallback() {
   @Override
   public void onError(String code, String errorMsg) {
      Toast.makeText(mContext, "添加设备到群组失败 "+ errorMsg, Toast.LENGTH_LONG).show();
   }

   @Override
   public void onSuccess() {
      Toast.makeText(mContext, "添加设备到群组成功 ", Toast.LENGTH_LONG).show();
   }
});

1.6.4. 将设备移除出群组

接口说明

void removeDevice(String devId,IResultCallback callback);

参数说明

参数 说明
devId 设备 Id
callback 回调

代码示例

ITuyaGroup mGroup = TuyaHomeSdk.newSigMeshGroupInstance(groupId);
mGroup.removeDevice("devId", new IResultCallback() {
   @Override
   public void onError(String code, String errorMsg) {
   }
   @Override
   public void onSuccess() {
   }
});

1.6.5. 解散群组

接口说明

void dismissGroup(IResultCallback callback);

参数说明

参数 说明
callback 回调

代码示例

ITuyaGroup mGroup = TuyaHomeSdk.newSigMeshGroupInstance(groupId);
mGroup.dismissGroup(new IResultCallback() {
   @Override
   public void onError(String code, String errorMsg) {
   }

   @Override
   public void onSuccess() {
   }
});

1.6.6. 重命名群组

接口说明

void renameGroup(String groupName,IResultCallback callback);

参数说明

参数 说明
groupName 重命名名称
callback 回调

代码示例

ITuyaGroup mGroup = TuyaHomeSdk.newSigMeshGroupInstance(groupId);
mGroup.renameGroup("群组名称",new IResultCallback() {
   @Override
   public void onError(String code, String errorMsg) {
   }

   @Override
   public void onSuccess() {
   }
});

1.7. 控制

ITuyaBlueMeshDevice 类提供了对 Mesh 设备的操作

1.7.1. 指令下发-控制设备

描述

发送控制指令按照以下格式:

{
  "(dpId)":"(dpValue)"
}

接口说明

void publishDps(String nodeId, String pcc, String dps, IResultCallback callback);

参数说明

参数 说明
nodeId 子设备本地编号
pcc 设备产品大小类
dps dps
callback 回调

代码示例

String dps = {"1":false};
ITuyaBlueMeshDevice mTuyaSigMeshDevice=TuyaHomeSdk.newSigMeshDeviceInstance("meshId");
mTuyaSigMeshDevice.publishDps(devBean.getNodeId(), devBean.getCategory(), dps, new IResultCallback() {
            @Override
            public void onError(String s, String s1) {
            }

            @Override
            public void onSuccess() {
            }
        });

1.7.2. 指令下发-控制群组

接口说明

void multicastDps(String localId, String pcc, String dps, IResultCallback callback)

参数说明

参数 说明
localId 群组本地编号
pcc 设备产品大小类
dps dps
callback 回调

代码示例

String dps = {"1":false};
ITuyaBlueMeshDevice mTuyaSigMeshDevice= TuyaHomeSdk.newSigMeshDeviceInstance("meshId");
mTuyaSigMeshDevice.multicastDps(groupBean.getLocalId(), devBean.getCategory(), dps, new IResultCallback() {
            @Override
            public void onError(String errorCode, String errorMsg) {
            }

            @Override
            public void onSuccess() {
            }
        });

1.7.3. 数据监听

描述

Mesh 网内相关信息( dp 数据、状态变更、设备名称、设备移除)会实时同步到 IMeshDevListener

代码示例

mTuyaSigMeshDevice.registerMeshDevListener(new IMeshDevListener() {
 /**
  * 数据更新
  * @param nodeId    更新设备的nodeId
  * @param dps       dp数据
  * @param isFromLocal   数据来源 true表示从本地蓝牙  false表示从云端
  */
    @Override
    public void onDpUpdate(String nodeId, String dps,boolean isFromLocal) {
      //可以通过node来找到相对应的DeviceBean
        DeviceBean deviceBean = mTuyaBlueMeshDevice.getMeshSubDevBeanByNodeId(nodeId);
     }
  /**
   * 设备状态的上报
   * @param online    在线设备列表
   * @param offline   离线设备列表
   * @param gwId      状态的来源 gwId不为空表示来自云端(gwId是上报数据的网关Id)为空则表示来自本地蓝牙
   */
  @Override
  public void onStatusChanged(List<String> online, List<String> offline,String gwId) {
  }

  /**
   * 网络状态变化
   * @param devId
   * @param status
   */
  @Override
  public void onNetworkStatusChanged(String devId, boolean status) {

  }        
  /**
   * raw类型数据上报
   * @param bytes
   */
  @Override
  public void onRawDataUpdate(byte[] bytes) {

  }
   /**
    * 设备信息变更(名称等)
    * @param bytes
    */            
  @Override
  public void onDevInfoUpdate(String devId) {
  }  
  /**
   * 设备移除
   * @param devId
   */
  @Override
  public void onRemoved(String devId) {
  }
});

1.8. 固件升级

可以通过 OTA 的方式给 SIG Mesh 子设备进行升级。

1.8.1. 设备固件升级信息查询

接口说明

void requestUpgradeInfo(String devId, IRequestUpgradeInfoCallback callback);

参数说明

参数 说明
devId 需要升级的设备 devId
callback 检查回调

示例代码

TuyaHomeSdk.getMeshInstance().requestUpgradeInfo(mDevID, new IRequestUpgradeInfoCallback() {
    @Override
    public void onSuccess(ArrayList<BLEUpgradeBean> bleUpgradeBeans) {

    }

    @Override
    public void onError(String errorCode, String errorMsg) {
    }
});

BLEUpgradeBean返回固件升级的信息,提供以下信息

字段 类型 描述
upgradeStatus int 升级状态,0:无新版本 1:有新版本 2:在升级中
version String 最新版本
currentVersion String 当前版本
timeout int 超时时间,单位:秒
upgradeType int 0:app 提醒升级 2:app 强制升级 3:检测升级
type int 0:wifi设备 1:蓝牙设备 2:GPRS设备 3:zigbee设备 9:MCU
typeDesc String 模块描述
lastUpgradeTime long 上次升级时间,单位:毫秒
url String 新固件下载地址,type = 1 或者 9 的时候 有值
fileSize long 新固件大小
md5 String 新固件 MD5 值

1.8.2. 子设备升级

升级接口

void startOta();

示例代码

private MeshUpgradeListener mListener = new MeshUpgradeListener() {
        @Override
        public void onUpgrade(int percent) {
            //升级进度
        }

        @Override
        public void onSendSuccess() {
            //固件数据发送成功
        }

        @Override
        public void onUpgradeSuccess() {
            //升级成功
             mMeshOta.onDestroy();
        }

        @Override
        public void onFail(String errorCode, String errorMsg) {
            //升级失败
             mMeshOta.onDestroy();
        }
    };
//获取指定文件的字节流
byte data[] = getFromFile(path);

TuyaBlueMeshOtaBuilder build = new TuyaBlueMeshOtaBuilder()
        .setData(data)
        .setMeshId(mDevBean.getMeshId())
        .setProductKey(mDevBean.getProductId())
        .setNodeId(mDevBean.getNodeId())
        .setDevId(mDevID)
        .setVersion("version")
        .setTuyaBlueMeshActivatorListener(mListener)
        .bulid();
ITuyaBlueMeshOta  = TuyaHomeSdk.newMeshOtaManagerInstance(build);

//开始升级
mMeshOta.startOta();

入参说明

TuyaBlueMeshOtaBuilder

参数 类型 说明
data byte[] 待升级固件的字节流
meshId String 设备 MeshId
productKey String 设备产品 Id
mNodeId String 设备 NodeId
devId String 设备 Id
version String 待升级固件的版本号

1.8.3. 网关设备升级

SIG Mesh 网关升级和普通的 Wi-Fi 设备升级一样。以下是实例代码。

示例代码

private IOtaListener iOtaListener = new IOtaListener() {
        @Override
        public void onSuccess(int otaType) {
            //升级成功
          }

        @Override
        public void onFailure(int otaType, String code, String error) {
             //升级失
        }

        @Override
        public void onProgress(int otaType, final int progress) {
           //升级进度         
        }
    };

ITuyaOta iTuyaOta = TuyaHomeSdk.newOTAInstance(mDevID);
iTuyaOta.setOtaListener(mOtaListener);
//开始升级
iTuyaOta.startOta();

//销毁升级
iTuyaOta.onDestroy();

results matching ""

    No results matching ""