Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homekit qrcode #1138

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ HomeKit module can work in two modes:
streams:
dahua1: rtsp://admin:[email protected]/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**
Expand All @@ -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
Expand Down
54 changes: 54 additions & 0 deletions internal/homekit/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"strings"
"strconv"

"github.com/AlexxIT/go2rtc/internal/api"
"github.com/AlexxIT/go2rtc/internal/app"
Expand Down Expand Up @@ -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()
}
}
5 changes: 5 additions & 0 deletions internal/homekit/homekit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand All @@ -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
Expand All @@ -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{
Expand All @@ -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,
Expand Down Expand Up @@ -128,6 +132,7 @@ func Init() {
log.Error().Err(err).Caller().Send()
}
}()
discovery()
}

var log zerolog.Logger
Expand Down
8 changes: 7 additions & 1 deletion internal/homekit/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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() {
Expand Down
3 changes: 2 additions & 1 deletion pkg/hap/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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])
}

Expand Down
35 changes: 35 additions & 0 deletions www/links.html
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,40 @@ <h2>WebRTC Magic</h2>
webrtcLinksUpdate();
</script>

<div>
<h2>HomeKit</h2>
<div id="homekit-info"></div>
<div id="homekit-qrcode"></div>
<div id="homekit-unpair"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<script>
const homekit = new URL('api/homekit/pairing', location.href);
fetch(homekit, {cache: 'no-cache'}).then(r => r.json()).then(data => {
try {
const homekitInfo = data[src];
console.log(homekitInfo);
document.getElementById('homekit-info').innerHTML = `
Setup Code : ${homekitInfo.Pin}<br>
Device ID : ${homekitInfo.DeviceID}<br>
Status : ${homekitInfo.Status}<br>
`;
new QRCode('homekit-qrcode', {
text: homekitInfo.SetupURI,
width: 128,
height: 128,
});
document.getElementById('homekit-unpair').innerHTML = '<br><button>unpair</button><br>';
document.getElementById('homekit-unpair').addEventListener('click', ev => {
const unpair = new URL(`api/homekit/pairing?stream=${src}`, location.href);
fetch(unpair, { method: 'DELETE' }).then(data => {
location.reload();
}).catch(e => {
});
});
} catch(e) {
}
});
</script>
</body>
</html>