react-native bluetooth connection with Accu-check Guide-me - android

I am developing an app that works with various health measuring bluetooth devices.
I am using with React-native and react-native-ble-plx.
I don't know much about Bluetooth, so I'm searching each device and developing it.
Some sphygmomanometers and scales have completed, but the blood glucose meter, which requires input of a serial number, cannot be linked.
The connection Bluetooth that has been developed so far is as follows.
Scan -> Found device -> Stop scan -> Connect -> discover all services&characteristics -> Find service list -> filter measurement service -> find characteristics list from filtered service -> monitor those
The device I am having a hard time developing right now is the “Accu-check Guide Me” blood glucose device.
Other devices are receiving the measured values ​​well.
But after this device is connected, if the test strip is inserted into the machine, the Bluetooth connection is cut off.
Connect -> Popup to insert serial number -> insert serial number -> connected success -> insert test strip into Accu-check -> disconnected
Perhaps unlike other devices, this device seems to have to do something more in between the normal flow, but it is difficult to find out from my knowledge even if I search hard.
I'd appreciate it if you could tell me what more to do in the code below.
const scanAndConnectAcucheckGlucoseMeter = () => {
return new Promise((resolve, reject) => {
let result = 0;
console.log('scanStart');
manager.startDeviceScan(null, null, (error, device) => {
if (error) {
console.log('error : ' + error);
return;
}
const deviceName = device.name;
if (deviceName != null) {
if (deviceName.includes('meter+')) {
console.log('detected!!');
manager.stopDeviceScan();
resolve(device);
}
}
});
});
};
const MonitoringForAcucheckGuideMe = device => {
return new Promise((resolve, reject) => {
device
.connect()
.then(device => {
const result = device.discoverAllServicesAndCharacteristics();
return result;
})
.then(device => {
return device.services();
})
.then(services => {
// 180A : device information
// 1800 : generic access
// 1808 : glucose
// 00000000-0000-1000-1000-00000000000 : custom service
const result = services.filter(id => id.uuid.indexOf('1808') != -1); // Glucose Service
return result[0].characteristics();
})
.then(characters => {
// Glucose Measurement :00002A18 / Descriptors 2902
// Glucose Feature : 2A51
// Record Access Control Point 2A52 / Descriptors 2902
// DateTime 2A08
const glucoseMeasurement = characters.filter(
data => data.uuid.indexOf('2a18') != -1, // 2a35 is for blood sugar measurement
);
// popup to insert pin number on mobile when monitor()
glucoseMeasurement[0].monitor((error, characteristic) => {
if (error) {
console.log('error:::::', error);
reject(error);
}
const Valuebytes = Buffer.from(characteristic.value, 'base64');
console.log(Valuebytes);
const result = "Not yet"
resolve(result)
});
})
.catch(error => console.log(error));
});
};

Related

firebase notifications stops working after a while (one day or a few days)

I am very frustrated with this problem:(
I am developing an app for android and ios (using capacitor 3) and I am sending notifications to the app via firebase notifications. (capacitor packages: #capacitor-community/fcm and #capacitor/push-notifications).
It works for a while and after one day or a few days that the app is running in background or foreground (and not killed) it stops from working and the app doesn't get notifications(This has happened to me in android device.).
I am sending notifications using topics and i also tried to send the notification through firebase console, but it didn't work.
I am not sure if this means that the registration token has expired because I would think that the capacitor packages are suppose to handle it since they are not talking about this problem.
I did everything from the documentation of capacitor push notifications.
When I watch the logs I can see the next error: Failed to sync topics. Won't retry sync. INVALID_PARAMETERS.
My code in javascript:
import '#capacitor/core';
import { ActionPerformed, PushNotificationSchema, PushNotifications } from '#capacitor/push-notifications'
import { FCM } from '#capacitor-community/fcm';
import { getMessaging, getToken as firebaseGetToken, onMessage, deleteToken, isSupported } from "firebase/messaging";
import { myAxios } from './generic-functions/my-axios';
const platform = window.Capacitor && window.Capacitor.platform;
const topicIos = `${process.env.REACT_APP_TOPIC}_ios`;
const topicAnd = `${process.env.REACT_APP_TOPIC}_and`;
function isCapacitor(): boolean {
//check if we are in a capacitor platform
return window.Capacitor && (window.Capacitor.platform === "android" || window.Capacitor.platform === "ios")
}
export async function InitFCM(destination: string) {
if (!isCapacitor()) {
const isNtfSupported = await isSupported()
if (!isNtfSupported) return
// web notifications
Notification.requestPermission().then(function (permission) {
if (permission === 'granted') {
subscribeTo(destination);
} else {
// Show some error
}
});
const messaging = getMessaging();
onMessage(messaging, (payload) => {
let notification = payload.data;
const notificationOptions: NotificationOptions = {
badge: notification?.largeIco,
body: notification?.body,
icon: notification?.largeIcon
};
const title = notification?.title || "";
// show notification
navigator.serviceWorker
.getRegistrations()
.then((registration) => {
if (notification?.sound) {
const audio = new Audio(`/notifications/${notification?.sound}`)
audio.play()
}
registration[0].showNotification(title, notificationOptions);
});
})
return
}
try {
console.log('Initializing Push Notifications');
// Request permission to use push notifications
// iOS will prompt user and return if they granted permission or not
// Android will just grant without prompting
PushNotifications.requestPermissions().then(result => {
if (result.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
// PushNotifications.register();
subscribeTo(destination);
} else {
// Show some error
}
});
// Some issue with our setup and push will not work
PushNotifications.addListener('registrationError',
(error: any) => {
console.log('Error on registration: ' + JSON.stringify(error));
}
);
// Show us the notification payload if the app is open on our device
PushNotifications.addListener('pushNotificationReceived',
(notification: PushNotificationSchema) => {
console.log('Push received: ' + JSON.stringify(notification));
}
);
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(notification: ActionPerformed) => {
console.log('Push action performed: ' + JSON.stringify(notification));
}
);
} catch (e) {
console.log('err in push notifications: ', e);
}
}
async function subscribeTo(destination: string) {
if (!isCapacitor()) {
//subscribe to web topic
const messaging = getMessaging();
firebaseGetToken(messaging, { vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY }).then(
async (token) => {
if (token) {
await myAxios.post("/api/notifications/subscribe-to-topic", { token, destination });
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
return
}
try {
await PushNotifications.register();
if (platform === "ios") {
//subscribe to ios topic
const resIos = await FCM.subscribeTo({ topic: `${topicIos}_${destination}` });
console.log(`subscribed to ios Topic ${JSON.stringify(resIos)}`);
}
if (platform === "android") {
//subscribe to android topic
const resAnd = await FCM.subscribeTo({ topic: `${topicAnd}_${destination}` });
console.log(`subscribed to android Topic ${JSON.stringify(resAnd)}`);
}
} catch (error) {
console.log(JSON.stringify(error));
}
}
export async function getToken() {
try {
/* const result = */ await FCM.getToken();
// console.log("TOKEN", result.token);
} catch (error) {
console.log(error);
}
}
export async function unsubscribeFrom(destination?: string) {
if (!isCapacitor()) {
const isNtfSupported = await isSupported()
if (!isNtfSupported || !destination) return
const messaging = getMessaging();
//unsubscribe from web topic
firebaseGetToken(messaging, { vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY }).then(
async (token) => {
if (token) {
await myAxios.post("/api/notifications/unsubscribe-from-topic", { token, destination });
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
return
}
try {
await PushNotifications.removeAllListeners();
if (destination) {
if (platform === "ios") {
//unsubscribe from ios topic
const resIos = await FCM.unsubscribeFrom({ topic: `${topicIos}_${destination}` });
console.log(`unsubscribed from ios topic ${resIos}`);
}
if (platform === "android") {
//unsubscribe from android topic
const resAndroid = await FCM.unsubscribeFrom({ topic: `${topicAnd}_${destination}` });
console.log(`unsubscribed from android topic ${topicAnd}_${destination}: ${resAndroid.message}`);
}
}
} catch (error) {
console.log(error)
}
if (platform === 'android') {
await FCM.deleteInstance();
}
}
Thank you all in advanced!
This is a common issue since Android 7.0. The problem occurs because you make use of data messages. This part of your code onMessage(messaging, (payload) => { tells me that you rely on that. This means that when a message is received, your apps code will handle the delivery even when in the background. It will create a notification to show it on the device and play a sound for example.
Power Management taken too far
Several device manufacturers have improved their power management too far. This results in the following problem: After a few days of inactivity, an app is completely killed by the Android OS. This means that the app is not able to handle incoming messages in the background anymore. Vendors have gone too far. But you can't do anything about that.
What to do?
To solve the problem, you should rely on notification messages. These are messages that are directly delivered to the Android OS, instead of your app. This means that messages do not need background handling of your app. On the server (sending) side it means you have to modify your current message and add notification info to the message that is sent.
The drawback
The drawback of notification messages is that you can't lay your hands on the data that is part of the notification. If you previously filled your app with data from each notification, with notification messages, you get the data only when your app is in the foreground or the notification is clicked. To get all data within your app, you need a server API solution or something else.
To overcome this you can add a NotificationListener to your app. I am not sure how to do this in Capacitor. A native example can be found here: https://github.com/Chagall/notification-listener-service-example. The NotificationListener can listen for notifications delivered to the Android device also in the background. With this solution you can be sure notifications are always delivered and the data is delivered in the background. But maybe, I don't know, this listener is killed too by power management. When you use the NotificationListener, you need a special permission, that must be set via device settings (see the mentioned example).
Conclusion
Change from data messages to notification messages. Provide a different way to get the data of your messages in your app. You can use the NotificationListener but I don't know if that is reliable. The most obvious solution is to introduce a server side API that provides the data to your app. In the new situation the notifications are reliable delivered to the app.

Connecting 2 arduinos via Bluetooth to the same Android flutter app

I want to connect 2 Arduino to the same mobile app using BLE I have the code for one Arduino connection how to manage it so I can have two Arduino connected
is it possible to connect two Arduinos with BLE to the same app?
Or should I find another alternative
void _connectBLE() {
setState(() {
temperatureStr = 'Loading';
});
_disconnect();
_subscription = _ble.scanForDevices(
withServices: [],
scanMode: ScanMode.lowLatency,
requireLocationServicesEnabled: true).listen((device) {
if (device.name == 'Arduino3') {
print('NiclaSenseME found!');
_connection = _ble
.connectToDevice(
id: device.id,
)
.listen((connectionState) async {
// Handle connection state updates
print('connection state:');
print(connectionState.connectionState);
if (connectionState.connectionState ==
DeviceConnectionState.connected) {
Timer.periodic(Duration(milliseconds: 5), (timer) async{
final characteristic = QualifiedCharacteristic(
serviceId: Uuid.parse("181A"),
characteristicId: Uuid.parse("2A6E"),
deviceId: device.id);
final response = await _ble.readCharacteristic(characteristic);
print(response);
setState(() {
temperature = fromBytesToInt32(response[0],response[1],response[2],response[3]);
print(temperature);
temperatureStr = temperature.toString();
});
});
_disconnect();
print('disconnected');
}
}, onError: (dynamic error) {
// Handle a possible error
print(error.toString());
});
}
}, onError: (error) {
print('error!');
print(error.toString());
});
}

How to disconnect from multiple connected ble devices in Flutter app?

I am currently connected to multiple ble devices. Now, I'd like to disconnect from them but I can't.
Here's the code for connecting:
for (String deviceId in deviceIdList) {
try {
await Provider.of<BleDeviceConnector>(context, listen: false)
.connectAndLoad(
deviceId: deviceId, custom: custom, index: index);
} catch (e) {
print(e);
}
}
// In separate file...
class BleDeviceConnector extends ReactiveState<ConnectionStateUpdate> {
BleDeviceConnector({
required FlutterReactiveBle ble,
required Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage;
final FlutterReactiveBle _ble;
final void Function(String message) _logMessage;
#override
Stream<ConnectionStateUpdate> get state => _deviceConnectionController.stream;
final _deviceConnectionController = StreamController<ConnectionStateUpdate>();
late StreamSubscription<ConnectionStateUpdate> _connection;
Future<void> connectAndLoad(
{required String deviceId,
required CustomModel custom,
required int index}) async {
_connection = _ble.connectToDevice(id: deviceId).listen((update) async {
_deviceConnectionController.add(update);
if (update.connectionState == DeviceConnectionState.connected) {
await custom.loadCustomStuff();
}
}, onError: (e) {
print('Connecting to device $deviceId resulted in error $e');
});
}
Future<void> disconnect(String deviceId) async {
try {
print('disconnecting from device: $deviceId');
_logMessage('disconnecting from device: $deviceId');
await _connection.cancel();
} on Exception catch (e, _) {
print("Error disconnecting from a device: $e");
_logMessage("Error disconnecting from a device: $e");
} finally {
// Since [_connection] subscription is terminated, the "disconnected" state cannot be received and propagated
_deviceConnectionController.add(
ConnectionStateUpdate(
deviceId: deviceId,
connectionState: DeviceConnectionState.disconnected,
failure: null,
),
);
print("Disconnected from $deviceId");
}
}
Future<void> dispose() async {
await _deviceConnectionController.close();
}
This results in connecting to all the devices in deviceList, and loading info.
However, when I then try to disconnect from all of connected devices, it only successfully disconnects from the last one that was written to.
Here's what I'm trying:
for (String deviceId in deviceIdList) {
await Provider.of<BleDeviceConnector>(context, listen: false).disconnect(deviceId);
}
When I reached out to the package author (package: flutter_reactive_ble), he said:
"you can create a class that will hold all subscriptions and then you can loop through them and cancel them one by one in order to disconnect"
When I ran this by the discord, the thought was that I should make a list instead of a class (which seemed more along the lines of what I was thinking). Either way, I tried adding the _connection StreamSubscription to a list, but it doesn't even end up getting added to the list (for some reason).
They also mentioned to try and make another _connection variable since that appears to be the only one.
My understanding was that I would get a new instance every time I make a call to **connectAndLoad(...).
Any help would REALLY be appreciated.
Thanks!

Ionic BLE ble.write return null on ios

I'm using this plugin inside a ionic + stencil app
https://github.com/don/cordova-plugin-ble-central
I'm send a write command to a characteristic that support WRITE.
If I call ble.write on Android, the callback returns me OK
If I call ble.write on iOS, the callback returns me NULL.
in both cases, I can see on my peripheral device that the command has been sent correctly.
I connect to the device like this:
connectToDevice(device){
var toast = new utils();
let tclass;
let tmessage;
console.log('----connectToDevice----');
BLE.connect(device.id).subscribe(
peripheralData => {
this.device = peripheralData;
let connectBtn = document.querySelector('#connectBtn') as any;
console.log('device connected: ', this.device);
},
error => {
console.log('connect error: ', error);
}
);
}
And then, send the command with this code:
async sendCommandNew(id){
let noteOk;
let noteError;
let data;
data = this.stringToBytes(this.commandToSend);
let timerId = setInterval(() => {
BLE.write(id, "49535343-fe7d-4ae5-8fa9-9fafd205e455", "49535343-1e4d-4bd9-ba61-23c647249616", data).then((res) => {
console.log('res: ', res);
}).catch(() => {
console.log('res no');
}
)
}, 1000);
setTimeout(() => { clearInterval(timerId); console.log('stopped'); }, 5000);
}
This is the characteristic
Inside the plugin issue many people had this problem but no solution provided.

I using cordova-plugin-ibeacon but not working(does'nt find beacons in android)

here is code
beacon-provider.ts >>
initialise(): any {
let promise = new Promise((resolve, reject) => {
if (this.platform.is('cordova')) {
IBeacon.enableBluetooth();
this.delegate = IBeacon.Delegate();
this.delegate.didRangeBeaconsInRegion()
.subscribe(
data => {
this.events.publish('didRangeBeaconsInRegion', data);
},
error => console.error()
);
this.region = IBeacon.BeaconRegion('deskBeacon', '24DDF411-8CF1-440C-87CD-E368DAF9C93E');
IBeacon.startRangingBeaconsInRegion(this.region)
.then(
() => {
resolve(true);
},
error => {
console.error('Failed to begin monitoring: ', error);
resolve(false);
}
);
} else {
console.error("This application needs to be running on a device");
resolve(false);
}
});
return promise;
}
}
home.ts >>
export class HomePage {
beacons: BeaconModel[] = [];
zone: any;
constructor(public navCtrl: NavController, public platform: Platform, public beaconProvider: BeaconProvider, public events: Events) {
this.zone = new NgZone({ enableLongStackTrace: false });
}
ionViewDidLoad() {
this.platform.ready().then(() => {
this.beaconProvider.initialise().then((isInitialised) => {
if (isInitialised) {
this.listenToBeaconEvents();
}
});
});
}
listenToBeaconEvents() {
this.events.subscribe('didRangeBeaconsInRegion', (data) => {
this.zone.run(() => {
this.beacons = [];
let beaconList = data.beacons;
beaconList.forEach((beacon) => {
let beaconObject = new BeaconModel(beacon);
this.beacons.push(beaconObject);
});
});
});
}
}
In this code, the result of alert(JSON.stringify(data)) is:
{"eventType":"didRangeBeaconslnRegion","region":{"identifier":"desk beacon","uuid":"24DDF411-8CF1-440C-87CD-E368DAF9C93E","typeName":"BeaconRegion"}, "beacons":[]}
The field data.beacons is empty.
What is the problem?
one more question i try BLE-central plugin first but,
when i was using BLE-central plugin i get signal but it was not given to me major , minor value if i get this value from advertising ?
There are lots of things that might cause this behavior:
Verify that Bluetooth is on
Verify that your app has been granted runtime location permissions needed to detect Bluetooth devices. Go to Settings -> Apps -> [Your app name] -> Permissions, and make sure you see a Location entry with the switch turned on.
Verify using an off-the-shelf detector app that your beacon actually is transmitting the identifier you expect. Try my Locate app here: https://play.google.com/store/apps/details?id=com.radiusnetworks.locate&hl=en

Categories

Resources