Active Filters: HomeKit

Topics

#298: Changing Light Colors with HomeKit 💡🌈

Topics

In Bite #297, we learned about about how to simulate a light bulb accessory using Apple's HomeKit Accessory Simulator. Today we'll continue where we left off, and learn how to change the color of our light bulb.

Let's dive in.

Everything in HomeKit is built around the HMHomeManager type. We'll use this manager to interact with homes, accessories, and more:

let manager = HMHomeManager()
manager.delegate = self

We've set ourselves as the delegate here so we can implement one function:

extension ViewController : HMHomeManagerDelegate {
  func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
    // TODO
  }
}

Like all user data, we'll need to ask for permission before we can access the user's HomeKit data. Once the user has allowed us, the homeManagerDidUpdateHomes function will be called. This function will also be called anytime signficant changes happen in a home.

We can use this as a cue to update our app's UI to match. Neat.

Ok, let's have some fun and see what it would look like (in code) to change all of the lights in our house to a different color.

First let's get all the lights in the home:

func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
  guard let home = manager.homes.first else { return }

  let lights = home.accessories.filter { $0.category.categoryType == HMAccessoryCategoryTypeLightbulb }
}

Nice. We now have an array of all lights in our home as HMAccessory objects. To make changes, we'll need to get to the services and characteristics inside of each accessory.

Let's flatMap our way to success and get an array of just the "Hue" characteristics.

Note: We're just going to try this out by tinting our light blue. In a complete app, we'd need to make sure to update all 3 Hue, Brightness, and Saturation characteristics of the light.

let hueCharacteristics = lights
  .flatMap { $0.services }
  .flatMap { $0.characteristics }
  .filter { $0.characteristicType == HMCharacteristicTypeHue }

Nice, now we need a way to grab a hue value from a UIColor:

func hsba(from color: UIColor) -> [CGFloat] {
  var HSBA = [CGFloat](repeating: 0.0, count: 4)
  color.getHue(&HSBA[0], saturation: &HSBA[1], brightness: &HSBA[2], alpha: &HSBA[3])
  return HSBA
}

Not the prettiest code, but it'll do. Now let's use it:

let color = hsba(from: UIColor.blue)
let newHue = Float(color[0])

for hc in hueCharacteristics {
  let max = hc.metadata?.maximumValue?.floatValue ?? 1.0

  hc.writeValue(NSNumber(value: newHue * max), completionHandler: { if let error = $0 { print("Failed: \(error)") } })
}

Here we grab our newHue value for our UIColor.blue color, then iterate through all the hueCharacteristics from before, ensuring we multiply our newHue value by each characteristic's maximumValue property. This makes sure we're speaking the language of the accessory, and setting a value in a scale it understands.

Finally, we wrap up our value in an NSNumber and write it to the HMCharacteristic.

When we build and run, we're prompted for permission. After allowing, we can flip back over to the HomeKit Accessory Simulator app and see the hue of our light has changed. Success!

Try adding more simulated lights, setting them to random colors, then running the app again to see a greater effect.

That's all for now. We've got plenty more to explore in HomeKit, look out for more Bites soon.

Topics

#297: Simulating HomeKit Accessories 💡🤖

Topics

"Home automation" is perhaps one of the hottest topics in technology these days.

While still an emerging market, many iOS device owners now also own at least one or two "smart home" devices.

Today we'll begin looking at HomeKit, Apple's framework for communicating with and controllling these devices from inside our apps.

Before we can dive in though, there's a bit of tooling we need to learn about first. Specifically, we need to learn how to simulate HomeKit devices.

For example, we might not own any HomeKit devices ourselves. Even if we do though, we'd rather not need to phsyically change things about our home to test our app.

Not to worry, Apple provides a great solution to this challenge in the form of a HomeKit Accessory Simulator app for macOS.

In it, we can setup and configure a "simulated" set of devices in any kind of Home setup we'd like.

Sadly though, it doesn't ship with Xcode.

We'll need to head over to Apple's "More Developer Downloads" page here and search for "Hardware IO Tools for Xcode". We'll download the latest release, then install the HomeKit Accessory Simulator app.

Now, let's open it up and simulate our first accessory.

We'll click the + button in the bottom left and select New Accessory...

We'll fill out the fields with some example information. The values aren't super important, they merely need to be unique and somewhat realistic.

Neat. We've now got a (pretend) lamp. 💡

Well, sort of. There's actually one more important step, and it's speaks to the heart of how HomeKit works.

So far, HomeKit doesn't know anything about our new lamp. "Lamp" is just the name we gave it.

For HomeKit to do something useful with our device, we'll need to add a HomeKit Service to it. HomeKit Services describe the capabilities and functionality of a device

We'll click the Add Service... button on our new device, and choose Lightbulb from the dropdown menu.

We can leave the rest of the fields alone.

Neat! Not only do we now have a fully-simluted, color changing light bulb, we're also provided with some nice sliders and controls to read from, and write to, the current state of the device.

That's all for today. We'll learn more about the HomeKit Accessory Simulator as we continue to explore HomeKit. Next time we'll learn how to change this light's color in code! 🌈💡