HomeAtlas delivers compile-time safe wrappers over Apple HomeKit services and characteristics. Metadata for every service originates from Developer Apple Context7 (developer_apple, HomeKit topic), ensuring generated Swift APIs remain aligned with the platform source of truth.
- Strongly typed descriptors for accessories, services, and characteristics (no
Anyleakage). @MainActorasync helpers that bridge HomeKit callbacks to structured Swift concurrency.- Schema-driven SwiftPM command plugin (
generate-homeatlas) to regenerate sources whenever the HomeKit catalog evolves. - Deterministic error surface that captures accessory, service, and characteristic context for diagnostics.
- Built-in snapshot export for diagnostics and monitoring with deterministic JSON serialization.
- Xcode 16 beta or newer with the Swift 6.0 toolchain.
- Apple platforms with HomeKit support (iOS 16+, macOS 13+, tvOS 16+, watchOS 9+).
Add HomeAtlas to your package dependencies:
.package(url: "https://github.com/pradeepmouli/HomeAtlas.git", from: "0.1.0")Then add the library to your target:
.target(name: "MyApp", dependencies: [
.product(name: "HomeAtlas", package: "HomeAtlas")
])This package is prepared for the Swift Package Index (SPI):
- Manifest includes library and executable products, platforms, and targets
- MIT license and README are present
- Semantic versions are tagged on Git for releases (e.g.,
0.1.0)
To publish a new release:
- Update CHANGELOG.md
- Create a new tag:
git tag -a v0.1.0 -m "Initial release" && git push origin v0.1.0 - Verify SPI ingestion and documentation build
import HomeAtlas
enum ToggleError: Error {
case accessoryNotFound
case characteristicUnavailable
}
@MainActor
func toggleLightbulb(named accessoryName: String, manager: HomeKitManager) async throws {
await manager.waitUntilReady()
guard
let accessory = manager.accessory(named: accessoryName),
let lightbulb = accessory.service(of: LightbulbService.self)
else {
throw ToggleError.accessoryNotFound
}
guard let power = lightbulb.powerState else {
throw ToggleError.characteristicUnavailable
}
try await power.write(true)
}The example mirrors the Developer Apple Context7 HomeKit Lightbulb service documentation. LightbulbService exposes a PowerStateCharacteristic wrapper (Characteristic<Bool>) so attempts to write a non-boolean value fail at compile time rather than at runtime.
HomeAtlas wrappers do not conform to Encodable because they wrap non-Encodable HomeKit framework types (HMAccessory, HMService, etc.). For diagnostics or logging that require serialization, use the DTO (Data Transfer Object) pattern to extract encodable snapshots:
struct AccessorySnapshot: Codable {
let name: String
let uniqueIdentifier: UUID
let isReachable: Bool
let categoryType: String
init(from accessory: Accessory) {
self.name = accessory.name
self.uniqueIdentifier = accessory.uniqueIdentifier
self.isReachable = accessory.isReachable
self.categoryType = accessory.category.categoryType
}
}
// Usage:
let snapshot = AccessorySnapshot(from: myAccessory)
let jsonData = try JSONEncoder().encode(snapshot)See docs/encodable-exclusion-rationale.md for detailed rationale and DTO examples.
HomeAtlas converts every fallible operation into a HomeKitError, enriching the error with the accessory, service, and characteristic metadata documented by Developer Apple.
do {
try await power.write(true)
} catch let error as HomeKitError {
switch error {
case .characteristicTransport(_, let context, _):
print("Write failed for", context.characteristicType, "on", context.serviceType ?? "<unknown>")
print("Metadata:", error.diagnosticsMetadata)
default:
throw error
}
}The shared DiagnosticsLogger already emits structured telemetry whenever a HomeKit operation fails or exceeds the configurable latency budget (default 500 ms). Register an observer to integrate with your logging stack:
let token = DiagnosticsLogger.shared.addObserver { event in
print("HomeKit", event.operation.rawValue, event.outcome, event.metadata)
}Pair the metadata with the relevant Developer Apple Context7 topic (e.g., accessory communication or latency guidance) to provide actionable insights to end users.
HomeAtlas provides strongly-typed wrappers for HomeKit context entities that organize accessories:
import HomeAtlas
@MainActor
func listHomeRooms(manager: HomeKitManager) async {
await manager.waitUntilReady()
guard let primaryHome = manager.homes.first else {
print("No homes configured")
return
}
// Wrap HMHome for type-safe access
let home = Home(primaryHome)
print("Home: \(home.name)")
print("Rooms:")
for hmRoom in home.rooms {
let room = Room(hmRoom)
print(" - \(room.name) (\(room.accessories.count) accessories)")
}
print("\nZones:")
for hmZone in home.zones {
let zone = Zone(hmZone)
print(" - \(zone.name) (\(zone.rooms.count) rooms)")
}
}These wrappers conform to the Developer Apple HMHome, HMRoom, and HMZone APIs while providing @MainActor safety and diagnostic logging.
For performance optimization, HomeAtlas exposes cache warm-up and reset APIs:
@MainActor
func optimizeAccessoryAccess(manager: HomeKitManager) async {
// Warm up caches for all services and characteristics
await manager.warmUpCache(includeServices: true, includeCharacteristics: true)
// Later, if accessories are modified externally:
await manager.resetCache(includeCharacteristics: true)
}Cache operations emit diagnostics events for monitoring performance:
let token = DiagnosticsLogger.shared.addObserver { event in
if event.operation == .cacheWarmUp || event.operation == .cacheReset {
print("Cache operation:", event.metadata)
}
}See Developer Apple - Interacting with a home automation network for best practices on accessory lifecycle management.
HomeAtlas uses a two-stage pipeline to keep service definitions synchronized with Apple's SDK:
swift run HomeKitCatalogExtractor \
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk \
--output Resources/homekit-services.yamlThis parses HomeKit framework headers and validates exported symbols against HomeKit.tbd, producing a normalized YAML catalog.
swift run HomeKitServiceGenerator \
Resources/homekit-services.yaml \
--output Sources/HomeAtlas/GeneratedOr use the SwiftPM plugin for integrated builds:
swift package plugin generate-homeatlasThe plugin/generator emits typed Swift wrappers into:
Sources/HomeAtlas/Generated/Servicesfor service classes such asLightbulbService.Sources/HomeAtlas/Generated/Characteristicsfor characteristic wrappers such asPowerStateCharacteristic.
Every generated file includes @MainActor annotations and doc comments referencing the corresponding Developer Apple HomeKit documentation so the code stays aligned with the platform source of truth.
For detailed workflow, see Service Extension Guide.
swift testSmoke tests validate the schema pipeline and ensure integration logic compiles on platforms without HomeKit support by exercising fallback paths.
- Service Extension Guide - SDK extraction and code generation workflow
- Troubleshooting Guide - Common errors and solutions
- Developer Apple Reference Index - Complete API reference citations
- Quickstart Guide - Step-by-step setup
HomeAtlas is available under the MIT license. See LICENSE for details.