简体中文
简体中文
English
联系我们
注册
登录
layout空间导航

涂鸦商用照明移动应用 SDK 开发入门教程 iOS 版

更新时间:2022-02-17 05:18:35下载pdf

涂鸦商用照明 App SDK 是专为照明行业的物联网应用提供的移动端开发工具。基于该 SDK,您可以快速实现商用照明及关联场景的 iOS App 功能开发。它适用于新装和存量的商用照明市场,多协议兼容,通过设备管理、能源管控、人因照明等实现绿色建筑与健康建筑。

您可以通过本教程在两小时内快速开发一款自己的 IoT App,并实现如下功能:

  • 在涂鸦商照管理平台上注册商户账号,并在 App 端管理该账号。
  • 在该账号下新建并管理项目和区域。
  • 在该区域下连接并控制设备。

您可以点击下方按钮下载 Sample 查看本教程中的示例代码。本次教程按功能模块进行分类,您可以快速找到对应的代码参考学习。

前往 App 开发平台 点击查看 GitHub Sample

准备工作

在您开始本教程前,请先确保您已经 :

  1. 在涂鸦 IoT 平台,注册账号并创建 App 应用,拿到 SDK 的 AppKey,AppSecret。参考 准备工作

    准备工作中,您需要额外申请一个商照账号。账号类型不限:

    • 类型一:体验版账号。
      • 您可以通过在 准备工作 中获取 SDK 选项下,在顶部点击 申请体验版,获得 30 天的体验账号。
      • 测试版账号在体验期间,您使用 SDK 开发的 App 可正常登录,到期后 App 无法登录,且无法再次申请,您需要购买正式版后继续使用。
    • 类型二:正式账号。
      • 您可以在 增值服务 开通。
      • 正式版账号的有效期则根据您购买的套餐时长来匹配,且需搭配商照 SaaS 或开放 API 进行使用。使用商用照明 PaaS 对接前,请联系您的涂鸦客户经理提供相应的域名与域名证书,协助您配置。
  2. 使用 CocoaPods 将涂鸦商业照明 SDK 集成到您的项目中。参考 快速集成

账号管理

账号类型分为品牌商账号、企业主账号、企业子账号。品牌商账号下只创建一个商户账号,属于单一的 SaaS 商户模式。

开始之前,请在 Podfile 文件中添加以下内容:

platform :ios, '9.0'

target 'Your_Project_Name' do
	pod "TuyaSmartUserToBKit"
end

第一步:开通账号

目前涂鸦商照 SDK 暂不支持 App 账号注册的功能。您需要前往 涂鸦商照管理平台,购买商户账号并开通企业主账号。

第二步:使用账号密码登录

接下来,您可以调用 登录接口 登录在上一步中注册的企业主账号。

 [[TuyaSmartUser sharedInstance]loginMerchantByPassword:@"your_password"
                                            countryCode:@"your_countryCode"
                                               username:@"your_username"
                                           merchantCode:nil
                                   multiMerchantHanlder:nil
                                                success:^{
                                                       NSLog(@"login success");
                                             } failure:^(NSError *error) {
                                                      NSLog(@"login error");
                                              }
];

目前,商业照明限制一个账号仅对应一个唯一商户。所以,在登录账号时,自动匹配商户到账号,您无需传入参数商户的 merchantCode

除了账号密码,您还可以使用 验证码登录,或者 提交工单 申请进行 第三方授权登录

第三步:账号管理

您可以对当前账号进行信息修改,如密码和昵称等。

修改密码

[[TuyaSmartUser sharedInstance]resetMerchantPasswordWithUsername:@"your_user_name"
                                                     countryCode:@"country_code"
                                                     oldPassword:@"old_password"
                                                     newPassword:@"new_password"
                                                         success:^{
                                                                     NSLog(@"reset password success");
                                                                  } failure:^(NSError *error) {
                                                                     NSLog(@"reset password failure");
                                                       }
];

账号管理还支持找回或重置密码、退出账号、修改账号头像、同步更新用户信息等。对应的详细内容,请参考 账号管理

项目与区域管理

名词介绍

  • 项目:项目为挂载在某一账号下的可独立操作的单元,也是照明 SDK 中可操作的最大单位。

    • 一个账号下可以有不定数量的项目。
    • 项目分为室内和户外项目,更多详情,请参考 项目类型
    • 新创建的账号默认没有项目,您需要在登录账号后新建项目,才能进行后续如设备配网和控制等操作。
      项目的相关类如下:
      • 查询项目配置、查询项目列表和创建项目等功能由 TuyaLightingProjectManager 类提供。
      • 查询项目信息、更新项目信息和删除项目功能由 TuyaLightingProject 类提供。
      • 项目的具体信息(名字,区域,项目负责人等)则从 TuyaLightingProjectModel 类查询。
  • 区域:区域是挂载在某一项目下的可独立操作的单元,区域可以有不定数量的子区域。与项目类似,区域也分为室内和户外区域。
    区域的相关类如下:

    • TuyaLightingAreaManager 类用于创建新的区域。
    • TuyaLightingArea 用于存储修改区域的相关信息,操作区域中的设备等。

本章节代码示例和方法说明均为室内项目和区域。

第一步:创建一个室内项目

在登录账号后,您首先需要 创建一个项目

// Create an indoor project
   [[TuyaLightingProjectManager new] createProjectWithProjectType:TuyaLightingProjectTypeIndoor
                                                      projectName:@"your projectName"
                                                       leaderName:@"your leaderName"
                                                     leaderMobile:@"your leaderMobile"
                                                    detailAddress:@"your detailAddress"
                                                 regionLocationId:nil
                                                          success:^(id result) {
                                                          NSLog(@"create success");
                                                          // you can get
                                                        } failure:^(NSError *error) {
                                                          NSLog(@"create failure: %@", error);
                                                        }];
  • 对于室内项目,参数 regionLocationId 可置为空。
  • 对于户外项目,可通过国家码(如 8601 等)和 查询一级行政区码 组合,以 , 拼接。

第二步:查询账号下的项目

您可以通过调用 查询项目列表 接口查询到商照账号下的所有项目。

TuyaLightingProjectManager *manager = [[TuyaLightingProjectManager alloc] init];
[manager getProjectListWithSuccess:^(NSArray<TuyaLightingProjectModel *> * _Nonnull projectList) {

		//  self.projectArray = [projectList  mutableCopy];

	} failure:^(NSError * _Nonnull error) {

	}];

对项目的信息修改和删除等其他操作可参考 更新项目信息

第三步:创建一个室内区域

您可以在当前项目下创建区域,创建 室内区域户外区域 为不同接口。在室内项目下,只能创建室内区域,户外项目同理。

[TuyaLightingAreaManager createAreaWithProjectId:@" the current ID"
                                   currentAreaId:0
                                            name:@"area name"
                                       roomLevel:1
                                         success:^(id result) {
                                                     NSLog(@"success");
                                                   // you can get the new area id here
                                       } failure:^(NSError *error) {
                                                   NSLog(@"failure");
                                      }
];

参数说明

  • ProjectId:当前项目 ID。
  • currentAreaId:当前区域 ID。
    • 若当前您还未创建区域或需要创建一级区域,该参数可为任意值。为防止冲突,建议设置为 0 或负数。
    • 若您想在一个已有区域的基础上创建父区域或子区域,则需要设为对应的区域 ID。

      当然,您也可以直接调用接口创建 父区域子区域
  • roomLevel:区域等级。
    • currentAreaId0 时,无论 roomLevel 为多少,该区域都是一级区域。
    • 若为一个已知的区域 ID,则根据该值大小创建一个子区域或父区域。

下面的方法会在已有的区域上创建一个子区域。

[TuyaLightingAreaManager createAreaWithProjectId:@" the current ID"
                                   currentAreaId:  self.area.areaId
                                            name:@"area name"
                                       roomLevel:self.area.roomLevel+1
                                         success:^(id result) {
                                                     NSLog(@"success");
                                                   // you can get the new area id here
                                       } failure:^(NSError *error) {
                                                   NSLog(@"failure");
                                      }
];

创建区域后您就可以在该区域下连接和管理设备了。

设备配网

简单来说,配网就是将设备连接并注册到云端,使其拥有与云端远程通信的能力。涂鸦商用照明 App SDK 提供了丰富的配网方式以支持大部分智能设备。如 Wi-Fi 连接,蓝牙连接等。详情请参考 设备配网蓝牙体系

配网方式介绍

本文以 Wi-Fi 配网为例,介绍如何使用 SDK 将设备配置到云端。

Wi-Fi 配网方式包括 快连模式(即 EZ 模式)热点模式(即 AP 模式)、扫 App 二维码三种方式。在之后的 iOS 版本 SDK 中,推荐使用 热点模式 代替 快连模式。主要原因如下:

  • 相比快连模式,热点模式成功率高、可靠性好,对手机和路由器有兼容性要求小。热点模式配网成功率高于快连模式。
  • 当 Xcode 升级至 12.5 版本后,编译出来的 App 无法在大于等于 14.5 版本的 iOS 系统的设备上发出快连配网的数据包。此时,App 需要额外开启一个 com.apple.developer.networking.multicast 的权限。这个权限需要向苹果额外申请,等审批通过后才能够使用。目前临时的解决方案是降低 Xcode 版本,但仍推荐使用热点模式。

获取配网 Token

开始配网之前,SDK 需要在联网状态下从涂鸦 获取配网 Token,然后才可以开始热点模式配网。

  • Token 的有效期为 10 分钟,且配置成功后就会失效,再次配网需要重新获取。
  • 获取 Token 需要上传当前的项目ID(projectId),因此您需要确保账号处于登录状态并至少创建了一个 项目
//The following parameter HomeId equals to the projectId.
[[TuyaSmartActivator sharedInstance] getTokenWithHomeId:projectId
                                                success:^(NSString *token) {
		                                    //  NSLog(@"getToken success: %@", token);
		                                   // You could start ConfigWiFi now.
	                                      } failure:^(NSError *error) {
		                                 //NSLog(@"getToken failure: %@", error.localizedDescription);
	                                     }
];

iOS 版本适配

iOS 14 版本适配

从 iOS 14 版本开始,在设备配网、局域网本地控制时会触发 本地网络 权限弹窗。

  • 如果用户点击了允许,App 才能够向本地局域网发送数据。
  • 如果用户点击了拒绝,将无法使用相关功能。

目前苹果没有提供任何 API 对此权限进行判断,建议您在相关功能无法正常使用时提示、引导用户检查 系统设置 中的 app设置,确认是否开启了 本地网络 权限。

iOS 13 版本适配

从 iOS 13 版本开始,如果用户没有开启地理位置权限,在已开启 Wi-Fi 权限的前提下,[[TuyaSmartActivator sharedInstance] currentWifiSSID] 将查询不到有效的 Wi-Fi SSID 或 BSSID。在此情况下,iOS 会返回下列默认值:

  • SSID:WLAN 或 Wi-Fi,针对中国大陆地区则是 WLAN
  • BSSID:“00:00:00:00:00:00”

开始设备配网

开始配网前,请确保设备处于待配网状态。操作方法,请参考设备本身提供的使用说明书。

调用 配网接口,需要提供路由器的 SSID(即 Wi-Fi 名称)、密码、从云端获取的 Token 等。

[TuyaSmartActivator sharedInstance].delegate = self;
[[TuyaSmartActivator sharedInstance] startConfigWiFi:TYActivatorModeAP
                                                ssid:ssid
                                            password:password
                                               token:token
                                             timeout:100];

timeout 单位为秒,默认为 100,您可以设置为任意值。但不建议将此值设置得过小,否则将影响配网结果。

使用热点模式配网时,您需要实现 TuyaSmartActivatorDelegate 协议,以监听配网结果的回调。

@interface xxxViewController () <TuyaSmartActivatorDelegate>
- (void)activator:(TuyaSmartActivator *)activator didReceiveDevice:(TuyaSmartDeviceModel *)deviceModel error:(NSError *)error {
    if (deviceModel && error == nil) {
             //success
            // NSLog(@"connected success: %@", deviceModel.name);
    }

    if (error) {
        //fail
    }

   // stop config
}

(可选)停止配网

开始配网操作后,App 会持续广播配网信息,直到配网成功或是超时才停止。如果需要中途取消操作或配网完成,需要调用 停止配网 接口。

[TuyaSmartActivator sharedInstance].delegate = nil;
[[TuyaSmartActivator sharedInstance] stopConfigWiFi];

设备控制

本章节主要操作对象包含 TuyaSmartDeviceModelTuyaSmartDevice

对象 说明 参考链接
TuyaSmartDeviceModel
  • TuyaSmartHomeModelTuyaSmartHome 类似,TuyaSmartDeviceModel 存放了设备的基本信息,如 ID、名字、图标等。
  • TuyaSmartDeviceModel 类的 dps 属性(NSDictionary 类型)定义了当前设备的状态,称作数据点(DP,Data Point)或功能点。每个 DP 都存储了了一个设备的功能信息。如开关(布尔值),灯泡的亮度(数值型)等。对于设备的控制都通过查询和修改 DP 值实现。
设备功能点
TuyaSmartDevice TuyaSmartDevice 存放了设备相关的所有功能,如功能控制,设备固件管理等。您需要用正确的 deviceId 初始化一个 TuyaSmartDevice 设备管理

请确保 ViewController 或其他对象中持有的 TuyaSmartDevice 为全局变量(@property)。临时的 TuyaSmartDevice 变量可能会因为作用域问题,在初始化时被提前释放,而返回 nil

查询已配网设备

设备成功配网后,您可以在对应的区域下查看 设备列表

您必须先调用 查询项目详细信息 接口。否则即使配网成功也无法成功查询。

long long projectId = TYCacheManager.sharedInstance.projectId;
 TuyaLightingArea *area = [[TuyaLightingArea alloc] initWithAreaId:self.areaId projectId:projectId];

[area getDeviceListWithOffsetKey:@"1"
                                 tag:@""
                             success:^(NSArray<TuyaSmartDeviceModel *> * _Nonnull devices, NSString * _Nonnull nextOffsetKey, BOOL end) {

                           self.deviveList = devices ;

    } failure:NULL];

查看设备信息

  • 设备的功能点信息存放在 deviceModelschemaArray 中。

    TuyaSmartDevice *device = self.device;
    NSArray *schemas = device.deviceModel.schemaArray;
    
  • schemaArray 存放了该设备的所有功能点信息,每个功能点被封装成一个TuyaSmartSchemaModel 对象。

    涂鸦商用照明移动应用 SDK 开发入门教程 iOS 版

  • 对于部分功能信息复杂的设备,涂鸦将功能再一次封装在 TuyaSmartSchemaModelproperty 属性中。具体判断方式如下:

    NSString *type = [schema.type isEqualToString:@"obj"] ? schema.property.type : schema.type;
    
    	if ([type isEqualToString:@"bool"]) {
    
    		SwitchTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"switchCell"];
    		if (cell == nil){
    			cell = [[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell" owner:self options:nil] lastObject];
    
    			cell.label.text = schema.name;
    			[cell.switchButton setOn:[dps[schema.dpId] boolValue]];
    
    			};
    
    		}
    		return cell;
    
    	}
    
    else if ([type isEqualToString:@"value"]) {
    
    		SliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"valueCell"];
    		if (cell == nil){
    			cell = [[[NSBundle mainBundle] loadNibNamed:@"SliderTableViewCell" owner:self options:nil] lastObject];
    
    			cell.label.text = schema.name;
    			cell.detailLabel.text = [dps[schema.dpId] stringValue];
    			cell.slider.minimumValue = schema.property.min;
    			cell.slider.maximumValue = schema.property.max;
    			cell.slider.value = [dps[schema.dpId] floatValue];
    
    			};
    		};
    		return cell;
    
    	}
    
    	else if ([type isEqualToString:@"enum"]) {
    		//...
    	}
    
    	//...
    

在上述代码中,以灯泡为例将其功能点信息展示在 TableView 上。其中:

  • typeboolcell 展示了开关的信息。
  • typevaluecell 展示了其亮度的信息。

控制设备

控制设备需要将对应的 DP 以 NSDictionary 形式,通过 设备控制 接口改变设备状态或功能。

参数 dps 中可以包含多个功能点,您可以一次同时改变设备的多个状态。

同样以灯泡为例,以下代码分别修改了其开关状态和亮度值。

if ([type isEqualToString:@"bool"]) {

        SwitchTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"switchCell"];
        if (cell == nil){
            cell = [[[NSBundle mainBundle] loadNibNamed:@"SwitchTableViewCell" owner:self options:nil] lastObject];

            cell.label.text = schema.name;
            [cell.switchButton setOn:[dps[schema.dpId] boolValue]];
            cell.isReadOnly = isReadOnly;
           // turn on/off when click the UISwitch
            cell.switchAction = ^(UISwitch *switchButton) {
                [weakSelf publishMessage:@{schema.dpId: [NSNumber numberWithBool:switchButton.isOn]}];
            };

        }
        return cell;

    }

else if ([type isEqualToString:@"value"]) {

        SliderTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"valueCell"];
        if (cell == nil){
            cell = [[[NSBundle mainBundle] loadNibNamed:@"SliderTableViewCell" owner:self options:nil] lastObject];

            cell.label.text = schema.name;
            cell.detailLabel.text = [dps[schema.dpId] stringValue];
            cell.slider.minimumValue = schema.property.min;
            cell.slider.maximumValue = schema.property.max;
            [cell.slider setContinuous:NO];
            cell.slider.value = [dps[schema.dpId] floatValue];

            // change the value when tap the UISlider
            cell.sliderAction = ^(UISlider * _Nonnull slider) {
                float step = schema.property.step;
                float roundedValue = round(slider.value / step) * step;
                [weakSelf publishMessage:@{schema.dpId : [NSNumber numberWithInt:(int)roundedValue]}];
            };
         };
        return cell;

    }
- (void)publishMessage:(NSDictionary *) dps {
    [self.device publishDps:dps success:^{
            // change success
    }
    failure:^(NSError *error) {
         // change failed
    }];
}

如果您需要监听设备状态的改变,如在线状态、移除通知、功能点状态改变等。需要实现 TuyaSmartDeviceDelegate 协议。

self.device = [TuyaSmartDevice deviceWithDeviceId:## your deviceId];
self.device.delegate = self;
#pragma mark - TuyaSmartDeviceDelegate

- (void)device:(TuyaSmartDevice *)device dpsUpdate:(NSDictionary *)dps {
	// The DPS status of the device has changed, refresh UI
}

- (void)deviceInfoUpdate:(TuyaSmartDevice *)device {
	//The other status of the device has changed(like name , online status), refresh UI
}

- (void)deviceRemoved:(TuyaSmartDevice *)device {
	//the current device had been removed
}

- (void)device:(TuyaSmartDevice *)device signal:(NSString *)signal {

}

- (void)device:(TuyaSmartDevice *)device firmwareUpgradeProgress:(NSInteger)type progress:(double)progress {

}

- (void)device:(TuyaSmartDevice *)device firmwareUpgradeStatusModel:(TuyaSmartFirmwareUpgradeStatusModel *)upgradeStatusModel {

}

下一步

在商用照明的业务场景中,设备更多以群组的形式出现。群组是一个或多个设备按照一定规则的聚合体,通过对群组的控制可以便捷地控制群组中设备。

具体的使用可参考章节 群组管理,或在本文文首下载 Sample 体验开发流程。