|
| 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 | + // BLE Battery Service |
| 22 | +BLEService batteryService("180F"); |
| 23 | + |
| 24 | +// BLE Battery Level Characteristic |
| 25 | +BLEUnsignedCharCharacteristic batteryLevelChar("2A19", // standard 16-bit characteristic UUID |
| 26 | + BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes |
| 27 | +BLEStringCharacteristic stringcharacteristic("183E", BLERead | BLEWrite, 31); |
| 28 | + |
| 29 | + |
| 30 | +// Add BLEEncryption tag to require pairing. This controls the LED. |
| 31 | +BLEUnsignedCharCharacteristic secretValue("2a3F", BLERead | BLEWrite | BLEEncryption); |
| 32 | + |
| 33 | +int oldBatteryLevel = 0; // last battery level reading from analog input |
| 34 | +long previousMillis = 0; // last time the battery level was checked, in ms |
| 35 | + |
| 36 | +void setup() { |
| 37 | + Serial.begin(9600); // initialize serial communication |
| 38 | + while (!Serial); |
| 39 | + |
| 40 | + pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected |
| 41 | + |
| 42 | + |
| 43 | + Serial.println("Serial connected"); |
| 44 | + |
| 45 | + // IRKs are keys that identify the true owner of a random mac address. |
| 46 | + // Add IRKs of devices you are bonded with. |
| 47 | + BLE.setGetIRKs([](uint8_t* nIRKs, uint8_t** BADDR_TYPES, uint8_t*** BDAddrs, uint8_t*** IRKs){ |
| 48 | + // Set to number of devices |
| 49 | + *nIRKs = 2; |
| 50 | + |
| 51 | + *BDAddrs = new uint8_t*[*nIRKs]; |
| 52 | + *IRKs = new uint8_t*[*nIRKs]; |
| 53 | + *BADDR_TYPES = new uint8_t[*nIRKs]; |
| 54 | + |
| 55 | + // Set these to the mac and IRK for your bonded devices as printed in the serial console after bonding. |
| 56 | + uint8_t iPhoneMac [6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 57 | + uint8_t iPhoneIRK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 58 | + |
| 59 | + uint8_t iPadMac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 60 | + uint8_t iPadIRK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; |
| 61 | + |
| 62 | + |
| 63 | + (*BADDR_TYPES)[0] = 0; |
| 64 | + (*IRKs)[0] = new uint8_t[16]; |
| 65 | + memcpy((*IRKs)[0],iPhoneIRK,16); |
| 66 | + (*BDAddrs)[0] = new uint8_t[6]; |
| 67 | + memcpy((*BDAddrs)[0], iPhoneMac, 6); |
| 68 | + |
| 69 | + |
| 70 | + (*BADDR_TYPES)[1] = 0; |
| 71 | + (*IRKs)[1] = new uint8_t[16]; |
| 72 | + memcpy((*IRKs)[1],iPadIRK,16); |
| 73 | + (*BDAddrs)[1] = new uint8_t[6]; |
| 74 | + memcpy((*BDAddrs)[1], iPadMac, 6); |
| 75 | + |
| 76 | + |
| 77 | + return 1; |
| 78 | + }); |
| 79 | + // The LTK is the secret key which is used to encrypt bluetooth traffic |
| 80 | + BLE.setGetLTK([](uint8_t* address, uint8_t* LTK){ |
| 81 | + // address is input |
| 82 | + Serial.print("Recieved request for address: "); |
| 83 | + btct.printBytes(address,6); |
| 84 | + |
| 85 | + // Set these to the MAC and LTK of your devices after bonding. |
| 86 | + uint8_t iPhoneMac [6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 87 | + uint8_t iPhoneLTK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 88 | + uint8_t iPadMac [6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 89 | + uint8_t iPadLTK[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 90 | + |
| 91 | + |
| 92 | + if(memcmp(iPhoneMac, address, 6)==0){ |
| 93 | + memcpy(LTK, iPhoneLTK, 16); |
| 94 | + return 1; |
| 95 | + }else if(memcmp(iPadMac, address, 6)==0){ |
| 96 | + memcpy(LTK, iPadLTK, 16); |
| 97 | + } |
| 98 | + return 0; |
| 99 | + }); |
| 100 | + BLE.setStoreIRK([](uint8_t* address, uint8_t* IRK){ |
| 101 | + Serial.print(F("New device with MAC : ")); |
| 102 | + btct.printBytes(address,6); |
| 103 | + Serial.print(F("Need to store IRK : ")); |
| 104 | + btct.printBytes(IRK,16); |
| 105 | + return 1; |
| 106 | + }); |
| 107 | + BLE.setStoreLTK([](uint8_t* address, uint8_t* LTK){ |
| 108 | + Serial.print(F("New device with MAC : ")); |
| 109 | + btct.printBytes(address,6); |
| 110 | + Serial.print(F("Need to store LTK : ")); |
| 111 | + btct.printBytes(LTK,16); |
| 112 | + return 1; |
| 113 | + }); |
| 114 | + |
| 115 | + while(1){// begin initialization |
| 116 | + if (!BLE.begin()) { |
| 117 | + Serial.println("starting BLE failed!"); |
| 118 | + delay(200); |
| 119 | + continue; |
| 120 | + } |
| 121 | + Serial.println("BT init"); |
| 122 | + delay(200); |
| 123 | + |
| 124 | + /* Set a local name for the BLE device |
| 125 | + This name will appear in advertising packets |
| 126 | + and can be used by remote devices to identify this BLE device |
| 127 | + The name can be changed but maybe be truncated based on space left in advertisement packet |
| 128 | + */ |
| 129 | + |
| 130 | + BLE.setDeviceName("Arduino"); |
| 131 | + BLE.setLocalName("BatteryMonitor"); |
| 132 | + |
| 133 | + BLE.setAdvertisedService(batteryService); // add the service UUID |
| 134 | + batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic |
| 135 | + batteryService.addCharacteristic(stringcharacteristic); |
| 136 | + batteryService.addCharacteristic(secretValue); |
| 137 | + |
| 138 | + BLE.addService(batteryService); // Add the battery service |
| 139 | + batteryLevelChar.writeValue(oldBatteryLevel); // set initial value for this characteristic |
| 140 | + char* stringCharValue = new char[32]; |
| 141 | + stringCharValue = "string"; |
| 142 | + stringcharacteristic.writeValue(stringCharValue); |
| 143 | + secretValue.writeValue(0); |
| 144 | + |
| 145 | + delay(1000); |
| 146 | + |
| 147 | + /* Start advertising BLE. It will start continuously transmitting BLE |
| 148 | + advertising packets and will be visible to remote BLE central devices |
| 149 | + until it receives a new connection */ |
| 150 | + |
| 151 | + // start advertising |
| 152 | + if(!BLE.advertise()){ |
| 153 | + Serial.println("failed to advertise bluetooth."); |
| 154 | + BLE.stopAdvertise(); |
| 155 | + delay(500); |
| 156 | + }else{ |
| 157 | + Serial.println("advertising..."); |
| 158 | + break; |
| 159 | + } |
| 160 | + BLE.end(); |
| 161 | + delay(100); |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | + |
| 166 | +void loop() { |
| 167 | + // wait for a BLE central |
| 168 | + BLEDevice central = BLE.central(); |
| 169 | + |
| 170 | + // if a central is connected to the peripheral: |
| 171 | + if (central) { |
| 172 | + Serial.print("Connected to central: "); |
| 173 | + // print the central's BT address: |
| 174 | + Serial.println(central.address()); |
| 175 | + |
| 176 | + // check the battery level every 200ms |
| 177 | + // while the central is connected: |
| 178 | + while (central.connected()) { |
| 179 | + long currentMillis = millis(); |
| 180 | + // if 200ms have passed, check the battery level: |
| 181 | + if (currentMillis - previousMillis >= 1000) { |
| 182 | + previousMillis = currentMillis; |
| 183 | + updateBatteryLevel(); |
| 184 | + if(secretValue.value()>0){ |
| 185 | + digitalWrite(13,HIGH); |
| 186 | + }else{ |
| 187 | + digitalWrite(13,LOW); |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + Serial.print("Disconnected from central: "); |
| 192 | + Serial.println(central.address()); |
| 193 | + } |
| 194 | +} |
| 195 | + |
| 196 | +void updateBatteryLevel() { |
| 197 | + /* Read the current voltage level on the A0 analog input pin. |
| 198 | + This is used here to simulate the charge level of a battery. |
| 199 | + */ |
| 200 | + int battery = analogRead(A0); |
| 201 | + int batteryLevel = map(battery, 0, 1023, 0, 100); |
| 202 | + |
| 203 | + if (batteryLevel != oldBatteryLevel) { // if the battery level has changed |
| 204 | + // Serial.print("Battery Level % is now: "); // print it |
| 205 | + // Serial.println(batteryLevel); |
| 206 | + batteryLevelChar.writeValue(batteryLevel); // and update the battery level characteristic |
| 207 | + oldBatteryLevel = batteryLevel; // save the level for next comparison |
| 208 | + } |
| 209 | +} |
0 commit comments