1
+ /*
2
+ Battery Monitor
3
+
4
+ This example creates a BLE peripheral with the standard battery service and
5
+ level characteristic. The A0 pin is used to calculate the battery level.
6
+
7
+ The circuit:
8
+ - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
9
+ Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
10
+
11
+ You can use a generic BLE central app, like LightBlue (iOS and Android) or
12
+ nRF Connect (Android), to interact with the services and characteristics
13
+ created in this sketch.
14
+
15
+ This example code is in the public domain.
16
+ */
17
+
18
+ #include < ArduinoBLE.h>
19
+
20
+
21
+ #define PAIR_BUTTON 3 // button for pairing
22
+ #define PAIR_LED 24 // LED used to signal pairing
23
+ #define PAIR_LED_ON LOW // Blue LED on Nano BLE has inverted logic
24
+ #define PAIR_INTERVAL 30000 // interval for pairing after button press in ms
25
+
26
+ #define CTRL_LED LED_BUILTIN
27
+
28
+
29
+ // BLE Battery Service
30
+ BLEService batteryService (" 180F" );
31
+
32
+ // BLE Battery Level Characteristic
33
+ BLEUnsignedCharCharacteristic batteryLevelChar (" 2A19" , // standard 16-bit characteristic UUID
34
+ BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
35
+ BLEStringCharacteristic stringcharacteristic (" 183E" , BLERead | BLEWrite, 31 );
36
+
37
+
38
+ // Add BLEEncryption tag to require pairing. This controls the LED.
39
+ BLEUnsignedCharCharacteristic secretValue (" 2a3F" , BLERead | BLEWrite | BLEEncryption);
40
+
41
+ int oldBatteryLevel = 0 ; // last battery level reading from analog input
42
+ unsigned long previousMillis = 0 ; // last time the battery level was checked, in ms
43
+ unsigned long pairingStarted = 0 ; // pairing start time when button is pressed
44
+ bool wasConnected = 0 ;
45
+ bool acceptOrReject = true ;
46
+
47
+ void setup () {
48
+ Serial.begin (9600 ); // initialize serial communication
49
+ while (!Serial);
50
+
51
+ pinMode (CTRL_LED, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
52
+ pinMode (PAIR_LED, OUTPUT);
53
+ pinMode (PAIR_BUTTON, INPUT_PULLUP);
54
+
55
+
56
+ Serial.println (" Serial connected" );
57
+
58
+ // Callback function with confirmation code when new device is pairing.
59
+ BLE.setDisplayCode ([](uint32_t confirmCode){
60
+ Serial.println (" New device pairing request." );
61
+ Serial.print (" Confirm code matches pairing device: " );
62
+ char code[6 ];
63
+ sprintf (code, " %06d" , confirmCode);
64
+ Serial.println (code);
65
+ });
66
+
67
+ // Callback to allow accepting or rejecting pairing
68
+ BLE.setBinaryConfirmPairing ([&acceptOrReject](){
69
+ Serial.print (" Should we confirm pairing? " );
70
+ delay (5000 );
71
+ if (acceptOrReject){
72
+ acceptOrReject = false ;
73
+ Serial.println (" yes" );
74
+ return true ;
75
+ }else {
76
+ acceptOrReject = true ;
77
+ Serial.println (" no" );
78
+ return false ;
79
+ }
80
+ });
81
+
82
+ // IRKs are keys that identify the true owner of a random mac address.
83
+ // Add IRKs of devices you are bonded with.
84
+ BLE.setGetIRKs ([](uint8_t * nIRKs, uint8_t ** BDaddrTypes, uint8_t *** BDAddrs, uint8_t *** IRKs){
85
+ // Set to number of devices
86
+ *nIRKs = 2 ;
87
+
88
+ *BDAddrs = new uint8_t *[*nIRKs];
89
+ *IRKs = new uint8_t *[*nIRKs];
90
+ *BDaddrTypes = new uint8_t [*nIRKs];
91
+
92
+ // Set these to the mac and IRK for your bonded devices as printed in the serial console after bonding.
93
+ uint8_t device1Mac[6 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
94
+ uint8_t device1IRK[16 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
95
+
96
+ uint8_t device2Mac[6 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
97
+ uint8_t device2IRK[16 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
98
+
99
+
100
+ (*BDaddrTypes)[0 ] = 0 ; // Type 0 is for pubc address, type 1 is for static random
101
+ (*BDAddrs)[0 ] = new uint8_t [6 ];
102
+ (*IRKs)[0 ] = new uint8_t [16 ];
103
+ memcpy ((*IRKs)[0 ] , device1IRK,16 );
104
+ memcpy ((*BDAddrs)[0 ], device1Mac, 6 );
105
+
106
+
107
+ (*BDaddrTypes)[1 ] = 0 ;
108
+ (*BDAddrs)[1 ] = new uint8_t [6 ];
109
+ (*IRKs)[1 ] = new uint8_t [16 ];
110
+ memcpy ((*IRKs)[1 ] , device2IRK,16 );
111
+ memcpy ((*BDAddrs)[1 ], device2Mac, 6 );
112
+
113
+
114
+ return 1 ;
115
+ });
116
+ // The LTK is the secret key which is used to encrypt bluetooth traffic
117
+ BLE.setGetLTK ([](uint8_t * address, uint8_t * LTK){
118
+ // address is input
119
+ Serial.print (" Received request for address: " );
120
+ btct.printBytes (address,6 );
121
+
122
+ // Set these to the MAC and LTK of your devices after bonding.
123
+ uint8_t device1Mac[6 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
124
+ uint8_t device1LTK[16 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
125
+ uint8_t device2Mac[6 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
126
+ uint8_t device2LTK[16 ] = {0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
127
+
128
+
129
+ if (memcmp (device1Mac, address, 6 ) == 0 ) {
130
+ memcpy (LTK, device1LTK, 16 );
131
+ return 1 ;
132
+ }else if (memcmp (device2Mac, address, 6 ) == 0 ) {
133
+ memcpy (LTK, device2LTK, 16 );
134
+ return 1 ;
135
+ }
136
+ return 0 ;
137
+ });
138
+ BLE.setStoreIRK ([](uint8_t * address, uint8_t * IRK){
139
+ Serial.print (F (" New device with MAC : " ));
140
+ btct.printBytes (address,6 );
141
+ Serial.print (F (" Need to store IRK : " ));
142
+ btct.printBytes (IRK,16 );
143
+ return 1 ;
144
+ });
145
+ BLE.setStoreLTK ([](uint8_t * address, uint8_t * LTK){
146
+ Serial.print (F (" New device with MAC : " ));
147
+ btct.printBytes (address,6 );
148
+ Serial.print (F (" Need to store LTK : " ));
149
+ btct.printBytes (LTK,16 );
150
+ return 1 ;
151
+ });
152
+
153
+ while (1 ){
154
+ // begin initialization
155
+ if (!BLE.begin ()) {
156
+ Serial.println (" starting BLE failed!" );
157
+ delay (200 );
158
+ continue ;
159
+ }
160
+ Serial.println (" BT init" );
161
+ delay (200 );
162
+
163
+ /* Set a local name for the BLE device
164
+ This name will appear in advertising packets
165
+ and can be used by remote devices to identify this BLE device
166
+ The name can be changed but maybe be truncated based on space left in advertisement packet
167
+ */
168
+
169
+ BLE.setDeviceName (" Arduino" );
170
+ BLE.setLocalName (" BatteryMonitor" );
171
+
172
+ BLE.setAdvertisedService (batteryService); // add the service UUID
173
+ batteryService.addCharacteristic (batteryLevelChar); // add the battery level characteristic
174
+ batteryService.addCharacteristic (stringcharacteristic);
175
+ batteryService.addCharacteristic (secretValue);
176
+
177
+ BLE.addService (batteryService); // Add the battery service
178
+ batteryLevelChar.writeValue (oldBatteryLevel); // set initial value for this characteristic
179
+ char * stringCharValue = new char [32 ];
180
+ stringCharValue = " string" ;
181
+ stringcharacteristic.writeValue (stringCharValue);
182
+ secretValue.writeValue (0 );
183
+
184
+ delay (1000 );
185
+
186
+ // prevent pairing until button is pressed (will show a pairing rejected message)
187
+ BLE.setPairable (false );
188
+
189
+ /* Start advertising BLE. It will start continuously transmitting BLE
190
+ advertising packets and will be visible to remote BLE central devices
191
+ until it receives a new connection */
192
+
193
+ // start advertising
194
+ if (!BLE.advertise ()){
195
+ Serial.println (" failed to advertise bluetooth." );
196
+ BLE.stopAdvertise ();
197
+ delay (500 );
198
+ }else {
199
+ Serial.println (" advertising..." );
200
+ break ;
201
+ }
202
+ BLE.end ();
203
+ delay (100 );
204
+ }
205
+ }
206
+
207
+
208
+ void loop () {
209
+ // wait for a BLE central
210
+ BLEDevice central = BLE.central ();
211
+
212
+
213
+ // If button is pressed, allow pairing for 30 sec
214
+ if (!BLE.pairable () && digitalRead (PAIR_BUTTON) == LOW){
215
+ pairingStarted = millis ();
216
+ BLE.setPairable (Pairable::ONCE);
217
+ Serial.println (" Accepting pairing for 30s" );
218
+ } else if (BLE.pairable () && millis () > pairingStarted + PAIR_INTERVAL){
219
+ BLE.setPairable (false );
220
+ Serial.println (" No longer accepting pairing" );
221
+ }
222
+ // Make LED blink while pairing is allowed
223
+ digitalWrite (PAIR_LED, (BLE.pairable () ? (millis ()%400 )<200 : BLE.paired ()) ? PAIR_LED_ON : !PAIR_LED_ON);
224
+
225
+
226
+ // if a central is connected to the peripheral:
227
+ if (central && central.connected ()) {
228
+ if (!wasConnected){
229
+ wasConnected = true ;
230
+ Serial.print (" Connected to central: " );
231
+ // print the central's BT address:
232
+ Serial.println (central.address ());
233
+ }
234
+
235
+ // check the battery level every 200ms
236
+ // while the central is connected:
237
+ long currentMillis = millis ();
238
+ // if 200ms have passed, check the battery level:
239
+ if (currentMillis - previousMillis >= 1000 ) {
240
+ previousMillis = currentMillis;
241
+ updateBatteryLevel ();
242
+ digitalWrite (CTRL_LED, secretValue.value ()>0 ? HIGH : LOW);
243
+ }
244
+ } else if (wasConnected){
245
+ wasConnected = false ;
246
+ Serial.print (" Disconnected from central: " );
247
+ Serial.println (central.address ());
248
+ }
249
+
250
+ }
251
+
252
+ void updateBatteryLevel () {
253
+ /* Read the current voltage level on the A0 analog input pin.
254
+ This is used here to simulate the charge level of a battery.
255
+ */
256
+ int battery = analogRead (A0);
257
+ int batteryLevel = map (battery, 0 , 1023 , 0 , 100 );
258
+
259
+ if (batteryLevel != oldBatteryLevel) { // if the battery level has changed
260
+ // Serial.print("Battery Level % is now: "); // print it
261
+ // Serial.println(batteryLevel);
262
+ batteryLevelChar.writeValue (batteryLevel); // and update the battery level characteristic
263
+ oldBatteryLevel = batteryLevel; // save the level for next comparison
264
+ }
265
+ }
0 commit comments