175 | * This method is called from the main thread when the services has been discovered and 176 | * the device is supported (has required service). 177 | *
178 | * Remember to call {@link Request#enqueue()} for each request. 179 | *
180 | * A sample initialization should look like this: 181 | *
182 | * @Override 183 | * protected void initialize() { 184 | * requestMtu(MTU) 185 | * .with((device, mtu) -> { 186 | * ... 187 | * }) 188 | * .enqueue(); 189 | * setNotificationCallback(characteristic) 190 | * .with((device, data) -> { 191 | * ... 192 | * }); 193 | * enableNotifications(characteristic) 194 | * .done(device -> { 195 | * ... 196 | * }) 197 | * .fail((device, status) -> { 198 | * ... 199 | * }) 200 | * .enqueue(); 201 | * } 202 | *203 | */ 204 | override fun initialize() { 205 | Timber.i("Initialising...") 206 | 207 | enableNotifications(espDisplayTimeCharacteristic) 208 | .done(SuccessCallback { 209 | Timber.i("Successfully enabled DisplayMessageCharacteristic notifications") 210 | }) 211 | .fail { device, status -> 212 | Timber.w("Failed to enable DisplayMessageCharacteristic notifications") 213 | }.enqueue() 214 | enableIndications(espDisplayMessageCharacteristic) 215 | .done(SuccessCallback { 216 | Timber.i("Successfully wrote message") 217 | }) 218 | .fail(FailCallback { device, status -> 219 | Timber.w("Failed to write message to ${device.address} - status: ${status}") 220 | }) 221 | .enqueue() 222 | 223 | // requestMtu(MTU).enqueue() 224 | setNotificationCallback(espDisplayTimeCharacteristic) 225 | .with(DataReceivedCallback { device, data -> 226 | Timber.i("Data received from ${device.address}") 227 | }) 228 | enableNotifications(espDisplayTimeCharacteristic) 229 | .done(SuccessCallback { 230 | Timber.i("Successfully enabled DisplayTimeCharacteristic notifications") 231 | }) 232 | .fail { device, status -> 233 | Timber.w("Failed to enable DisplayTimeCharacteristic notifications") 234 | }.enqueue() 235 | enableIndications(espDisplayTimeCharacteristic) 236 | .done(SuccessCallback { 237 | Timber.i("Successfully wrote Time & Battery status") 238 | }) 239 | .fail(FailCallback { device, status -> 240 | Timber.w("Failed to write Time & Battery status to ${device.address} - status: ${status}") 241 | }).enqueue() 242 | 243 | val batteryLevelPercent = Companion.readBatteryLevel(context) 244 | writeTimeAndBatteryLevel(batteryLevelPercent, ForegroundService.formatter.format(Date())) 245 | } 246 | 247 | /** 248 | * This method should nullify all services and characteristics of the device. 249 | * It's called when the device is no longer connected, either due to user action 250 | * or a link loss. 251 | */ 252 | override fun onDeviceDisconnected() { 253 | espDisplayMessageCharacteristic = null 254 | espDisplayTimeCharacteristic = null 255 | espDisplayOrientationCharacteristic = null 256 | } 257 | } 258 | } -------------------------------------------------------------------------------- /app/src/main/java/za/co/mitchwongho/example/esp32/alerts/ble/LeManagerCallbacks.kt: -------------------------------------------------------------------------------- 1 | package za.co.mitchwongho.example.esp32.alerts.ble 2 | 3 | import android.bluetooth.BluetoothDevice 4 | import no.nordicsemi.android.ble.BleManagerCallbacks 5 | import timber.log.Timber 6 | 7 | /** 8 | * Implements the BLEManager callback methods 9 | */ 10 | open class LeManagerCallbacks : BleManagerCallbacks { 11 | 12 | /** 13 | * Called when the Android device started connecting to given device. 14 | * The [.onDeviceConnected] will be called when the device is connected, 15 | * or [.onError] in case of error. 16 | * @param device the device that got connected 17 | */ 18 | override fun onDeviceConnecting(device: BluetoothDevice) { 19 | Timber.d("onDeviceConnecting {address=${device.address},name=${device.name}}") 20 | } 21 | 22 | /** 23 | * Called when the device has been connected. This does not mean that the application may start communication. 24 | * A service discovery will be handled automatically after this call. Service discovery 25 | * may ends up with calling [.onServicesDiscovered] or 26 | * [.onDeviceNotSupported] if required services have not been found. 27 | * @param device the device that got connected 28 | */ 29 | override fun onDeviceConnected(device: BluetoothDevice) { 30 | 31 | Timber.d("onDeviceConnected {address=${device.address},name=${device.name}}") 32 | } 33 | 34 | /** 35 | * Called when user initialized disconnection. 36 | * @param device the device that gets disconnecting 37 | */ 38 | override fun onDeviceDisconnecting(device: BluetoothDevice) { 39 | Timber.d("onDeviceDisconnecting {address=${device.address},name=${device.name}}") 40 | } 41 | 42 | /** 43 | * Called when the device has disconnected (when the callback returned 44 | * [BluetoothGattCallback.onConnectionStateChange] with state DISCONNECTED), 45 | * but ONLY if the [BleManager.shouldAutoConnect] method returned false for this device when it was connecting. 46 | * Otherwise the [.onLinklossOccur] method will be called instead. 47 | * @param device the device that got disconnected 48 | */ 49 | override fun onDeviceDisconnected(device: BluetoothDevice) { 50 | Timber.d("onDeviceDisconnected {address=${device.address},name=${device.name}}") 51 | } 52 | 53 | /** 54 | * This callback is invoked when the Ble Manager lost connection to a device that has been connected 55 | * with autoConnect option (see [BleManager.shouldAutoConnect]. 56 | * Otherwise a [.onDeviceDisconnected] method will be called on such event. 57 | * @param device the device that got disconnected due to a link loss 58 | */ 59 | override fun onLinkLossOccurred(device: BluetoothDevice) { 60 | Timber.d("onLinklossOccur {address=${device.address},name=${device.name}}") 61 | } 62 | 63 | /** 64 | * Called when service discovery has finished and primary services has been found. 65 | * This method is not called if the primary, mandatory services were not found during service discovery. 66 | * For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and 67 | * Intermediate Cuff Pressure service is a optional secondary service. 68 | * Existence of battery service is not notified by this call. 69 | * 70 | * After successful service discovery the service will initialize all services. 71 | * The [.onDeviceReady] method will be called when the initialization is complete. 72 | * 73 | * @param device the device which services got disconnected 74 | * @param optionalServicesFound 75 | * if `true` the secondary services were also found on the device. 76 | */ 77 | override fun onServicesDiscovered(device: BluetoothDevice, optionalServicesFound: Boolean) { 78 | Timber.d("onServiceDiscovered {address=${device.address},name=${device.name}}") 79 | } 80 | 81 | /** 82 | * Method called when all initialization requests has been completed. 83 | * @param device the device that get ready 84 | */ 85 | override fun onDeviceReady(device: BluetoothDevice) { 86 | Timber.d("onDeviceReady {address=${device.address},name=${device.name}}") 87 | } 88 | 89 | /** 90 | * This method should return true if Battery Level notifications should be enabled on the target device. 91 | * If there is no Battery Service, or the Battery Level characteristic does not have NOTIFY property, 92 | * this method will not be called for this device. 93 | * 94 | * This method may return true only if an activity is bound to the service (to display the information 95 | * to the user), always (e.g. if critical battery level is reported using notifications) or never, if 96 | * such information is not important or the manager wants to control Battery Level notifications on its own. 97 | * @param device target device 98 | * @return true to enabled battery level notifications after connecting to the device, false otherwise 99 | */ 100 | override fun shouldEnableBatteryLevelNotifications(device: BluetoothDevice): Boolean { 101 | // TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 102 | return false 103 | } 104 | 105 | /** 106 | * Called when battery value has been received from the device. 107 | * 108 | * @param value 109 | * the battery value in percent 110 | * @param device the device frm which the battery value has changed 111 | */ 112 | override fun onBatteryValueReceived(device: BluetoothDevice, value: Int) { 113 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 114 | } 115 | 116 | /** 117 | * Called when an [BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION] error occurred and the device bond state is NOT_BONDED 118 | * @param device the device that requires bonding 119 | */ 120 | override fun onBondingRequired(device: BluetoothDevice) { 121 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 122 | } 123 | 124 | /** 125 | * Called when the device has been successfully bonded. 126 | * @param device the device that got bonded 127 | */ 128 | override fun onBonded(device: BluetoothDevice) { 129 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 130 | } 131 | 132 | override fun onBondingFailed(device: BluetoothDevice) { 133 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 134 | } 135 | 136 | /** 137 | * Called when a BLE error has occurred 138 | * 139 | * @param message 140 | * the error message 141 | * @param errorCode 142 | * the error code 143 | * @param device the device that caused an error 144 | */ 145 | override fun onError(device: BluetoothDevice, message: String, errorCode: Int) { 146 | Timber.e("onError {address=${device.address},name=${device.name},msg=${message},err=$errorCode}") 147 | } 148 | 149 | /** 150 | * Called when service discovery has finished but the main services were not found on the device. 151 | * @param device the device that failed to connect due to lack of required services 152 | */ 153 | override fun onDeviceNotSupported(device: BluetoothDevice) { 154 | Timber.d("onDeviceNotSupported {address=${device.address},name=${device.name}}") 155 | } 156 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stat_espressif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchwongho/ESP-Alerts-for-Android/00d16bd81ce51bb14bc0eaa187da1af8630aaebf/app/src/main/res/drawable-hdpi/ic_stat_espressif.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_stat_espressif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitchwongho/ESP-Alerts-for-Android/00d16bd81ce51bb14bc0eaa187da1af8630aaebf/app/src/main/res/drawable-mdpi/ic_stat_espressif.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 |