diff --git a/README.md b/README.md index 0ec1f0d0..04bb9a8c 100644 --- a/README.md +++ b/README.md @@ -970,7 +970,7 @@ HomeKit module can work in two modes: streams: dahua1: rtsp://admin:password@192.168.1.123/cam/realmonitor?channel=1&subtype=0 homekit: - dahua1: # same stream ID from streams list, default PIN - 19550224 + dahua1: # same stream ID from streams list, default PIN - 19550224, default setup_id - HMXS ``` **Full config** @@ -985,6 +985,7 @@ streams: homekit: dahua1: # same stream ID from streams list pin: 12345678 # custom PIN, default: 19550224 + setup_id: ABCD # custom setup ID, default: HMXS name: Dahua camera # custom camera name, default: generated from stream ID device_id: dahua1 # custom ID, default: generated from stream ID device_private: dahua1 # custom key, default: generated from stream ID diff --git a/internal/homekit/api.go b/internal/homekit/api.go index abd8e97c..e853b9ae 100644 --- a/internal/homekit/api.go +++ b/internal/homekit/api.go @@ -6,6 +6,7 @@ import ( "net/http" "net/url" "strings" + "strconv" "github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/app" @@ -137,3 +138,56 @@ func findHomeKitURLs() map[string]*url.URL { } return urls } + +type PairingInfo struct { + Name string `yaml:"name"` + DeviceID string `yaml:"device_id"` + Pin string `yaml:"pin"` + Status string `yaml:"status"` + SetupURI string `yaml:"setup_uri"` +} + +func getPairingInfo(host string, s *server) PairingInfo { + // for QR-Code + category, _ := strconv.ParseInt(hap.CategoryCamera, 10, 64) + pin, _ := strconv.ParseInt(strings.Replace(s.hap.Pin, "-", "", -1), 10, 64) + payload := "00000000" + strconv.FormatInt(category << 31 + 1 << 28 + pin, 36) + uri := strings.ToUpper("X-HM://" + payload[len(payload)-9:] + s.hap.SetupID[:4]) + status := "unpaired" + if len(s.pairings) > 0 { + status = "paired" + } + return PairingInfo { + Name: s.mdns.Name , + DeviceID: s.hap.DeviceID, + SetupURI: uri, + Pin: s.hap.Pin, + Status: status, + } +} + +func apiPairingHandler(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + pairingInfo := map[string]PairingInfo{} + for host, s := range servers { + pairingInfo[s.stream] = getPairingInfo(host, s) + } + api.ResponseJSON(w, pairingInfo) + + case "DELETE": + query := r.URL.Query() + name := query.Get("name") + stream := query.Get("stream") + device_id := query.Get("device_id") + for _, s := range servers { + if name == s.mdns.Name || stream == s.stream || device_id == s.hap.DeviceID { + s.pairings = nil + s.UpdateStatus() + s.PatchConfig() + break; + } + } + discovery() + } +} diff --git a/internal/homekit/homekit.go b/internal/homekit/homekit.go index bfe3e971..1ac7d857 100644 --- a/internal/homekit/homekit.go +++ b/internal/homekit/homekit.go @@ -26,6 +26,7 @@ func Init() { Name string `yaml:"name"` DeviceID string `yaml:"device_id"` DevicePrivate string `yaml:"device_private"` + SetupID string `yaml:"setup_id"` Pairings []string `yaml:"pairings"` } `yaml:"homekit"` } @@ -36,6 +37,7 @@ func Init() { streams.HandleFunc("homekit", streamHandler) api.HandleFunc("api/homekit", apiHandler) + api.HandleFunc("api/homekit/pairing", apiPairingHandler) if cfg.Mod == nil { return @@ -62,6 +64,7 @@ func Init() { } deviceID := calcDeviceID(conf.DeviceID, id) // random MAC-address + setupID := (conf.SetupID + "HMXS")[:4] // default setup ID name := calcName(conf.Name, deviceID) srv := &server{ @@ -73,6 +76,7 @@ func Init() { srv.hap = &hap.Server{ Pin: pin, DeviceID: deviceID, + SetupID: setupID, DevicePrivate: calcDevicePrivate(conf.DevicePrivate, id), GetPair: srv.GetPair, AddPair: srv.AddPair, @@ -128,6 +132,7 @@ func Init() { log.Error().Err(err).Caller().Send() } }() + discovery() } var log zerolog.Logger diff --git a/internal/homekit/server.go b/internal/homekit/server.go index cb114fea..fa40f40b 100644 --- a/internal/homekit/server.go +++ b/internal/homekit/server.go @@ -203,6 +203,7 @@ func (s *server) AddPair(conn net.Conn, id string, public []byte, permissions by s.UpdateStatus() s.PatchConfig() } + discovery() } func (s *server) DelPair(conn net.Conn, id string) { @@ -214,11 +215,16 @@ func (s *server) DelPair(conn net.Conn, id string) { continue } - s.pairings = append(s.pairings[:i], s.pairings[i+1:]...) + if strings.Contains(pairing, "permissions=1") { + s.pairings = nil + } else { + s.pairings = append(s.pairings[:i], s.pairings[i+1:]...) + } s.UpdateStatus() s.PatchConfig() break } + discovery() } func (s *server) PatchConfig() { diff --git a/pkg/hap/server.go b/pkg/hap/server.go index 2a912324..a4b61715 100644 --- a/pkg/hap/server.go +++ b/pkg/hap/server.go @@ -23,6 +23,7 @@ type HandlerFunc func(net.Conn) error type Server struct { Pin string DeviceID string + SetupID string DevicePrivate []byte GetPair func(conn net.Conn, id string) []byte @@ -45,7 +46,7 @@ func (s *Server) ServerPublic() []byte { func (s *Server) SetupHash() string { // should be setup_id (random 4 alphanum) + device_id (mac address) // but device_id is random, so OK - b := sha512.Sum512([]byte(s.DeviceID)) + b := sha512.Sum512([]byte(s.SetupID[:4] + s.DeviceID)) return base64.StdEncoding.EncodeToString(b[:4]) } diff --git a/www/links.html b/www/links.html index 940de9fd..96b80997 100644 --- a/www/links.html +++ b/www/links.html @@ -218,5 +218,40 @@