|
| 1 | +#include "Nicla_System.h" |
| 2 | +#include <ArduinoBLE.h> |
| 3 | + |
| 4 | +constexpr auto printInterval { 2000ul }; |
| 5 | +constexpr auto batteryMeasureInterval { 5000ul }; |
| 6 | +int8_t batteryChargeLevel = -1; |
| 7 | +int8_t batteryPercentage = -1; |
| 8 | +float batteryVoltage = -1.0f; |
| 9 | + |
| 10 | + |
| 11 | +#define DEVICE_NAME "NiclaSenseME" |
| 12 | +#define DEVICE_UUID(val) ("19b10000-" val "-537e-4f6c-d104768a1214") |
| 13 | +BLEService service(DEVICE_UUID("0000")); |
| 14 | + |
| 15 | +BLEIntCharacteristic batteryPercentageCharacteristic(DEVICE_UUID("1001"), BLERead | BLENotify); |
| 16 | +BLEFloatCharacteristic batteryVoltageCharacteristic(DEVICE_UUID("1002"), BLERead | BLENotify); |
| 17 | +BLEIntCharacteristic batteryChargeLevelCharacteristic(DEVICE_UUID("1003"), BLERead | BLENotify); |
| 18 | + |
| 19 | +bool updateBatteryLevel(bool enforceNewReading = false) { |
| 20 | + static auto updateTimestamp = millis(); |
| 21 | + bool intervalFired = millis() - updateTimestamp >= batteryMeasureInterval; |
| 22 | + bool isFirstReading = batteryPercentage == -1 || batteryVoltage == -1.0f; |
| 23 | + |
| 24 | + if (intervalFired || isFirstReading || enforceNewReading) { |
| 25 | + Serial.println("Checking the battery level..."); |
| 26 | + updateTimestamp = millis(); |
| 27 | + auto percentage = nicla::getBatteryPercentage(); |
| 28 | + |
| 29 | + if (percentage < 0) { |
| 30 | + return false; // Percentage couldn't be determined. |
| 31 | + } |
| 32 | + |
| 33 | + if (batteryPercentage != percentage) { |
| 34 | + batteryPercentage = percentage; |
| 35 | + batteryVoltage = nicla::getCurrentBatteryVoltage(); |
| 36 | + batteryChargeLevel = nicla::getBatteryChargeLevel(); |
| 37 | + |
| 38 | + Serial.print("New battery level: "); |
| 39 | + Serial.println(batteryPercentage); |
| 40 | + |
| 41 | + return true; |
| 42 | + } |
| 43 | + } |
| 44 | + |
| 45 | + return false; |
| 46 | +} |
| 47 | + |
| 48 | +String getBatteryTemperatureDescription(int status) { |
| 49 | + switch (status) { |
| 50 | + case BATTERY_TEMPERATURE_NORMAL: |
| 51 | + return "Normal"; |
| 52 | + case BATTERY_TEMPERATURE_EXTREME: |
| 53 | + return "Extreme"; |
| 54 | + case BATTERY_TEMPERTURE_COOL: |
| 55 | + return "Cool"; |
| 56 | + case BATTERY_TEMPERTURE_WARM: |
| 57 | + return "Warm"; |
| 58 | + default: |
| 59 | + return "Unknown"; |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +String getBatteryChargeLevelDescription(int status) { |
| 64 | + switch (status) { |
| 65 | + case BATTERY_EMPTY: |
| 66 | + return "Empty"; |
| 67 | + case BATTERY_ALMOST_EMPTY: |
| 68 | + return "Almost Empty"; |
| 69 | + case BATTERY_HALF: |
| 70 | + return "Half Full"; |
| 71 | + case BATTERY_ALMOST_FULL: |
| 72 | + return "Almost Full"; |
| 73 | + case BATTERY_FULL: |
| 74 | + return "Full"; |
| 75 | + default: |
| 76 | + return "Unknown"; |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | + |
| 81 | +void blePeripheralDisconnectHandler(BLEDevice central) { |
| 82 | + nicla::leds.setColor(red); |
| 83 | + Serial.println("Device disconnected."); |
| 84 | +} |
| 85 | + |
| 86 | +void blePeripheralConnectHandler(BLEDevice central) { |
| 87 | + nicla::leds.setColor(blue); |
| 88 | + Serial.println("Device connected."); |
| 89 | +} |
| 90 | + |
| 91 | +void onBatteryVoltageCharacteristicRead(BLEDevice central, BLECharacteristic characteristic) { |
| 92 | + Serial.println("Requesting battery voltage..."); |
| 93 | + updateBatteryLevel(); |
| 94 | + Serial.print("Battery voltage: "); |
| 95 | + Serial.println(batteryVoltage); |
| 96 | + batteryVoltageCharacteristic.writeValue(batteryVoltage); |
| 97 | +} |
| 98 | + |
| 99 | +void onBatteryPercentageCharacteristicRead(BLEDevice central, BLECharacteristic characteristic) { |
| 100 | + Serial.println("Requesting battery percentage..."); |
| 101 | + updateBatteryLevel(); |
| 102 | + Serial.print("Battery Percent: "); |
| 103 | + Serial.println(batteryPercentage); |
| 104 | + batteryPercentageCharacteristic.writeValue(batteryPercentage); |
| 105 | +} |
| 106 | + |
| 107 | +void onBatteryChargeLevelCharacteristicRead(BLEDevice central, BLECharacteristic characteristic) { |
| 108 | + Serial.println("Requesting battery charge level..."); |
| 109 | + updateBatteryLevel(); |
| 110 | + Serial.print("Battery Charge Level: "); |
| 111 | + Serial.println(batteryChargeLevel); |
| 112 | + batteryChargeLevelCharacteristic.writeValue(batteryChargeLevel); |
| 113 | +} |
| 114 | + |
| 115 | +void onCharacteristicSubscribed(BLEDevice central, BLECharacteristic characteristic) { |
| 116 | + Serial.println("Device subscribed to characteristic: " + String(characteristic.uuid())); |
| 117 | +} |
| 118 | + |
| 119 | +void setupBLE() { |
| 120 | + if (!BLE.begin()) { |
| 121 | + Serial.println("Failed to initialized BLE!"); |
| 122 | + |
| 123 | + while (true) { |
| 124 | + // Blink the red LED to indicate failure |
| 125 | + nicla::leds.setColor(red); |
| 126 | + delay(500); |
| 127 | + nicla::leds.setColor(off); |
| 128 | + delay(500); |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + BLE.setLocalName(DEVICE_NAME); |
| 133 | + BLE.setDeviceName(DEVICE_NAME); |
| 134 | + BLE.setAdvertisedService(service); |
| 135 | + BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); |
| 136 | + BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler); |
| 137 | + |
| 138 | + service.addCharacteristic(batteryPercentageCharacteristic); |
| 139 | + batteryPercentageCharacteristic.setEventHandler(BLERead, onBatteryPercentageCharacteristicRead); |
| 140 | + batteryPercentageCharacteristic.setEventHandler(BLESubscribed, onCharacteristicSubscribed); |
| 141 | + batteryPercentageCharacteristic.writeValue(batteryPercentage); |
| 142 | + |
| 143 | + service.addCharacteristic(batteryVoltageCharacteristic); |
| 144 | + batteryVoltageCharacteristic.setEventHandler(BLERead, onBatteryVoltageCharacteristicRead); |
| 145 | + batteryVoltageCharacteristic.setEventHandler(BLESubscribed, onCharacteristicSubscribed); |
| 146 | + batteryVoltageCharacteristic.writeValue(batteryVoltage); |
| 147 | + |
| 148 | + service.addCharacteristic(batteryChargeLevelCharacteristic); |
| 149 | + batteryChargeLevelCharacteristic.setEventHandler(BLERead, onBatteryChargeLevelCharacteristicRead); |
| 150 | + batteryChargeLevelCharacteristic.setEventHandler(BLESubscribed, onCharacteristicSubscribed); |
| 151 | + batteryChargeLevelCharacteristic.writeValue(batteryChargeLevel); |
| 152 | + |
| 153 | + BLE.addService(service); |
| 154 | + BLE.advertise(); |
| 155 | +} |
| 156 | + |
| 157 | +void setup() |
| 158 | +{ |
| 159 | + Serial.begin(115200); |
| 160 | + for (const auto timeout = millis() + 2500; millis() < timeout && !Serial; delay(250)); |
| 161 | + |
| 162 | + // run this code once when Nicla Sense ME board turns on |
| 163 | + nicla::begin(); // initialise library |
| 164 | + nicla::leds.begin(); // Start I2C connection |
| 165 | + |
| 166 | + nicla::ntc_disabled = false; // Set to true for standard LiPo batteries without NTC |
| 167 | + setupBLE(); |
| 168 | + |
| 169 | + nicla::leds.setColor(green); |
| 170 | +} |
| 171 | + |
| 172 | +void loop() |
| 173 | +{ |
| 174 | + //BLE.poll(); // Implicit when calling BLE.connected(). Uncomment when only using BLERead |
| 175 | + |
| 176 | + if (BLE.connected()) { |
| 177 | + bool newBatteryLevelAvailable = updateBatteryLevel(); |
| 178 | + |
| 179 | + if (batteryPercentageCharacteristic.subscribed() && newBatteryLevelAvailable) { |
| 180 | + Serial.print("Battery Percentage: "); |
| 181 | + Serial.println(batteryPercentage); |
| 182 | + batteryPercentageCharacteristic.writeValue(batteryPercentage); |
| 183 | + } |
| 184 | + |
| 185 | + if (batteryVoltageCharacteristic.subscribed() && newBatteryLevelAvailable) { |
| 186 | + Serial.print("Battery Voltage: "); |
| 187 | + Serial.println(batteryVoltage); |
| 188 | + batteryVoltageCharacteristic.writeValue(batteryVoltage); |
| 189 | + } |
| 190 | + |
| 191 | + if (batteryChargeLevelCharacteristic.subscribed() && newBatteryLevelAvailable) { |
| 192 | + Serial.print("Battery charge level: "); |
| 193 | + Serial.println(batteryChargeLevel); |
| 194 | + batteryChargeLevelCharacteristic.writeValue(batteryChargeLevel); |
| 195 | + } |
| 196 | + |
| 197 | + return; |
| 198 | + } |
| 199 | + |
| 200 | + static auto updateTimestamp = millis(); |
| 201 | + |
| 202 | + if (millis() - updateTimestamp >= printInterval) { |
| 203 | + updateTimestamp = millis(); |
| 204 | + |
| 205 | + float voltage = nicla::getCurrentBatteryVoltage(); |
| 206 | + Serial.print("Voltage: "); |
| 207 | + Serial.println(voltage); |
| 208 | + |
| 209 | + Serial.print("Battery Percent: "); |
| 210 | + auto percent = nicla::getBatteryPercentage(); |
| 211 | + Serial.println(percent); |
| 212 | + |
| 213 | + Serial.print("Battery Temperature: "); |
| 214 | + auto temperature = nicla::getBatteryTemperature(); |
| 215 | + Serial.println(getBatteryTemperatureDescription(temperature)); |
| 216 | + |
| 217 | + auto chargeLevel = nicla::getBatteryChargeLevel(); |
| 218 | + Serial.println("Battery is " + getBatteryChargeLevelDescription(chargeLevel)); |
| 219 | + Serial.println("----------------------"); |
| 220 | + } |
| 221 | +} |
0 commit comments