I am building a bluetooth service. I was able to make unary call from client to server to turn on bluetooth and discover device. My Bluetooth engine class "registers events", and listens to changes in the BlueZ list of discovered devices:
_clientBlueZ.deviceAdded.listen((device) => _onDeviceAdded(device));
_clientBlueZ.deviceRemoved.listen((device) => _onDeviceRemoved(device));
Now I need to "publish" the devices to grpc channel so that client can listen to it. I am taking reference from BlueZ sourcecode itself but still have issue:
- BlueZ packages uses "stream controller" to add device to stream.
deviceAdded
is like a property, with get function returns_deviceAddedStreamController.stream
.
Stream<BlueZDevice> get deviceAdded => _deviceAddedStreamController.stream;
- When an object is somehow found, the stream adds that object.
_adapterAddedStreamController.add(BlueZAdapter(this, object));
- To get changes from the stream, then
_onDeviceAdded.listen
is used.
Fair enough. I try to replicate the same concept and publish the discovered devices to grpc channel and then to client with the following steps, but they don't work quite right:
- First, I initialize an instance of stream controller in my
BluetoothEngine
class:
final StreamController<AllDeviceStatusRes> _deviceStatusController
= StreamController<AllDeviceStatusRes>();
StreamController<AllDeviceStatusRes> get deviceStatusController
=> _deviceStatusController;
- in
_onDeviceAdd
I invoke another function_addToStream
to add to the stream the device:
void _addToStream(String deviceId, String deviceName, String address, bool isPaired, bool isConnected){
// add to stream so that BluetoothService can send to grpc
BluetoothDeviceRes deviceRes = BluetoothDeviceRes()
..deviceId = deviceId
..deviceName = deviceName
..deviceAddress = address
..isPaired = isPaired
..isConnected = isConnected;
_deviceStatusController.add(AllDeviceStatusRes()..device = deviceRes);
}
BluetoothService
is the actually class that sends data to the grpc server. It implements streamDeviceStatus function that return stream of devices. Of courseBluetoothEngine
is initialized withinBluetoothService
class BluetoothService extends BluetoothServiceBase{
final BluetoothEngine _bleCtrl = BluetoothCEngine();
@override
Stream<AllDeviceStatusRes> streamDeviceStatus(grpc.ServiceCall call, AllDeviceStatusReq
request) {
print ("send device status update to grpc");
return _bleCtrl.deviceStatusController.stream;
}
}
- On the client side, I implement streamDeviceStatus.
class BluetoothClient {
// it is like a Client, thus it makes connection to grpc first:
late final ClientChannel channel;
late final BluetoothServiceClient _stup;
BluetoothClient() {
channel = ClientChannel(
'localhost',
port: 50051,
options: const ChannelOptions(credentials: ChannelCredentials.insecure()),
);
_stup = BluetoothServiceClient(channel);
print('client listens to port 50051');
}
Future<void> streamDeviceStatus(AllDeviceStatusReq request) async {
final responseStream = await _stup.streamDeviceStatus(request);
responseStream.listen((response) {
print("Received device status: ${response.device.deviceName}
${response.device.deviceAddress} ${response.device.isPaired}
${response.device.isConnected} ");
// do other changes to models, and views on client sides
});
}
}
I think step 2 or 4 may be wrong. I expect that streamDeviceStatus
is invoked on client side, and that the console must at least prints out the device information on client side. But I don't have any yet.
I run command bluetoothctl
and check console log on server and client and see that the prerequisite steps have been done. There was starting bluetooth, scanning on both server and client side. There was device discovered on server side.
Please help me.