Observing HomeKit Database Changes

There is one HomeKit database per home. As shown in the figure below, the database is securely synchronized with a user’s iOS devices and potentially with guest user iOS devices that are granted access to the home. In order to show the most current data to the user, your app needs to observe changes to this database.

../Art/architecture_2x.png../Art/architecture_2x.png

About HomeKit Delegation Methods

HomeKit uses the delegation design pattern to notify your app of changes to HomeKit objects. In general, if your app invokes a HomeKit method with a completion handler parameter and the method is successful, the associated delegate message is sent to other HomeKit apps running on the same or remote iOS devices. The apps can even be run by guest users on their iOS devices. If your app initiates the change, the delegate message is not sent to your app. Therefore, add code to both the completion handler and the associated delegate method to reload data and update views as needed. If a home layout changes significantly, reload all the information about that home. In the case of the completion handler, check whether the method is successful before updating the app. HomeKit also invokes delegate methods to notify your app of changes to the state of the home network.

For example, if (1) in response to a user action, (2) your app invokes addRoomWithName:completionHandler: and no error occurs, (3) the completion handler should (4) update the views of the home. If successful, HomeKit (5) sends the home:didAddRoom: message to delegates of the home in other apps. Therefore, your implementation of the home:didAddRoom: method should also (6) update the views of the home.

../Art/changeflow_2x.png

The apps need to be in the foreground to receive these delegate messages. Changes are not batched while your app is in the background. If your app is in the background while another app successfully adds a room to a home, your app doesn’t receive a home:didAddRoom: message. When your app comes to the foreground, your app receives a homeManagerDidUpdateHomes: message, which signals your app to reload all its data.

Observing Changes to the Collection of Homes

To receive delegate messages when the primary home or collection of homes changes, set the home manager’s delegate and implement the HMHomeManagerDelegate protocol.

All apps need to implement the homeManagerDidUpdateHomes: method, which is invoked after HomeKit finishes the initial fetch of homes. Until this method is invoked, for a newly created home manager, the primaryHome property is nil and the homes property is an empty array. The homeManagerDidUpdateHomes: method is also invoked when the app comes to the foreground, and changes occurred while it was in the background. The homeManagerDidUpdateHomes: method should reload all data associated with the homes.

To observe changes to homes

  1. Add the home manager delegate protocol and home manager property to your class interface.

    @interface AppDelegate () <HMHomeManagerDelegate>
     
    @property (strong, nonatomic) HMHomeManager *homeManager;
     
    @end
  2. Create the home manager object and set its delegate.

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.homeManager = [[HMHomeManager alloc] init];
        self.homeManager.delegate = self;
     
        return YES;
  3. Implement the delegate methods that are invoked when a home changes.

    For example, if multiple view controllers display information about homes, you can post a notification that a change occurred to update all the views.

    - (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager {
        // Send a notification to the other objects
        [[NSNotificationCenter defaultCenter] postNotificationName:@"UpdateHomesNotification" object:self];
    }
     
    - (void)homeManagerDidUpdatePrimaryHome:(HMHomeManager *)manager {
        // Send a notification to the other objects
        [[NSNotificationCenter defaultCenter] postNotificationName:@"UpdatePrimaryHomeNotification" object:self];
    }

    View controllers register for the change notification and implement the appropriate action.

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateHomes:) name:@"UpdateHomesNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePrimaryHome:) name:@"UpdatePrimaryHomeNotification"  object:nil];

Observing Changes to Individual Homes

The view controller that displays information about a home should be the delegate for the home object and update its views when the home changes.

To observe changes to a specific home

  1. Add the home delegate protocol to your class interface.

    @interface HomeViewController () <HMHomeDelegate>
     
    @end
  2. Set the delegate of the accessory.

    home.delegate = self;
  3. Implement the HMHomeDelegate protocol.

    For example, implement the home:didAddAccessory: and home:didRemoveAccessory: methods to update views that display accessories. To get the room that the accessory belongs to, use the room property in the HMAccessory class. (The default room for an accessory is returned by the roomForEntireHome method.)

Observing Changes to Accessories

The state of an accessory can change at any time. An accessory may not be reachable, can be out of range, or may be turned off. Update the user interface accordingly to reflect the current state of accessories, especially if your app allows the user to control an accessory.

In these steps it is assumed that you already retrieved an accessory object from the HomeKit database, as described in Getting the Accessories in a Room.

To observe changes to a specific accessory

  1. Add the accessory delegate protocol to your class interface.

    @interface AccessoryViewController () <HMAccessoryDelegate>
     
    @end
  2. Set the delegate of the accessory.

    accessory.delegate = self;
  3. Implement the HMAccessoryDelegate protocol.

    For example, implement the accessoryDidUpdateReachability: method to enable or disable accessory controls.

    - (void)accessoryDidUpdateReachability:(HMAccessory *)accessory {
        if (accessory.reachable == YES) {
           // Can communicate with the accessory
        } else {
           // The accessory is out of range, turned off, etc
        }
    }

If you display the state of services and their characteristics, implement the following delegate methods to update views accordingly:

To access the services of an accessory, read Accessing Services and Their Characteristics.