@@ -12,9 +12,10 @@ import (
1212)
1313
1414type configuration struct {
15- scanTimeout time.Duration
16- sleepAfterDisconnect time.Duration
17- debug bool
15+ scanTimeout time.Duration
16+ sleepAfterDisconnect time.Duration
17+ dropCharacteristicsOnDisconnect bool
18+ debug bool
1819}
1920
2021// Adaptor represents a Client Connection to a BLE Peripheral
@@ -38,8 +39,9 @@ type Adaptor struct {
3839//
3940// Supported options:
4041//
41- // "WithAdaptorDebug"
42- // "WithAdaptorScanTimeout"
42+ // "WithDebug"
43+ // "WithDropCharacteristicsOnDisconnect"
44+ // "WithScanTimeout"
4345func NewAdaptor (identifier string , opts ... optionApplier ) * Adaptor {
4446 cfg := configuration {
4547 scanTimeout : 10 * time .Minute ,
@@ -67,6 +69,13 @@ func WithDebug() debugOption {
6769 return debugOption (true )
6870}
6971
72+ // WithWithDropCharacteristicsOnDisconnect leads to clean all discovered services from last connect command if a
73+ // disconnect command happen. Also all subscriptions will be cleaned. A new discover of services and characteristics is
74+ // done on next connect and the subscriptions needs to be done again afterwards by the caller.
75+ func WithDropCharacteristicsOnDisconnect () dropCharacteristicsOnDisconnect {
76+ return dropCharacteristicsOnDisconnect (true )
77+ }
78+
7079// WithScanTimeout substitute the default scan timeout of 10 min.
7180func WithScanTimeout (timeout time.Duration ) scanTimeoutOption {
7281 return scanTimeoutOption (timeout )
@@ -104,6 +113,10 @@ func (a *Adaptor) Connect() error {
104113 a .mutex .Lock ()
105114 defer a .mutex .Unlock ()
106115
116+ if a .connected {
117+ return fmt .Errorf ("%s is already connected" , a .name )
118+ }
119+
107120 var err error
108121
109122 if a .cfg .debug {
@@ -139,28 +152,30 @@ func (a *Adaptor) Connect() error {
139152 a .rssi = int (result .RSSI )
140153 a .btDevice = dev
141154
142- if a .cfg .debug {
143- fmt .Println ("[Connect]: get all services/characteristics..." )
144- }
145- services , err := a .btDevice .discoverServices (nil )
146- if err != nil {
147- return err
148- }
149- for _ , service := range services {
155+ if len (a .characteristics ) == 0 {
150156 if a .cfg .debug {
151- fmt .Printf ("[Connect]: service found: %s \n " , service )
157+ fmt .Println ("[Connect]: get all services/characteristics..." )
152158 }
153- chars , err := service . DiscoverCharacteristics (nil )
159+ services , err := a . btDevice . discoverServices (nil )
154160 if err != nil {
155- log .Println (err )
156- continue
161+ return err
157162 }
158- for _ , char := range chars {
163+ for _ , service := range services {
159164 if a .cfg .debug {
160- fmt .Printf ("[Connect]: characteristic found: %s\n " , char )
165+ fmt .Printf ("[Connect]: service found: %s\n " , service )
166+ }
167+ chars , err := service .DiscoverCharacteristics (nil )
168+ if err != nil {
169+ log .Println (err )
170+ continue
171+ }
172+ for _ , char := range chars {
173+ if a .cfg .debug {
174+ fmt .Printf ("[Connect]: characteristic found: %s\n " , char )
175+ }
176+ c := char // to prevent implicit memory aliasing in for loop, before go 1.22
177+ a .characteristics [char .UUID ().String ()] = & c
161178 }
162- c := char // to prevent implicit memory aliasing in for loop, before go 1.22
163- a .characteristics [char .UUID ().String ()] = & c
164179 }
165180 }
166181
@@ -187,6 +202,26 @@ func (a *Adaptor) Disconnect() error {
187202 if a .cfg .debug {
188203 fmt .Println ("[Disconnect]: disconnect..." )
189204 }
205+
206+ if a .cfg .dropCharacteristicsOnDisconnect {
207+ if a .cfg .debug {
208+ fmt .Println ("[Disconnect]: unsubscribe..." )
209+ }
210+
211+ for id , chara := range a .characteristics {
212+ if err := adjustNotificationsForCharacteristic (chara , nil ); err != nil {
213+ fmt .Printf ("[Disconnect]: error on unsubscribe characteristic %s: %v\n " , id , err )
214+ }
215+ }
216+
217+ if a .cfg .debug {
218+ fmt .Println ("[Disconnect]: drop characteristics..." )
219+ }
220+ a .characteristics = make (map [string ]bluetoothExtCharacteristicer )
221+ } else if a .cfg .debug {
222+ fmt .Println ("[Disconnect]: as configured, characteristics not dropped" )
223+ }
224+
190225 err := a .btDevice .disconnect ()
191226 time .Sleep (a .cfg .sleepAfterDisconnect )
192227 a .connected = false
@@ -252,7 +287,26 @@ func (a *Adaptor) Subscribe(cUUID string, f func(data []byte)) error {
252287 }
253288
254289 if chara , ok := a .characteristics [cUUID ]; ok {
255- return enableNotificationsForCharacteristic (chara , f )
290+ return adjustNotificationsForCharacteristic (chara , f )
291+ }
292+
293+ return fmt .Errorf ("unknown characteristic: %s" , cUUID )
294+ }
295+
296+ // Unsubscribe remove subscription to notifications from the BLE device for the requested characteristic UUID.
297+ // The UUID can be given as 16-bit or 128-bit (with or without dashes) value.
298+ func (a * Adaptor ) Unsubscribe (cUUID string ) error {
299+ if ! a .connected {
300+ return fmt .Errorf ("cannot unsubscribe from BLE device until connected" )
301+ }
302+
303+ cUUID , err := convertUUID (cUUID )
304+ if err != nil {
305+ return err
306+ }
307+
308+ if chara , ok := a .characteristics [cUUID ]; ok {
309+ return adjustNotificationsForCharacteristic (chara , nil )
256310 }
257311
258312 return fmt .Errorf ("unknown characteristic: %s" , cUUID )
0 commit comments