第六部分:访问服务和特性

最后更新于:2022-04-01 02:09:58

服务([HMService](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/cl/HMService))代表了一个配件(accessory)的某个功能和一些具有可读写的特性([HMCharacteristic](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMCharacteristic_Class/index.html#//apple_ref/occ/cl/HMCharacteristic))。一个配件可以拥有多项服务,一个服务也可以有很多特性。比如一个车库开门器可能拥有一个照明和开关的服务。照明服务可能拥有打开/关闭和调节亮度的特性。用户不能制造智能家电配件和它们的服务-配件制造商会制造配件和它们的服务-但是用户可以改变服务的特性。一些拥有可读写属性的特性代表着某种物理状态,比如,一个恒温器中的当前温度就是一个只可读的值,但是目标温度又是可读写的。苹果预先定义了一些服务和特性的名称,以便让Siri能够识别它们。 **获得配件的服务和属性** 在依照[Getting the Accessroties in a Room](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/HomeKitDeveloperGuide/FindingandAddingAccessories/FindingandAddingAccessories.html#//apple_ref/doc/uid/TP40015050-CH3-SW5)中描述,你创建了一个配件对象之后,你可以获得配件的服务和特性。当然你也可以直接从home中按照类型获得不同的服务。 重要:不要暴露匿名服务-比如固件升级服务-给用户 通过[HMAccessory](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMAccessory_Class/index.html#//apple_ref/occ/cl/HMAccessory)类对象的[services](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMAccessory_Class/index.html#//apple_ref/occ/instp/HMAccessory/services)属性,我们可以获得一个配件的服务。 ~~~ NSArray *services = accessroy.services; ~~~ 要获得一个home当中配件提供的特定服务,使用[HMHome](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/cl/HMHome)类对象的[servicesWithTypes:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/instm/HMHome/servicesWithTypes:)方法。 ~~~ // Get all lights and thermostats in a home NSArray *lightServices = [home servicesWithTypes:[HMServicesTypeLightbulb]]; NSArray *thermostatServices = [home servicesWithTypes:[HMServicesTypeThermostat]]; ~~~ 使用[HMServices](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/cl/HMService)类对象的[name](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/instp/HMService/name)属性来获得服务的名称 ~~~ NSString *name = services.name; ~~~ 要获得一个服务的特性,请使用[characteristics](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/instp/HMService/characteristics)属性。 ~~~ NSArray *characteristics = service.characteristics ~~~ 使用[servicesType](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/instp/HMService/serviceType)属性来获得服务的类型 NSString *serviceType = service.serviceType; 苹果定义了一些服务类型,并能被Siri识别: * 门锁(Door locks) * 车库开门器(Garage door openers) * 灯光(Lights) * 插座(Outlets) * 恒温器(Thermostats) **改变服务名称** 使用[updateName:completionHandler:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/instm/HMService/updateName:completionHandler:)异步方法来改变服务名称。传入此方法的服务名称参数必须在一个home当中是唯一的,并且服务名可被Siri识别。 ~~~ [service updateName:@"Garage 1 Opener" completionHandler:^(NSError *error) { if (error) { // Failed to change the name } else { // Successfully changed the name } }]; ~~~ **访问特性的值** 特性代表了一个服务的一个参数,它要么是只读、可读写或者只写。它提供了这个参数可能的值的信息,比如,一个布尔或者一个范围值。恒温器中的温度就是只读的,而目标温度又是可读写的。一个执行某个任务的命令且不要求任何返回-比如播放一段声音或者闪烁一下灯光来确认某个配件-可能就是只写的。 苹果定义了一些特性的类型,并能被Siri识别: * 亮度(Brightness) * 最近温度(Current temperature) * 锁的状态(Lock state) * 电源的状态(Power state) * 目标状态(Target state) * 目标温度(Target temperature) 比如,对于一个车库开门器来说,目标状态就是打开或者关闭。对于一个锁来说,目标状态又是上锁和未上锁。 在你获得了一个[HMService](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/cl/HMService)对象之后,如 [Getting Services and Their Properties](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/HomeKitDeveloperGuide/AccessingServicesandTheirCharacteristics/AccessingServicesandTheirCharacteristics.html#//apple_ref/doc/uid/TP40015050-CH6-SW2)所描述的,你可以获得每个服务的特性的值。因为这些值是从配件中获得的,这些读写的方法都是异步的,并可以传入一个完成回调的block。 使[用readValueWithCompletionHandler:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMCharacteristic_Class/index.html#//apple_ref/occ/instm/HMCharacteristic/readValueWithCompletionHandler:)异步方法来读取一个特性的值。 ~~~ [characteristic readValueWithCompletionHandler:^(NSError *error) { if (error == nil) { // Successfully read the value id value = characteristic.value; } else { // Unable to read the value } }]; ~~~ 在if语句块中,加入你的代码以更新app的视图。 使用[writeValue:completionHandler:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMCharacteristic_Class/index.html#//apple_ref/occ/instm/HMCharacteristic/writeValue:completionHandler:)异步方法来向一个特性写入值。 ~~~ [self.characteristic writeValue:@42 withCompletionHandler:^(NSError *error) { if (error == nil) { // Successfully wrote the value } else { // Unable to write the value } }]; ~~~ 不要以为函数调用完成就意味着写入成功,实际上只有在当完成回调执行并没有错误产生时才表示写入成功。比如,直到一个开关的特性改变之前都不要改变这个开关的状态。在if语句块中,加入你的代码,以更新app的视图。 另外,在别的app更新了特性的值时也需要更新视图,在[Observing Changes to Accessories](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/HomeKitDeveloperGuide/RespondingtoHomeKitDatabaseChanges/RespondingtoHomeKitDatabaseChanges.html#//apple_ref/doc/uid/TP40015050-CH5-SW1)中有描述。 **创建服务组** 一个服务组([HMServiceGroup](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMServiceGroup_Class/index.html#//apple_ref/occ/cl/HMServiceGroup))提供了控制不同配件的任意数量服务的快捷方式-比如,当用户离开家之后控制家中的某些灯。 ![405.png](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-08_55c5769bb36e0.png "1427340681778912.png") 在你创建了一个[HMHome](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/cl/HMHome)对象之后,如[Getting the Primary Home and Collection of Homes](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/HomeKitDeveloperGuide/FindingandAddingAccessories/FindingandAddingAccessories.html#//apple_ref/doc/uid/TP40015050-CH3-SW3)中描述,你也就在这个家中创建一个服务组。 为了创建一个服务组,我们使用[HMHome](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/cl/HMHome)类对象的[addServiceGroupWithName:completionHandler:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/instm/HMHome/addServiceGroupWithName:completionHandler:)方法。方法中参数服务组的名称必须在此家中唯一,并可以被Siri识别。 ~~~ [self.home addServiceGroupWithName:@"Away Lights" completionHandler:^(HMServiceGroup *serviceGroup, NSError *error) { if (error == nil) { // Successfully created the service group } else { // Unable to create the service group }]; ~~~ 我们使用[HMServiceGroup](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMServiceGroup_Class/index.html#//apple_ref/occ/cl/HMServiceGroup)类对象的[addService:completionHandler:](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMServiceGroup_Class/index.html#//apple_ref/occ/instm/HMServiceGroup/addService:completionHandler:)方法来向服务组中添加一个服务。服务可以在一个或多个服务组中。 ~~~ [serviceGroup addService:service completionHandler:^(NSError *error) { if (error == nil) { // Successfully added service to service group } // Unable to add the service to the service group }]; ~~~ 通过[HMHome](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/cl/HMHome)类对象的[serviceGroups](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMHome_Class/index.html#//apple_ref/occ/instp/HMHome/serviceGroups)属性,来获得这个家的所有服务组。 ~~~ NSArray *serviceGroups = self.home.serviceGroups; ~~~ 通过[HMServiceGroup](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMServiceGroup_Class/index.html#//apple_ref/occ/cl/HMServiceGroup)类对象的[accessory](https://developer.apple.com/library/ios/documentation/HomeKit/Reference/HMService_Class/index.html#//apple_ref/occ/instp/HMService/accessory)属性,我们获得服务所对应的智能电器。 ~~~ HMAccessory *accessory = service.accessory; ~~~ 和配件类似,代理方法在别的app改变服务组时也会被调用。如果你的app使用了服务组,请阅读HMHomeDelegate Protocol Reference文档,获悉你应该实现哪些方法以观察这些变化。
';