TuyaLink 设备

更新时间:2024-03-04 07:31:45

TuyaLink 生态设备接入是面向物联网生态领域(自研模组/成品智能设备)全面开放的设备上云解决方案。通过此方案可以快速加入涂鸦生态体系,实现跨领域设备间互连互通,并可使用平台丰富的 PaaS、SaaS 和 App 等应用开发能力,最大程度地降低物联网整体解决方案的落地实施成本,减少开发周期。更多详情,请参考 生态设备接入

判断 TuyaLink 设备

接口说明

- (BOOL)isSupportThingModelDevice;

代码示例

Objective-C:

- (void)judgeSupportThingLink {
    // self.device = [ThingSmartDevice deviceWithDeviceId:@"your_device_id"];

    BOOL isSupport = [self.device.deviceModel isSupportThingModelDevice];
    NSLog(@"judgeSupportThingLink: %ld", isSupport);
}

Swift:

func judgeSupportThingLink() {
    let isSupport = device?.deviceModel?.isSupportThingModelDevice()
}

物模型

物模型是涂鸦针对物理实体设备在云端建立的数据模型,主要用于描述产品的功能。物模型通过定义一款产品设备所应具备的功能属性、动作功能、事件来表示一个物理实体设备,在云端的数据展现。

功能类型 说明 适用场景
属性 定义设备具有持续性、可查询等特点的状态,它代表设备的某个或者某几个功能参数。 属性通过设置读写操作,来实现对设备功能参数的修改和查询。当设备本身的某项功能参数发生变更,设备也可以主动修改属性。例如灯的亮度、开关状态等。
动作 用于控制设备执行复杂的业务功能。动作不涉及设备属性变更的控制指令。 需要设备响应指令,从而对外提供一个可供用户调用的方法。例如人脸识别、照片下发等。
事件 是设备上报的瞬时通知消息,可以包含多个输出参数,需要被外部感知和处理。 事件通常搭配数据订阅服务,或者与规则引擎结合,对事件信息作出业务逻辑上的处理,以满足特定的功能。例如水温报警、故障报警等。

目前,物模型信息是按需获取机制,请在合适的时机检查物模型本地缓存,并在适当的时候获取并更新物模型缓存。

接口说明

@interface ThingSmartDeviceModel
// ....

// 获取设备的物模型本地缓存
@property (nonatomic, strong, nullable) ThingSmartThingModel *thingModel;
@end

@interface ThingSmartDevice
// ...

// 使用 当前设备信息 获取并更新物模型缓存
- (void)getThingModelWithSuccess:(nullable void(^)(ThingSmartThingModel * _Nullable thingModel))success
                         failure:(nullable ThingFailureError)failure;

// 使用 产品 ID + 产品 ID 版本获取并更新物模型
+ (void)getThingModelWithProductId:(NSString *)pid
                    productVersion:(NSString *)productVersion
                           success:(nullable void (^)(ThingSmartThingModel * _Nullable thingModel))success
                           failure:(nullable ThingFailureError)failure;
@end

ThingSmartThingModel 数据模型

字段 类型 说明
modelId NSString 物模型 ID
productId NSString 产品 ID
productVersion NSString 产品 ID 版本
services NSArray<ThingSmartThingServiceModel *> 服务模型
extensions NSDictionary 扩展信息

ThingSmartThingServiceModel 数据模型

字段 类型 说明
properties ThingSmartThingProperty 属性
actions ThingSmartThingAction 动作
events ThingSmartThingEvent 事件

ThingSmartThingProperty 数据模型

字段 类型 说明
abilityId NSInteger 属性 ID
可与普通设备的 dpsdpId 对应
code NSString 属性 Code
accessMode NSString 访问模式:
  • rw: 可下发可上报
  • ro: 仅上报
  • wr: 仅下发
typeSpec NSDictionary 类型定义
defaultValue id 默认值

附加说明

typeSpec 类型定义,目前支持 valuestringdateboolenumfault(bitmap)arraystruct 几种类型。

其中,arraystruct 是 TuyaLink 特有的。struct 中存在嵌套,在使用时请注意嵌套定义。

各种类型定义样例:

// type = value
{
  "unit" : "℃",
  "type" : "value",
  "min" : 0,
  "max" : 100,
  "typeDefaultValue" : 0,
  "step" : 1,
  "scale" : 1
}

// type = string
{
  "type" : "string",
  "typeDefaultValue" : "",
  "maxlen" : 50
}

// date
{
  "type" : "date",
  "typeDefaultValue" : 1658482441413
}

// bool
{
  "type" : "bool",
  "typeDefaultValue" : false
}

// enum
{
  "range" : [
    "e1",
    "e2",
    "e3"
  ],
  "typeDefaultValue" : "e1",
  "type" : "enum"
}

// fault (bitmap)
{
  "label" : [
    "f1",
    "f2"
  ],
  "typeDefaultValue" : 0,
  "type" : "bitmap"
}

// array
{
  "maxSize" : 4,
  "type" : "array",
  "elementTypeSpec" : {
    "type" : "value"
  }
}

// struct
{
  "type" : "struct",
  "properties" : {
    "struct_value" : {
      "name" : "test_value",
      "typeSpec" : {
        "type" : "value",
        "min" : 11,
        "typeDefaultValue" : 11,
        "max" : 22,
        "step" : 2,
        "scale" : 1
      }
    }
  }
}

ThingSmartThingAction 数据模型

字段 类型 说明
abilityId NSInteger 动作 ID
code NSString 动作 Code
inputParams NSArray 下发参数列表
outputParams NSArray 上报参数列表

inputParamsoutputParams 实际上是 typeSpec 的数组,可为空数组,例如:

// input
{
  "code": "action_input_output_params",
  "abilityId" : 108,

  "inputParams" : [{
    "typeSpec" : {
      "unit" : "¥",
      "type" : "value",
      "min" : 0,
      "max" : 5,
      "typeDefaultValue" : 0,
      "step" : 1,
      "scale" : 0
    },
    "code" : "action_value"
  },
  {
    "typeSpec" : {
      "type" : "string",
      "typeDefaultValue" : "",
      "maxlen" : 100
    },
    "code" : "action_string"
  }],

  "outputParams" : [{
    "typeSpec" : {
      "unit" : "$",
      "type" : "value",
      "min" : 0,
      "max" : 100,
      "typeDefaultValue" : 0,
      "step" : 1,
      "scale" : 0
    },
    "code" : "out_action_value"
  }]
}

ThingSmartThingEvent 数据模型

字段 类型 说明
abilityId NSInteger 事件 ID
code NSString 事件 Code
outputParams NSArray 上报参数列表

控制设备

下发控制

接口说明

- (void)publishThingMessageWithType:(ThingSmartThingMessageType)thingMessageType
                            payload:(NSDictionary *)payload
                            success:(ThingSuccessHandler)success
                            failure:(ThingFailureError)failure

参数说明

参数 类型 说明
thingMessageType ThingSmartThingMessageType
  • 0:属性
  • 1:动作
  • 2:事件
payload NSDictionary 下发内容
success ThingSuccessHandler 成功回调
failure ThingFailureError 失败回调
  • 由于下发时会校验内容合法性,下发时需要有物模型缓存,请在合适的时机判断和拉取物模型。
  • 由于 TuyaLink 设备的特性,目前仅通过 MQTT 通道进行控制。
  • ThingSmartThingMessageType事件 仅上报,不能下发。

payload 格式如下:

  • 下发属性时规则

    // 可多个同时下发,code 是物模型中属性的 code,value 要符合 typeSpec 定义
    {
        "code": value,
        "code": value
    }
    
    // 例如
    {
        "color":"green",
        "brightness": 50
    }
    
  • 下发动作时规则

    // 同时只能下发一个动作
    {
    "actionCode": "code",
    "inputParams": {
        "paramsCode": value,
        "paramsCode": value,
    }
    }
    
    // 例如
    {
        "actionCode": "action_input_output_params",
        "inputParams": {
            "action_value": 5,
            "action_string": "test_string"
        }
    }
    

代码示例

Objective-C:

// 在合适的时机去拉取,例如:用户单击设备进入控制页的时候
- (void)fetchThingModel {
    // self.device = [ThingSmartDevice deviceWithDeviceId:@"your_device_id"];

    if (!self.device.deviceModel.thingModel) {
      [self.device getThingModelWithSuccess:^(ThingSmartThingModel * _Nullable thingModel) {
          NSLog(@"fetch thing model success: %@", thingModel);
      } failure:^(NSError *error) {
          NSLog(@"fetch thing model fail: %@", error);
      }];
    }
}

// 控制设备-下发属性
// 注意:在下发前需要 deviceModel.thingModel 是存在的
- (void)publishProperty {
    // self.device = [ThingSmartDevice deviceWithDeviceId:@"your_device_id"];

      // 下发属性
      NSDictionary *propertyPayload = @@{
        @"color": @"green",
        @"brightness": @50
    };
        [self.device publishThingMessageWithType:ThingSmartThingMessageTypeProperty payload:propertyPayload success:^{
        NSLog(@"success");
    } failure:^(NSError *error) {
        NSLog(@"failure: %@", error);
    }];
}

// 控制设备-下发动作
// 注意:在下发前需要 deviceModel.thingModel 是存在的
- (void)publishAction {
    // self.device = [ThingSmartDevice deviceWithDeviceId:@"your_device_id"];

      // 下发动作
        NSDictionary *actionPayload = @{
        @"actionCode": @"action_input_output_params",
        @"inputParams": @{
            @"action_value": @5,
            @"action_string": @"test_string"
        }
    };
      [self.device publishThingMessageWithType:ThingSmartThingMessageTypeAction payload:actionPayload success:^{
        NSLog(@"success");
    } failure:^(NSError *error) {
        NSLog(@"failure: %@", error);
    }];
}

Swift:

// 在合适的时机去拉取,例如:用户单击设备进入控制页的时候
func fetchThingModel() {
  device?.getThingModel(success: { thingModel in
      print("success \(thingModel)")
  }, failure: { error in
      if let err = error {
          print("failure \(err)")
      }
  })
}

// 控制设备-下发属性
// 注意:在下发前需要 deviceModel.thingModel 是存在的
func publishProperty() {
  let porpetyPayload = [
    "color": "green",
    "brightness": 50
  ]
  device?.publishThingMessage(with: .property, payload: porpetyPayload, success: {
    print("publish property success")
  }, failure: { error in
    if let err = error {
      print("publish property fail.(%@)", err)
    }
  })
}

func publishAction() {
  let actionPayload = [
    "actionCode": "action_input_output_params",
    "inputParams": [
      "action_value": 5,
      "action_string": "test_string"
    ]
  ]
  device?.publishThingMessage(with: .action, payload: actionPayload, success: {
    print("publish action success")
  }, failure: { error in
    if let err = error {
      print("publish action fail.(%@)", err)
    }
  })
}

监听回调

通过 ThingSmartDevice 设置 delegate 进行监听回调。

接口说明

- (void)device:(ThingSmartDevice *)device didReceiveThingMessageWithType:(ThingSmartThingMessageType)thingMessageType payload:(NSDictionary *)payload;

参数说明

参数 类型 说明
device ThingSmartDevice 设备操作对象
ThingSmartThingMessageType ThingSmartThingMessageType
  • 0:属性
  • 1:动作
  • 2:事件
payload NSDictionary 收到的上报内容,thingMessageType 不同则格式不同,具体见 下列注意事项 中的样例
  • 由于上报时会校验内容合法性,上报时需要有物模型缓存,请在合适的时机判断和拉取物模型
  • 仅对于属性消息,还会转换成 dps 格式,也会通过 -device:dpsUpdate: 回调

payload 在不同消息类型下的格式,如下样例所示:

  • 上报属性时

    // 格式规则
    {
    "code": {
        "value": value,
        "time": 1234567890
    },
    "code": {
        "value": value,
        "time": 1234567890
    }
    }
    
    // 例如
    {
        "color": {
            "value": "green",
            "time": 1234567890
        },
        "brightness": {
            "value": 50,
            "time": 1234567890
        }
    }
    
  • 上报动作时

    // 格式规则
    {
        "actionCode": code,
        "outputParams": {
            "outputParam1": value,
            "outputParam2": value
        }
    }
    
    // 例如
    {
        "actionCode": "open_door_action",
        "outputParams": {
            "status": "open",
            "angle": 30
        }
    }
    
  • 上报事件时

    // 格式规则
    {
        "eventCode": code,
        "outputParams": {
            "outputParam1": value,
            "outputParam2": value
        }
    }
    
    // 例如
    {
        "eventCode": "people_move_event",
        "outputParams": {
            "count": 2,
            "time": "2022-07-22 18:30:00"
        }
    }
    

代码示例

Objective-C:

// 在合适的时机去监听
- (void)addThingDeviceListner {
      // self.device = [ThingSmartDevice deviceWithDeviceId:@"your_device_id"];
      device.delegate = self;
}

// 注意:在接收上报前需要 deviceModel.thingModel 是存在的
- (void)device:(ThingSmartDevice *)device didReceiveThingMessageWithType:(ThingSmartThingMessageType)thingMessageType payload:(NSDictionary *)payload {

    NSLog(@"---did receive thing msg type: %ld, msg: %@", thingMessageType, payload);
    // 不同 type 的消息 payload 格式不同,详见参数说明
    if (thingMessageType == ThingSmartThingMessageTypeProperty) {
        //.. do something
    } else if (thingMessageType == ThingSmartThingMessageTypeAction) {
        //.. do something
    } else if (thingMessageType == ThingSmartThingMessageTypeEvent) {
        //.. do something
    }
}

Swift:

// 在合适的时机去监听
func addThingDeviceListner {
  device?.delegate = self;
}

// 注意:在接收上报前需要 deviceModel.thingModel 是存在的
func device(_ device: ThingSmartDevice, didReceiveThingMessageWith thingMessageType: ThingSmartThingMessageType, payload: [AnyHashable : Any]) {
  print("---did receive thing msg type: \(thingMessageType), payload: \(payload)")
  switch thingMessageType {
  case .property:
    //.. do something
  case .action:
    //.. do something
  case .event:
    //.. do something
  }
}

属性、动作、事件 payload 缓存

在上文 物模型 介绍中,提到 属性 表示设备的持续性、可查询的状态,而 动作事件 是设备实时的响应。所以,对应消息的 payload 的缓存机制如下所述:

  • 属性 有缓存,可以通过 ThingSmartDeviceModel::dps 来获取缓存。
  • 动作 无缓存。
  • 事件 无缓存。

属性 实际与原本普通设备的 DP(Data Point) 含义一致,所以通过 ThingSmartDeviceModel::dps 来缓存,格式定义为:dpId = value

在使用时,请通过 属性模型ThingSmartThingProperty::abilityId 来进行映射对应来展示。

属性 payload 转换为 DP

TuyaLink 设备的属性实际上和原本涂鸦普通设备的 DP 概念一致。只是相比 DP,增加 arraystruct 两种新的类型定义。

当收到属性消息的上报时,在通过 -device:didReceiveThingMessageWithType:payload: 回调的同时,也会同步转换成 dps,通过 -device:dpsUpdate: 回调并缓存在 deviceModel.dpsdeviceModel.dpsTime 中。

您也可以通过 ThingSmartThingModel 开放的方法 -dpsFromProperties: 将 属性 转换为 DP。

接口说明

@interface ThingSmartThingModel : NSObject
//...

// 将属性 转换为 DP 格式
- (NSDictionary *)dpsFromProperties:(NSDictionary *)properties;
@end

参数说明

参数 类型 说明
properties NSDictionary 属性 payload,格式与上报属性时一致。

属性 payload 格式:

{
  "code": {
    "value": value,
    "time": time
  },
  "code": {
    "value": value,
    "time": time
  },
}

代码示例

Objective-C:

- (void)transferPropertiesToDp {
      ThingSmartThingModel *thing = self.device.deviceModel.thingModel;

      NSDictionary *propertiesPayload = @{
        @"color": @"green",
        @"brightness": @50
    }
    NSDictionary *dps = [thing dpsFromProperties:propertiesPayload];
    NSLog(@"---- dps: %@", dps);

      /**
          输出结果是,101、105 实际就是 "color" 和 "brightness" 的 ThingSmartThingProperty::abilityId
          @{
              @"101": @"green",
              @"105": @50
          }
      */
}

Swift:

func trnasferPropertiesToDp {
  if let thing = device?.deviceModel.thingModel {
    let propertiesPayload = [
      "color": "green",
      "brightness": 50
    ]
    let dps = thing?.dps(fromProperties: propertiesPayload)
    print("--- dps: \(dps)")
  }
}