如果當前裝置是一個網關,且該網關下的子裝置需接入雲端,此時需要使用子裝置管理功能。
子裝置動態註冊
網關子裝置管理提供子裝置動態註冊、擷取雲端網關下子裝置列表、添加子裝置、刪除子裝置、子裝置上線、子裝置下線、監聽子裝置禁用和刪除的訊息、代理子裝置資料上下行的能力。
網關本身是一個直連裝置,網關使用子裝置管理的功能前,需要網關已經串連到阿里雲物聯網平台。網關裝置的開發,請參見認證與串連和基於MQTT Topic通訊。
子裝置的動態註冊是指網關根據子裝置的productKey、deviceName向雲端擷取子裝置DeviceSecret的過程,網關擷取到子裝置的DeviceSecret之後,需要將其儲存在網關上,即使網關reset也不能將子裝置的DeviceSecret丟失。
子裝置在商家後台建立時需要開啟允許動態註冊功能,同時子裝置的deviceName需要廠商預先上傳到阿里雲物聯網平台。
範例程式碼如下:
self.gatewayInterface = [[LinkKitEntry sharedKit] gatewayInterface];
NSMutableArray * subBases = @[].mutableCopy;
for (NSDictionary * subinfo in _subDevices) {
LinkkitDeviceBase * base = [[LinkkitDeviceBase alloc] init];
base.productKey = [subinfo valueForKey:@"productKey"];
base.deviceName = [subinfo valueForKey:@"deviceName"];
[subBases addObject:base];
}
[self.gatewayInterface subDeviceRegisterBatch:subBases
resultBlock:^(NSArray * _Nullable result, NSError * _Nullable error) {
LinkkitLogDebug(@"subDeviceRegisterBatch error : %@", error);
self.subDevicesReg = result;
LinkkitDeviceAuth * authSub = result[0];
/// LinkkitDeviceAuth這個類包含deviceSecret,建議使用者將deviceSecret持久儲存。當子裝置再次上線時,使用儲存的子裝置認證進行身份認證。
dispatch_async(dispatch_get_main_queue(), ^{
[self ims_showHUDWithMessage:[NSString stringWithFormat:@"成功註冊子裝置個數 : %d",
(int)self.subDevicesReg.count]];
});
}];
添加子裝置到網關
添加子裝置過程實際上是子裝置跟網關在本地以及IoT雲端建立拓撲關係的過程,子裝置要通過網關實現資料上下雲,必須首先跟網關建立拓撲關係。拓撲關係建立後一直存在,直到刪除拓撲關係。
添加子裝置存在兩種方式:
通過動態註冊網關擷取到了子裝置的認證資訊。 範例程式碼如下:
__weak typeof (self) weakSelf = self; LinkkitDeviceAuth * authSub = self.subDevicesReg[0]; [self.gatewayInterface addSubDevice:authSub delegate:self resultBlock:^(id<ILKSubDeviceChannel> _Nonnull subChannel, NSError * _Nullable error) { LinkkitLogDebug(@"subDevice logout add to gateway : %@", error); weakSelf.subChannel = subChannel; dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.lableSubState.text = @"已關聯至網關"; [weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"添加子裝置到網關 : %@", error ? @"失敗":@"成功"]]; }); }];子裝置本身燒錄了裝置認證資訊,對於此類裝置,切記無需要再去調用 “子裝置動態註冊”方法。 範例程式碼如下:
__weak typeof (self) weakSelf = self; LinkkitDeviceBase * devBase = [[LinkkitDeviceBase alloc] init]; devBase.productKey = @"sub device productKey"; devBase.deviceName = @"sub device deviceName"; [self.gatewayInterface addSubDevice:devBase signer:self delegate:self resultBlock:^(id<ILKSubDeviceChannel> _Nullable subChannel, NSError * _Nullable error) { LinkkitLogDebug(@"subDevice logout add to gateway : %@", error); weakSelf.subChannel = subChannel; dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.lableSubState.text = @"已關聯至網關"; [weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"添加子裝置到網關 : %@", error ? @"失敗":@"成功"]]; }); }]; // 其中 signer的具體實現,請參見LinkkitGateway.h 中的 protocol ILKSubDeviceSigner 聲明中介紹。
從網關刪除子裝置
刪除子裝置與網關拓撲關係的範例程式碼如下:
__weak typeof (self) weakSelf = self;
LinkkitDeviceBase * devBase = [[LinkkitDeviceBase alloc] init];
devBase.productKey = @"sub device productKey";
devBase.deviceName = @"sub device deviceName";
[self.gatewayInterface deleteSubDevice:devBase
resultBlock:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice delete from gateway error : %@", error);
weakSelf.subChannel = nil;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.lableSubState.text = @"未關連網關";
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"從網關刪除子裝置 : %@", error ? @"失敗":@"成功"]];
});
}];
子裝置上線
子裝置必須在上線之後才可以執行子裝置的訂閱、發布等操作。代理子裝置上線的範例程式碼如下:
__weak typeof (self) weakSelf = self;
[self.subChannel login:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice login error : %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.lableSubState.text = @"已上線";
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"子裝置上線 : %@", error ? @"失敗":@"成功"]];
});
}];
子裝置下線
子裝置下線之後不可以進行子裝置的發布、訂閱、取消訂閱等操作。子裝置下線的範例程式碼如下:
__weak typeof (self) weakSelf = self;
[self.subChannel logout:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice logout error : %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.lableSubState.text = @"未上線";
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"子裝置下線 : %@", error ? @"失敗":@"成功"]];
});
}];
監聽子裝置禁用、刪除
網關裝置可以在雲端操作子裝置,例如禁用子裝置、啟用子裝置、刪除和子裝置的拓撲關係。目前服務端只支援禁用子裝置的下行通知。服務端在禁用子裝置時會對子裝置進行下線處理,後續網關不能代理子裝置和雲端做通訊。可以通過設定子裝置stateListener來偵聽子裝置禁用、刪除訊息。
self.subChannel.stateListener = self;
代理子裝置基礎資料上下行
使用網關的通道執行子裝置的資料上下行。
上行資料範例程式碼:
- (IBAction)onClickUpload:(id)sender {
if (self.subChannel == nil) {
[self ims_showHUDWithMessage:@"請添加子裝置並上線"];
return;
}
__weak typeof (self) weakSelf = self;
NSString * topic = self.textFieldPubTopic.text;
NSData * upData = [self.textViewPubContent.text dataUsingEncoding:NSUTF8StringEncoding];
int qos = [self.textFieldQos.text intValue];
[self.subChannel publish:topic data:upData qos:qos
resultBlock:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice upload error : %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"子裝置資料上行 : %@", error ? @"失敗":@"成功"]];
});
}];
}
關於QoS取值,目前阿里雲IoT平台只支援QoS取值為[0,1],不支援QoS=2。
如果需要能收到子裝置的下推訊息,首先需要訂閱相關Topic範例程式碼如下:
- (IBAction)onClickSubscribe:(id)sender {
if (self.subChannel == nil) {
[self ims_showHUDWithMessage:@"請添加子裝置並上線"];
return;
}
__weak typeof (self) weakSelf = self;
NSString * topic = self.textFieldSubTopic.text;
[self.subChannel subscribe:topic
resultBlock:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice subscribe error : %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"子裝置訂閱 : %@", error ? @"失敗":@"成功"]];
});
}];
}
同時,還需要在添加子裝置到網關時傳入ILKSubDeviceDelegate的執行個體。 ILKSubDeviceDelegate實現如下所示:
///偵聽子裝置與雲端的串連狀態,即上下線情況
- (void)onConnectResult:(BOOL)success
error:(NSError * _Nullable)err
subDeviceChannel:(nonnull id<ILKSubDeviceChannel>)subDeviceChannel {
if ([self.subChannel.subDeviceProfile.deviceBaseId
isEqualToString:subDeviceChannel.subDeviceProfile.deviceBaseId]) {
//__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
});
} else {
}
}
///偵聽子裝置的下推(從雲端下推)資料
- (void)onDataPush:(nonnull NSString *)topic data:(nonnull NSData *)data {
NSString * downData = [NSString stringWithFormat:@"收到下推,topic : %@ \r\n", topic];
downData = [downData stringByAppendingString:[NSString stringWithFormat:@"\r\n資料 : %@", data]];
LinkkitLogDebug(@"subDevice recv topic : %@", topic);
dispatch_async(dispatch_get_main_queue(), ^{
self.textViewDownData.text = downData;
});
}
可以通過取消訂閱方法來屏蔽某些已經訂閱過的訊息。 範例程式碼如下:
- (IBAction)onClickUnsubscribe:(id)sender {
if (self.subChannel == nil) {
[self ims_showHUDWithMessage:@"請添加子裝置並上線"];
return;
}
__weak typeof (self) weakSelf = self;
NSString * topic = self.textFieldSubTopic.text;
[self.subChannel unsubscribe:topic
resultBlock:^(BOOL succeeded, NSError * _Nullable error) {
LinkkitLogDebug(@"subDevice unsubscribe error : %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf ims_showHUDWithMessage:[NSString stringWithFormat:@"子裝置取消訂閱 : %@", error ? @"失敗":@"成功"]];
});
}];
}