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

Services and characteristics list #92

Merged
merged 13 commits into from
Feb 5, 2020
44 changes: 37 additions & 7 deletions example/lib/adapter/ble_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:async';
import 'package:blemulator_example/example_peripherals/generic_peripheral.dart';
import 'package:blemulator_example/model/ble_peripheral.dart';
import 'package:blemulator_example/example_peripherals/sensor_tag.dart';
import 'package:blemulator_example/model/ble_service.dart';
import 'package:flutter_ble_lib/flutter_ble_lib.dart';
import 'package:blemulator/blemulator.dart';

Expand Down Expand Up @@ -30,6 +31,8 @@ class BleAdapter {

Stream<BlePeripheral> get blePeripherals => _blePeripheralsController.stream;

Map<String, Peripheral> _scannedPeripherals = Map();

factory BleAdapter(BleManager bleManager, Blemulator blemulator) {
if (_instance == null) {
_instance = BleAdapter._internal(bleManager, blemulator);
Expand Down Expand Up @@ -58,14 +61,16 @@ class BleAdapter {

Stream<BlePeripheral> _startPeripheralScan() {
return _bleManager.startPeripheralScan().map((scanResult) {
_scannedPeripherals.putIfAbsent(
scanResult.peripheral.identifier, () => scanResult.peripheral);
return BlePeripheral(
scanResult.peripheral.name ??
scanResult.advertisementData.localName ??
'Unknown',
scanResult.peripheral.identifier,
scanResult.rssi,
false,
BlePeripheralCategoryResolver.categoryForScanResult(scanResult),
scanResult.peripheral.name ??
scanResult.advertisementData.localName ??
'Unknown',
scanResult.peripheral.identifier,
scanResult.rssi,
false,
BlePeripheralCategoryResolver.categoryForScanResult(scanResult),
);
});
}
Expand All @@ -82,4 +87,29 @@ class BleAdapter {
_blemulator.addSimulatedPeripheral(GenericPeripheral());
_blemulator.simulate();
}

Future<List<BleService>> discoverAndGetServicesCharacteristics(
String peripheralId) async {
await _scannedPeripherals[peripheralId].connect();
await _scannedPeripherals[peripheralId]
.discoverAllServicesAndCharacteristics();

List<BleService> bleServices = [];
for (Service service
in await _scannedPeripherals[peripheralId].services()) {
List<Characteristic> serviceCharacteristics =
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
await service.characteristics();
List<BleCharacteristic> bleCharacteristics = serviceCharacteristics
.map(
(characteristic) =>
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
BleCharacteristic.fromCharacteristic(characteristic),
)
.toList();
bleServices.add(BleService(service.uuid, bleCharacteristics));
}

_scannedPeripherals[peripheralId].disconnectOrCancelConnection();
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved

return bleServices;
}
}
6 changes: 4 additions & 2 deletions example/lib/common/components/property_row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class PropertyRow extends StatelessWidget {
final Widget titleIcon;
final Color titleColor;
final String valueCompanion;
final TextStyle valueTextStyle;
final Widget rowAccessory;
final Widget titleAccessory;
final Widget valueAccessory;
Expand All @@ -17,6 +18,7 @@ class PropertyRow extends StatelessWidget {
this.titleIcon,
this.titleColor,
@required this.value,
this.valueTextStyle = CustomTextStyle.cardValue,
this.valueCompanion,
this.rowAccessory,
this.titleAccessory,
Expand Down Expand Up @@ -113,7 +115,7 @@ class PropertyRow extends StatelessWidget {
child: Text(
value ?? '',
textWidthBasis: TextWidthBasis.longestLine,
style: CustomTextStyle.cardValue,
style: valueTextStyle,
),
),
),
Expand All @@ -129,7 +131,7 @@ class PropertyRow extends StatelessWidget {
return Expanded(
child: Text(
value ?? '',
style: CustomTextStyle.cardValue,
style: valueTextStyle,
),
);
}
Expand Down
2 changes: 1 addition & 1 deletion example/lib/device_details/device_detail_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class DeviceDetailsViewState extends State<DeviceDetailsView> {
child: Scaffold(
backgroundColor: Colors.grey[300],
appBar: AppBar(
title: Text('Devicie Details'),
title: Text('Device Details'),
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.autorenew), text: "Automatic",),
Expand Down
52 changes: 43 additions & 9 deletions example/lib/example_peripherals/generic_peripheral.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,49 @@ class GenericPeripheral extends SimulatedPeripheral {
advertisementInterval: Duration(milliseconds: milliseconds),
services: [
SimulatedService(
uuid: 'F000AA00-0001-4000-B000-000000000000',
isAdvertised: true,
characteristics: [
SimulatedCharacteristic(
uuid: 'F000AA10-0001-4000-B000-000000000000',
value: Uint8List.fromList([0]),
convenienceName: 'Generic characteristic'),
],
convenienceName: 'Generic service'),
uuid: 'F000AA00-0001-4000-B000-000000000000',
isAdvertised: true,
characteristics: [
SimulatedCharacteristic(
uuid: 'F000AA10-0001-4000-B000-000000000000',
value: Uint8List.fromList([0]),
convenienceName: 'Generic characteristic'),
],
convenienceName: 'Generic service',
),
SimulatedService(
uuid: 'F000AA01-0001-4000-B000-000000000000',
isAdvertised: true,
characteristics: [
SimulatedCharacteristic(
uuid: 'F000AA10-0001-4000-B000-000000000000',
value: Uint8List.fromList([0]),
convenienceName: 'Generic characteristic'),
],
convenienceName: 'Generic service',
),
SimulatedService(
uuid: 'F000AA02-0001-4000-B000-000000000000',
isAdvertised: true,
characteristics: [
SimulatedCharacteristic(
uuid: 'F000AA10-0001-4000-B000-000000000000',
value: Uint8List.fromList([0]),
convenienceName: 'Generic characteristic'),
],
convenienceName: 'Generic service',
),
SimulatedService(
uuid: 'F000AA03-0001-4000-B000-000000000000',
isAdvertised: true,
characteristics: [
SimulatedCharacteristic(
uuid: 'F000AA10-0001-4000-B000-000000000000',
value: Uint8List.fromList([0]),
convenienceName: 'Generic characteristic'),
],
convenienceName: 'Generic service',
),
],
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
);

Expand Down
54 changes: 54 additions & 0 deletions example/lib/model/ble_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'dart:typed_data';

import 'package:equatable/equatable.dart';
import 'package:flutter_ble_lib/flutter_ble_lib.dart';

class BleService extends Equatable {
final String uuid;
final List<BleCharacteristic> characteristics;

BleService(this.uuid, this.characteristics);

@override
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
List<Object> get props => [uuid, characteristics];
}

class BleCharacteristic extends Equatable {
final String uuid;
final Uint8List value;
final bool isReadable;
final bool isWritableWithResponse;
final bool isWritableWithoutResponse;
final bool isNotifiable;
final bool isIndicatable;

BleCharacteristic(
this.uuid,
this.value,
this.isReadable,
this.isWritableWithResponse,
this.isWritableWithoutResponse,
this.isNotifiable,
this.isIndicatable,
);

@override
List<Object> get props => [
uuid,
value,
isReadable,
isWritableWithResponse,
isWritableWithoutResponse,
isNotifiable,
isIndicatable
];

BleCharacteristic.fromCharacteristic(Characteristic characteristic)
: uuid = characteristic.uuid,
value = null,
isReadable = characteristic.isReadable,
isWritableWithResponse = characteristic.isWritableWithResponse,
isWritableWithoutResponse = characteristic.isWritableWithoutResponse,
isNotifiable = characteristic.isNotifiable,
isIndicatable = characteristic.isIndicatable;
}
114 changes: 109 additions & 5 deletions example/lib/peripheral_details/components/peripheral_details_view.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'package:blemulator_example/model/ble_service.dart';
import 'package:blemulator_example/peripheral_details/bloc.dart';
import 'package:blemulator_example/common/components/property_row.dart';
import 'package:blemulator_example/styles/custom_text_style.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class PeripheralDetailsView extends StatelessWidget {
Expand All @@ -15,11 +18,17 @@ class PeripheralDetailsView extends StatelessWidget {
sliver: SliverToBoxAdapter(
child: BlocBuilder<PeripheralDetailsBloc, PeripheralDetailsState>(
builder: (context, state) {
return PropertyRow(
title: 'Identifier',
titleIcon: Icon(Icons.perm_device_information),
titleColor: Theme.of(context).primaryColor,
value: state.peripheral.id,
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
PropertyRow(
title: 'Identifier',
titleIcon: Icon(Icons.perm_device_information),
titleColor: Theme.of(context).primaryColor,
value: state.peripheral.id,
),
_createServiceView(context, state)
],
);
},
),
Expand All @@ -29,4 +38,99 @@ class PeripheralDetailsView extends StatelessWidget {
],
);
}

Widget _createServiceView(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering, maybe it(Services view) should be extracted to separate view/widget/file?

BuildContext context,
PeripheralDetailsState state,
) {
return Flexible(
fit: FlexFit.loose,
child: ListView.builder(
shrinkWrap: true,
itemCount: state.bleServiceStates.length,
itemBuilder: (context, index) =>
_createServiceTileView(context, state.bleServiceStates[index]),
),
);
}

Widget _createServiceTileView(
BuildContext context,
BleServiceState serviceState,
) {
// ignore: close_sinks
final PeripheralDetailsBloc bloc =
BlocProvider.of<PeripheralDetailsBloc>(context);

return Column(
children: <Widget>[
PropertyRow(
title: "Service UUID",
titleColor: Theme.of(context).primaryColor,
value: serviceState.service.uuid,
valueTextStyle: CustomTextStyle.serviceUuidStyle,
rowAccessory: IconButton(
icon: Icon(
serviceState.expanded ? Icons.unfold_less : Icons.unfold_more),
onPressed: () => bloc.add(ServiceViewExpandedEvent(
serviceState,
!serviceState.expanded,
)),
),
),
serviceState.expanded
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
? Padding(
padding: EdgeInsets.only(left: 16.0),
child: ListView.builder(
itemCount: serviceState.service.characteristics.length,
itemBuilder: (context, index) => _buildCharacteristicCard(
context, serviceState.service.characteristics[index]),
shrinkWrap: true,
),
)
: Column(),
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
],
);
}

Widget _buildCharacteristicCard(
BuildContext context,
BleCharacteristic characteristic,
) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"UUID: ${characteristic.uuid}",
style: CustomTextStyle.characteristicsStyle,
),
Text(
"Properties: ${_getCharacteristicProperties(characteristic).toString()}",
style: CustomTextStyle.characteristicsStyle,
),
],
),
),
);
}
}

List<String> _getCharacteristicProperties(BleCharacteristic characteristic) {
List<String> properties = new List<String>();

if (characteristic.isWritableWithoutResponse ||
characteristic.isWritableWithoutResponse) {
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved
properties.add("write");
}
if (characteristic.isReadable) {
properties.add("read");
}
if (characteristic.isIndicatable || characteristic.isNotifiable) {
properties.add("notify");
}
martawoldanska marked this conversation as resolved.
Show resolved Hide resolved

return properties;
}
Loading