Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

writeWithResponse returns a response that is the sent message #1253

Open
4 tasks done
RoyceTheBiker opened this issue Nov 26, 2024 · 1 comment
Open
4 tasks done

writeWithResponse returns a response that is the sent message #1253

RoyceTheBiker opened this issue Nov 26, 2024 · 1 comment
Labels

Comments

@RoyceTheBiker
Copy link

RoyceTheBiker commented Nov 26, 2024

Prerequisites

  • I checked the documentation and FAQ without finding a solution
  • I checked to make sure that this issue has not already been filed
  • I'm sure that question is related to the library itself and not Bluetooth Low Energy or Classic in general. If that so, please post your question on StackOverflow.
  • I'm running the latest version

Question

I have a peripheral device hosting BLE service with two characteristics, one for reading from the device, and one for writing to the device. The React-Native screen shows a list of Bluetooth devices and the user clicks on one to connect. My device is listening for a message GET config.

After connecting to the device the GET config message is sent to the device, it arrives and is perfectly readable on the device. At that point, the device would send back some config data but I have removed that because the only thing that shows in the response.value is GET config

I have removed the device code that would send a response, it is no longer sending a response, but the control app still gets a response that seems to be coming from itself with the same message it sent out.

I have tried using writeCharacteristicWithResponseForService and it does the same thing, replies with the outgoing message.

What am I missing? How can I stop the response from being the outgoing message?

Question related code

import { BleManager, Characteristic, Device, Service, State } from "react-native-ble-plx";
import Base64 from 'react-native-base64';

let bleManager: BleManager;
let btDevice: Device;
let btServices: Array<Service>;
let readChannel: Characteristic;
let writeChannel: Characteristic;

const ServiceUUID   = "aac12ad2-a77c-48e2-89ad-a3e7a32422fe"
const ReadFromESP32 = "915bb543-3299-403d-b924-b2c1887b4c82"
const WriteToESP32  = "f78f9b6c-c078-4ef1-af4f-b68c1df1af4e"

export const initBluetooth = (connectDevice: string): Promise<string> => {
    return new Promise( (resolve) => {
        if(!bleManager) {
            bleManager = new BleManager();
            if(bleManager) {
                bleManager.startDeviceScan(null, null, (error, device) => {
                    if (error) {
                        console.log('Device scan error %s', error.message);
                    } else {
                        if((connectDevice === device.localName) || (connectDevice === device.name)) {
                            // console.log('BT Device is set');
                            btDevice = device;
                            resolve('Connected');
                        }
                    }
                });
            }
        }
    });
}

export const connectToDevice = (deviceName: string): Promise<string> => {
    console.log('Connecting to BT device %s', deviceName);
    return new Promise( (resolve) => {
        console.log('Call connect');
        btDevice.connect().then( (device: Device) => {
            console.log('Discovering characteristics');
            return device.discoverAllServicesAndCharacteristics();
        }).then( (device: Device) => {
            console.log('charactoristics discovered');
            return device.services();
        }).then( (services: Service[]) => {
            
            btServices = new Array<Service>;
            services.forEach( (service) => {
                btServices.push(service);
                service.characteristics().then( (channels: Characteristic[]) => {
                    channels.forEach( (channel) => {
                        if(channel.uuid === ReadFromESP32) {
                            readChannel = channel;
                            // console.log('setupMonitoring');
                            // setupMonitoring(btDevice);
                            console.log('read channel has write with response %s', channel.isWritableWithResponse ? 'true' : 'false');
                        }
                        if(channel.uuid === WriteToESP32) {
                            console.log('write channel has write with response %s', channel.isWritableWithResponse ? 'true' : 'false');

                            writeChannel = channel;
                        }
                    });
                });
            });
            resolve('Connected');
        });
    });
}

// const incomingMessage = (error: BleError | null, charactoristic: Characteristic | null) => {
//     if(error) {
//         console.error(error.message);
//         return;
//     }
//     if(!charactoristic?.value) {
//         console.error('No data');
//         return;
//     }
//     console.log('Data %s', Base64.decode(charactoristic.value));
// }

// const setupMonitoring = async (device: Device) => {
//     if(device) {
//         console.log('setupMonitoring');
//         device.monitorCharacteristicForService(ServiceUUID, ReadFromESP32, incomingMessage);
//     }
// }

export const getData = (request: string): Promise<string> => {
    console.log('Request: %s', request);
    return new Promise( (resolve) => {
        bleManager.state().then( (bleState: State) => {
            console.log('BLE State is %s', bleState);
            if(bleState === 'PoweredOn') {
                console.log('Sending message to %s', writeChannel.uuid);
                console.log('request %s', request);
        
                let requestB64 = Base64.encode(request);
                console.log('requestB64 length %d', requestB64.length);
                console.log('requestB64 %s', requestB64);
                
                writeChannel.writeWithResponse(requestB64).then( (response: Characteristic) => {                    
                    console.log('got a response from %s', response.uuid);
                    console.log('got a response %s', Base64.decode(response.value));
                    // console.log('got a readChannel %s', readChannel.value ? Base64.decode(readChannel.value) : 'NULL');
                    // console.log('got a writeChannel %s', writeChannel.value ? Base64.decode(writeChannel.value) : 'NULL');                    
                    resolve(Base64.decode(response.value));
                }).catch( (err) => {
                    console.error('response %s', err.message);
                });
                // btDevice.writeCharacteristicWithResponseForService(ServiceUUID, WriteToESP32, requestB64).then( (response: Characteristic) => {
                //     console.log('got a response from %s', response.uuid);
                //     console.log('got a response %s', Base64.decode(response.value));
                // }).catch( (err) => {
                //     console.error(err.message);
                // });
            } else {
                resolve('Device is powered off');
            }
        });
    });
};

export const putData = (request: object): Promise<string> => {
    return new Promise( (resolve, reject) => {
        // btdevice send request, get a response
    });
};

Update 2024-11-26

I have now tested my peripheral device using the LightBlue app by Punch Through. With the device having the notification on write disabled, the app receives the sent message as the reply. I re-enabled the onWrite callback and now LightBlue receives the message that the device is set to reply with. I tried adding notify permission to the write characteristic and now LightBlue shows me a subscribe button that does not seem to do anything. I don't think that would help because I need the response to be in the promise returned from sending a message.

@RoyceTheBiker
Copy link
Author

I may have found a workaround. The Wiki for Characteristic Writing has a helpful statement Latest value may not be stored inside returned object., so I could have this problem again in the future, but for now I have something working.

I found that writeWithoutResponse is able to get the correct reply by using monitor. I hope this does not become a problem for follow-up messages.

Can anyone tell me if I need to destroy this monitor to prevent it from catching other replies for to other messages?

writeChannel.writeWithoutResponse(requestB64).then( (response: Characteristic) => {
       response.monitor( (err: BleError, characteristic: Characteristic) => {
             if(err) {
                 console.error(err.message);
             } else {
                  console.log('characteristic value %s', Base64.decode(characteristic.value));
             }
       });                    
    }).catch( (err) => {
       console.error(err.message);
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant