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.