Create custom BlueZ agent
This commit is contained in:
@@ -59,12 +59,14 @@ var (
|
||||
ErrNotConnected = errors.New("not connected")
|
||||
ErrCharNotAvail = errors.New("required characteristic is not available")
|
||||
ErrNoTimelineHeader = errors.New("events must contain the timeline header")
|
||||
ErrPairTimeout = errors.New("reached timeout while pairing")
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
AttemptReconnect bool
|
||||
WhitelistEnabled bool
|
||||
Whitelist []string
|
||||
OnReqPasskey func() (uint32, error)
|
||||
}
|
||||
|
||||
var DefaultOptions = &Options{
|
||||
@@ -94,6 +96,8 @@ func Connect(opts *Options) (*Device, error) {
|
||||
}
|
||||
dev.opts = opts
|
||||
dev.onReconnect = func() {}
|
||||
setOnPasskeyReq(opts.OnReqPasskey)
|
||||
|
||||
// Watch device properties
|
||||
devEvtCh, err := dev.device.WatchProperties()
|
||||
if err != nil {
|
||||
@@ -121,14 +125,29 @@ func Connect(opts *Options) (*Device, error) {
|
||||
dev.device.Properties.Connected = false
|
||||
// While not connected
|
||||
for !dev.device.Properties.Connected {
|
||||
// Attempt to connect via bluetooth address
|
||||
reConnDev, err := ConnectByAddress(dev.device.Properties.Address)
|
||||
reConnDev := dev
|
||||
|
||||
paired, err := reConnDev.device.GetPaired()
|
||||
if err != nil {
|
||||
// Decrement disconnect event number
|
||||
disconnEvtNum--
|
||||
// Skip rest of loop
|
||||
continue
|
||||
}
|
||||
|
||||
if !paired {
|
||||
err = reConnDev.pairTimeout()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// Attempt to connect via bluetooth address
|
||||
reConnDev, err = connectByName(opts)
|
||||
if err != nil {
|
||||
// Decrement disconnect event number
|
||||
disconnEvtNum--
|
||||
// Skip rest of loop
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Store onReconn callback
|
||||
onReconn := dev.onReconnect
|
||||
// Set device to new device
|
||||
@@ -154,6 +173,7 @@ func (i *Device) OnReconnect(f func()) {
|
||||
|
||||
// Connect connects to a paired InfiniTime device
|
||||
func connectByName(opts *Options) (*Device, error) {
|
||||
setOnPasskeyReq(opts.OnReqPasskey)
|
||||
// Create new device
|
||||
out := &Device{}
|
||||
// Get devices from default adapter
|
||||
@@ -203,6 +223,7 @@ func contains(ss []string, s string) bool {
|
||||
|
||||
// Pair attempts to discover and pair an InfiniTime device
|
||||
func pair(opts *Options) (*Device, error) {
|
||||
setOnPasskeyReq(opts.OnReqPasskey)
|
||||
// Create new device
|
||||
out := &Device{}
|
||||
// Start bluetooth discovery
|
||||
@@ -237,10 +258,17 @@ func pair(opts *Options) (*Device, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
// Pair device
|
||||
out.device.Pair()
|
||||
// Connect to device
|
||||
err = out.device.Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.device.Properties.Connected = true
|
||||
// Pair device
|
||||
err = out.pairTimeout()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set connected to true
|
||||
out.device.Properties.Connected = true
|
||||
@@ -254,32 +282,33 @@ func pair(opts *Options) (*Device, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ConnectByAddress tries to connect to an InifiniTime at
|
||||
// the specified InfiniTime address
|
||||
func ConnectByAddress(addr string) (*Device, error) {
|
||||
var err error
|
||||
// Create new device
|
||||
out := &Device{}
|
||||
// Get device from bluetooth address
|
||||
out.device, err = defaultAdapter.GetDeviceByAddress(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// setOnPasskeyReq sets the callback for a passkey request.
|
||||
// It ensures the function will never be nil.
|
||||
func setOnPasskeyReq(onReqPasskey func() (uint32, error)) {
|
||||
itdAgent.ReqPasskey = onReqPasskey
|
||||
if itdAgent.ReqPasskey == nil {
|
||||
itdAgent.ReqPasskey = func() (uint32, error) {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to device
|
||||
err = out.device.Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// pairTimeout tries to pair with the device.
|
||||
// It will time out after 20 seconds.
|
||||
func (i *Device) pairTimeout() error {
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
errCh <- i.device.Pair()
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-time.After(20 * time.Second):
|
||||
if err := i.device.CancelPairing(); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrPairTimeout
|
||||
}
|
||||
|
||||
out.device.Properties.Connected = true
|
||||
|
||||
// Resolve characteristics
|
||||
err = out.resolveChars()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// resolveChars attempts to set all required
|
||||
@@ -719,7 +748,11 @@ func (i *Device) AddWeatherEvent(event interface{}) error {
|
||||
}
|
||||
|
||||
func (i *Device) checkStatus(char *gatt.GattCharacteristic1) error {
|
||||
if !i.device.Properties.Connected {
|
||||
connected, err := i.device.GetConnected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !connected {
|
||||
return ErrNotConnected
|
||||
}
|
||||
if char == nil {
|
||||
|
||||
Reference in New Issue
Block a user