forked from Elara6331/infinitime
Add call notification support
This commit is contained in:
parent
ce95ce259c
commit
6b602169a0
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
bt "github.com/muka/go-bluetooth/api"
|
||||
@ -17,6 +16,7 @@ const BTName = "InfiniTime"
|
||||
|
||||
const (
|
||||
NewAlertChar = "00002a46-0000-1000-8000-00805f9b34fb"
|
||||
NotifEventChar = "00020001-78fc-48fe-8e23-433b3a1942d0"
|
||||
FirmwareVerChar = "00002a26-0000-1000-8000-00805f9b34fb"
|
||||
CurrentTimeChar = "00002a2b-0000-1000-8000-00805f9b34fb"
|
||||
BatteryLvlChar = "00002a19-0000-1000-8000-00805f9b34fb"
|
||||
@ -27,6 +27,7 @@ type Device struct {
|
||||
opts *Options
|
||||
device *device.Device1
|
||||
newAlertChar *gatt.GattCharacteristic1
|
||||
notifEventChar *gatt.GattCharacteristic1
|
||||
fwVersionChar *gatt.GattCharacteristic1
|
||||
currentTimeChar *gatt.GattCharacteristic1
|
||||
battLevelChar *gatt.GattCharacteristic1
|
||||
@ -41,10 +42,13 @@ var ErrNotFound = errors.New("could not find any advertising InfiniTime devices"
|
||||
|
||||
type Options struct {
|
||||
AttemptReconnect bool
|
||||
WhitelistEnabled bool
|
||||
Whitelist []string
|
||||
}
|
||||
|
||||
var DefaultOptions = &Options{
|
||||
AttemptReconnect: true,
|
||||
WhitelistEnabled: false,
|
||||
}
|
||||
|
||||
// Connect will attempt to connect to a
|
||||
@ -58,7 +62,7 @@ func Connect(opts *Options) (*Device, error) {
|
||||
opts = DefaultOptions
|
||||
}
|
||||
// Attempt to connect to paired device by name
|
||||
dev, err := connectByName()
|
||||
dev, err := connectByName(opts)
|
||||
// If such device does not exist
|
||||
if errors.Is(err, ErrNoDevices) {
|
||||
// Attempt to pair device
|
||||
@ -128,7 +132,7 @@ func (i *Device) OnReconnect(f func()) {
|
||||
}
|
||||
|
||||
// Connect connects to a paired InfiniTime device
|
||||
func connectByName() (*Device, error) {
|
||||
func connectByName(opts *Options) (*Device, error) {
|
||||
// Create new device
|
||||
out := &Device{}
|
||||
// Get devices from default adapter
|
||||
@ -140,6 +144,9 @@ func connectByName() (*Device, error) {
|
||||
for _, dev := range devs {
|
||||
// If device name is InfiniTime
|
||||
if dev.Properties.Name == BTName {
|
||||
if opts.WhitelistEnabled && !contains(opts.Whitelist, dev.Properties.Address) {
|
||||
continue
|
||||
}
|
||||
// Set outout device to discovered device
|
||||
out.device = dev
|
||||
break
|
||||
@ -161,6 +168,15 @@ func connectByName() (*Device, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func contains(ss []string, s string) bool {
|
||||
for _, str := range ss {
|
||||
if str == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Pair attempts to discover and pair an InfiniTime device
|
||||
func pair() (*Device, error) {
|
||||
// Create new device
|
||||
@ -259,6 +275,8 @@ func (i *Device) resolveChars() error {
|
||||
switch char.Properties.UUID {
|
||||
case NewAlertChar:
|
||||
i.newAlertChar = char
|
||||
case NotifEventChar:
|
||||
i.notifEventChar = char
|
||||
case FirmwareVerChar:
|
||||
i.fwVersionChar = char
|
||||
case CurrentTimeChar:
|
||||
@ -414,7 +432,55 @@ func (i *Device) Notify(title, body string) error {
|
||||
return nil
|
||||
}
|
||||
return i.newAlertChar.WriteValue(
|
||||
[]byte(fmt.Sprintf("00\x00%s\x00%s", title, body)),
|
||||
append([]byte{0x00, 0x01, 0x00}, []byte(title+"\x00"+body)...),
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// These constants represent the possible call statuses selected by the user
|
||||
const (
|
||||
CallStatusDeclined uint8 = iota
|
||||
CallStatusAccepted
|
||||
CallStatusMuted
|
||||
)
|
||||
|
||||
// NotifyCall sends a call notification to the PineTime and returns a channel.
|
||||
// This channel will contain the user's response to the call notification. It
|
||||
// can only contain one value.
|
||||
func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan uint8), nil
|
||||
}
|
||||
// Write call notification to new alert characteristic
|
||||
err := i.newAlertChar.WriteValue(
|
||||
append([]byte{0x03, 0x01, 0x00}, []byte(from)...),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Start notifications on notification event characteristic
|
||||
err = i.notifEventChar.StartNotify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Watch properties of notification event characteristic
|
||||
ch, err := i.notifEventChar.WatchProperties()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create new output channel for status
|
||||
out := make(chan uint8, 1)
|
||||
go func() {
|
||||
// For every event
|
||||
for event := range ch {
|
||||
// If value changed
|
||||
if event.Name == "Value" {
|
||||
// Send status to channel
|
||||
out <- uint8(event.Value.([]byte)[0])
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user