hap
hap
(previously hc) is a lightweight library to develop HomeKit accessories in Go. It abstracts the HomeKit Accessory Protocol (HAP) and makes it easy to work with services and characteristics.
hap
handles the underlying communication between HomeKit accessories and clients. You can focus on implementing the business logic for your accessory, without having to worry about the protocol.
Here are some projects which use hap
.
What is HomeKit?
HomeKit is a set of protocols and libraries from Apple. It is used by Apple's platforms to communicate with smart home appliances. A non-commercial version of the documentation is now available on the HomeKit developer website.
HomeKit is fully integrated into iOS since iOS 8. Developers can use HomeKit.framework to communicate with accessories using high-level APIs.
I've developed the Home+ app to control HomeKit accessories from iPhone, iPad, and Apple Watch. If you want to support hap
, please purchase Home from the App Store. That would be awesome.
Migrate from hc
This library is a rewrite of hc. If you want to migrate from hc
, consider the following changes.
- Instead of
hc.NewIPTransport(...)
you now call hap.NewServer(...) to create a server. - You can create your own persistent storage by implementing the Store interface.
- Setting the value of a characteristic can now fail. Fixes hc#163
- You can define custom http handlers. Fixes hc#212
server.ServeMux().HandleFunc("/ping", func(res http.ResponseWriter, req *http.Request) {
res.Write([]byte("pong"))
})
- You can define your own public and private key (just in case) by setting the Key field of the server. Otherwise those keys are generate and stored on disk for you.
server.Key = hap.KeyPair{
Public: []byte{...},
Private: []byte{...},
}
- The base structs for accessories, services and characteristics are now accessory.A, service.S, characteristic.C
Features
- Supports Go modules (requires Go 1.13)
- Full implementation of the HAP in Go
- Supports all HomeKit services and characteristics
- Built-in service announcement via DNS-SD using dnssd
- Runs on linux and macOS
- Documentation: http://godoc.org/github.com/brutella/hap
Usage
In a following example a simple on/off switch is created. It can be paired with HomeKit using the Apple Home app – use the pin code 00102003.
package main
import (
"github.com/brutella/hap"
"github.com/brutella/hap/accessory"
"context"
"log"
"os"
"os/signal"
"syscall"
)
func main() {
// Create the switch accessory.
a := accessory.NewSwitch(accessory.Info{
Name: "Lamp",
})
// Store the data in the "./db" directory.
fs := hap.NewFsStore("./db")
// Create the hap server.
server, err := hap.NewServer(fs, a.A)
if err != nil {
// stop if an error happens
log.Panic(err)
}
// Setup a listener for interrupts and SIGTERM signals
// to stop the server.
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-c
// Stop delivering signals.
signal.Stop(c)
// Cancel the context to stop the server.
cancel()
}()
// Run the server.
server.ListenAndServe(ctx)
}
Events
The library provides callback functions, which let you know when a client updates a characteristic value. The following example shows how to get notified when the On characteristic value changes.
a.Switch.On.OnValueRemoteUpdate(func(on bool) {
if on == true {
log.Println("Switch is on")
} else {
log.Println("Switch is off")
}
})
If you want to change the state of a switch programmatically, you call SetValue(...).
a.Switch.On.SetValue(true)
The library takes care of the rest and notifies all connected clients that the state has changed.
Multiple Accessories
When you create a server you can specify multiple accessories like this.
var a1, a2, a3 *accessory.A
s, err := hap.NewServer(fs, a1, a2, a3)
By doing so, the first accessory a1
appears as a bridge in HomeKit. When adding the accessories to HomeKit, iOS only shows the bridge accessory. Once the bridge was added, the other accessories appear automatically.
HomeKit requires that every accessory has a unique id, which must not change between system restarts. hap
automatically assigns the ids for you based on the order in which the accessories are added to the server.
The best would be to specify the unique id for every accessory yourself, like this
a1.Id = 1
a2.Id = 2
Accessory Architecture
HomeKit uses a hierarchical architecture to define accessories, services and characeristics. At the root level there is an accessory. Every accessory contains services. And every service contains characteristics.
For example a lightbulb accessory contains a lightbulb service. This service contains the on characteristic.
There are predefined accessories, services and characteristics available in HomeKit. Those types are defined in the packages accessory, service, characteristic.
Contact
Matthias Hochgatterer
Website: https://hochgatterer.me
Github: https://github.com/brutella
Twitter: https://twitter.com/brutella
License
hap
is available under the Apache License 2.0 license. See the LICENSE file for more info.
hap does not support multiple servers/bridges
Multiple bridges with accessories are supported by multiple servers only. So creating a new bridge and assign it to a new server will start listening on random ports. While the bridges all appear on the Home App 'Add new device', only one bridge can be added. When trying to add a second one, the Home App waits to connect and runs into an timeout. All server appear correctly in the DNS viewer. Is there a way to have multiple bridges?
Dynamic device resolution
Hey @brutella :wave:
First of I all would like to thank you! I just started playing around with this library and I finally added some glue code to my own library and was able to create a simple home-automation app with device auto discovery within an hour! :clap:
Also the possibility to add an external data-storage is great, so I can easily run this within a container and won't have to worry about local filesystems. :clap:
Nevertheless it seems like I have run into a problem:I am trying to autodetect my devices.
I am doing something like that:
This auto-creates the accessories with a consistent name + serialnumber (idempotent action). Sadly the order of the detected devices is not idempotent as there is no order and devices may be added or removed.
When restarting the services, I have noticed that the name of the Home-App was not matching to the actor anymore. I believe that's because of the id generation of the accessories.
I tried to work my way around this by manually generating a unique accessory id before starting the server, but that feels like I am having to much knowledge of what is going on inside of hap.
Maybe you can share some thoughts about potential solutions or maybe my use-case is just unsupported.
Thanks and best regards, Dennis
No reponse and not responding
Hi, when i run an example with the hap library, there is no problem adding the device to home app. But after a while, home app will show the device "no response" or "not responding" and can not control it.
I have tried a few workarounds, including turning off the iphone's Private WLAN Address, tweaking the router, but none of them worked.
Here is my example:
Here is some debug output:
[Question] Windows Shutter process
Hello again, I'm trying to build a gateway with my shutters. I just want some clarification about the process to update / get update with a WindowsCovering device.
My Actual process is the following:
On TargetPosition.OnValueRemoteUpdate event is received I activate the shutter. When I receive a confimation that the shutter reached the desired position, I SetValue on CurrentPosition.
If the shutter is manually positionned, I SetValue on CurrentPosition
Do I need to SetValue on TargetPosition? and when?
Does PositionState need to be updated as well? Or is it handeled by the protocol?
Thanks for your time
[Question] on update events
Hello,
I would like some clarifications about the update events: Whats the difference between: OnValueRemoteUpdate, OnValueUpdate and OnSetRemoteValue?
ClientController feature?
Hello,
In deprecated library I have found example https://github.com/brutella/hc/blob/master/_example/client.go
so I'm able to pair with remote accessory.
Is this functionality present in current package or any plans to implement it?
Thanks.
Improve consistency for Accessories
This fixes some variable names that were incorrect in
accessories/security_system.go
but also changes to a single style for all accessories setup, including using AddS() rather than a manual append().It also cleans up some spacing and formatting to be consistent between all accessories.
Broken link in README
First paragraph:
hap (previously hc) is a lightweight library to develop HomeKit accessories in Go. It abstracts the HomeKit Accessory Protocol (HAP) and makes it easy to work with services and characteristics.
link to characteristics (last word) is broken: https://github.com/brutella/hap/blob/master/characteristic/README.md
Fix error handling
This code
throws false positive errors:
Thanks.
Add interfaces on dnssd service
I suggest a new configuration value of the server to the dnssd service. The new value is a list of interface names used by dnsssd service to publish the correct ip when it exposes the hap service.
The problem, for me, is that the raspberry where I deploy the hap server has a multiple interfaces: one for the lan and the second for the iot devices. My firewall configuration blocks all the iot traffic (192.168.20.0/24) to the regular lan (192.168.1.00/24).
When the dnssd server goes up it uses all the interfaces on the device so the pairing with the iphone fails. I suppose that when the iphone starts pairing it uses the iot lan ip, that cannot reach the lan networks.
The change I suggest is to add the new value to the server configuration that will be used on
dnssd.Config
.Ifaces
into the fileserver.go
at line 479.Upgrading from HC to HAP
Hello!
First I would like to thank you for the amazing work on this library, it's really fun to play with Go and Homekit accessories!
I'm trying to migrate from HC to HAP in the most idiomatic way, but I'm not sure to understand what's the equivalent of
OnValueRemoteGet
of a characteristic in HAP, to allow Homekit to update the current real value of the characteristic (in my case, it's an air conditioner controlled via a remote API in the cloud, which I can also control using a remote)If someone could help me on that, it would really help me!
Thank you :)
tlv8: unmarshal (silent) bug
Servus,
as previously mentioned, I have been playing with
hap
as well and used your library to test the correctness of my implementation.While trying to debug my tlv8 unmarshal implementation, I found a bug in the
tlv8.Unmarshal
function. Please find below a test which marshals a struct, unmarshals it and compare the initial and final structs.I get the following error (as you can see the
Parameters
,Levels
and other attributes differ):FYI, my
tlv8
implementation is split in 2 steps:reflect.Type
(a nested tree offunc(io.Reader, reflect.Value) error
)reflect.Value
This way, the first step can be cached based on the type and the whole process is a bit cleaner and faster.
I will never repeat it enough: huge thanks for your amazing work on this library!
accessory pair failed if name is unicode
iphone will stuck when add accessory name use unicode unless the name is ascii charset
MethodDeletePairing doesn't work correctly
maybe it's my problem I have 7 users at home adding an accessory works correctly, but if I remove the accessory, not all .pairing files are removed, after the accessory is not added again
before pairing
after pairing
after removal
LOG