|
| 1 | +A Flutter plugin for accessing the [Movesense](https://www.movesense.com/) family of ECG devices. This is a developer-friendly wrapper of the [mdsflutter](https://pub.dev/packages/mdsflutter) plugin. |
| 2 | + |
| 3 | +## Features |
| 4 | + |
| 5 | +This plugin supports the following features, which is the most commonly used sub-set of the total [Movensene API](https://www.movesense.com/docs/esw/api_reference/): |
| 6 | + |
| 7 | +* scan for Movensense devices (and stop scanning again) |
| 8 | +* connect and disconnect to a device |
| 9 | +* get device and state information |
| 10 | +* get a stream of the following data from a device: |
| 11 | + * heart rate |
| 12 | + * ECG |
| 13 | + * IMU |
| 14 | + * temperature |
| 15 | + * state events (movement, battery, connectors, double tap, tap, free fall) |
| 16 | + |
| 17 | +## Getting started |
| 18 | + |
| 19 | +Similar to the [mdsflutter](https://pub.dev/packages/mdsflutter) plugin, the Movesense library needs to be installed in your app. |
| 20 | + |
| 21 | +### iOS |
| 22 | + |
| 23 | +Install the Movesense iOS library using CocoaPods with adding this line to your app's Podfile: |
| 24 | + |
| 25 | +```shell |
| 26 | +pod 'Movesense', :git => 'ssh://git@altssh.bitbucket.org:443/movesense/movesense-mobile-lib.git' |
| 27 | +``` |
| 28 | + |
| 29 | +Then set up your `ios/Podfile` as follows: |
| 30 | + |
| 31 | +```pod |
| 32 | +target 'Runner' do |
| 33 | + use_modular_headers! |
| 34 | + use_frameworks! :linkage => :static |
| 35 | + |
| 36 | + pod 'Movesense', :git => 'https://bitbucket.org/movesense/movesense-mobile-lib.git' |
| 37 | + |
| 38 | + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) |
| 39 | +end |
| 40 | +``` |
| 41 | + |
| 42 | +This will ensure that the MDS library is linked correctly. If you need to use frameworks that demand dynamic linking, [follow the instructions here](https://bitbucket.org/movesense/movesense-mobile-lib/issues/119/cannot-use-health-and-mdsflutter-depending). |
| 43 | + |
| 44 | +### Android |
| 45 | + |
| 46 | +Download `mdslib-x.x.x-release.aar` from the [movesense-mobile-lib](https://bitbucket.org/movesense/movesense-mobile-lib/src/master/) repository and put it somewhere under 'android' folder of your app. Preferably create a new folder named `android/libs` and put it there. |
| 47 | + |
| 48 | +In the `build.gradle` of your android project, add the following lines (assuming `.aar` file is in `android/libs`): |
| 49 | + |
| 50 | +```graddle |
| 51 | +allprojects { |
| 52 | + repositories { |
| 53 | + ... |
| 54 | + flatDir{ |
| 55 | + dirs "$rootDir/libs" |
| 56 | + } |
| 57 | + } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +## Usage |
| 62 | + |
| 63 | +### Scanning for devices |
| 64 | + |
| 65 | +The singleton `Movesense` can be used for scanning devices: |
| 66 | + |
| 67 | +```dart |
| 68 | +/// Listen for discovered devices |
| 69 | +Movesense().devices.listen((device) { |
| 70 | + debugPrint('Discovered device: ${device.name} [${device.address}]'); |
| 71 | +}); |
| 72 | +/// Start scanning. |
| 73 | +Movesense().scan(); |
| 74 | +
|
| 75 | +/// Stop scanning at some later point. |
| 76 | +Movesense().stopScan(); |
| 77 | +``` |
| 78 | + |
| 79 | +### Connecting to a device |
| 80 | + |
| 81 | +Scanning return a `MovesenseDevice` which can be used to connect to the device, like: |
| 82 | + |
| 83 | +```dart |
| 84 | +if (!device.isConnected) { |
| 85 | + device.connect(); |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +A `MovesenseDevice` can either be obtained using the scan method above, or can be create if the address of the device is know: |
| 90 | + |
| 91 | +```dart |
| 92 | +final MovesenseDevice device = MovesenseDevice(address: '0C:8C:DC:1B:23:BF'); |
| 93 | +
|
| 94 | +device.connect(); |
| 95 | +``` |
| 96 | + |
| 97 | +Connection status is available in the `status` can is emitted in the `statusEvents` stream. |
| 98 | + |
| 99 | +```dart |
| 100 | +print(device.status); |
| 101 | +
|
| 102 | +device.statusEvents.listen((status) { |
| 103 | + print('Device connection status changed: ${status.name}'); |
| 104 | +}); |
| 105 | +``` |
| 106 | + |
| 107 | +### Accessing device information and battery status |
| 108 | + |
| 109 | +The following device information and status is available as getter methods: |
| 110 | + |
| 111 | +* `getDeviceInfo` - get the full [device info](https://www.movesense.com/docs/esw/api_reference/#info) of this Movesense device. |
| 112 | +* `getBatteryStatus` - get the [battery level](https://www.movesense.com/docs/esw/api_reference/#systemstates) ("OK" or "LOW") from the device. |
| 113 | +* `getState` - get the [system state](https://www.movesense.com/docs/esw/api_reference/#systemstates) from the device (movement, connectors, doubleTap, tap, freeFall). |
| 114 | + |
| 115 | +For example, getting device info and battery level: |
| 116 | + |
| 117 | +```dart |
| 118 | +var info = await device.getDeviceInfo(); |
| 119 | +print('Product name: ${info?.productName}'); |
| 120 | +
|
| 121 | +var battery = await device.getBatteryStatus(); |
| 122 | +print('Battery level: ${battery.name}'); |
| 123 | +``` |
| 124 | + |
| 125 | +### Streaming sensor data |
| 126 | + |
| 127 | +The following sensor data is available as streams: |
| 128 | + |
| 129 | +* `hr` - Heart rate as an `int` at 1 Hz. |
| 130 | +* `ecg` - Electrocardiography (ECG) as a sample of reading at 125 Hz. |
| 131 | +* `imu` - 9-axis Inertial Movement Unit (IMU) at 13 Hz. |
| 132 | +* `temperature` - Surface temperature of the device in Kelvin. |
| 133 | + |
| 134 | +For example, you can listen to the heart rate stream like this: |
| 135 | + |
| 136 | +```dart |
| 137 | +// Start listening to the stream of heart rate readings |
| 138 | +var hrSubscription = device.hr.listen((hr) { |
| 139 | + print('Heart Rate: $hr'); |
| 140 | +}); |
| 141 | +
|
| 142 | +// Stop listening. |
| 143 | +hrSubscription?.cancel(); |
| 144 | +``` |
| 145 | + |
| 146 | +The example app shows streaming heart rate data, once connected to a device. |
| 147 | + |
| 148 | +### Streaming state change events |
| 149 | + |
| 150 | +You can also listen to a stream of [system state](https://www.movesense.com/docs/esw/api_reference/#systemstates) from the device (movement, connectors, doubleTap, tap, freeFall). For example, listening for 'tap' events like this: |
| 151 | + |
| 152 | +```dart |
| 153 | +stateSubscription = device |
| 154 | + .getStateEvents(SystemStateComponent.tap) |
| 155 | + .listen((state) { |
| 156 | + print('State: $state'); |
| 157 | + }); |
| 158 | +``` |
| 159 | + |
| 160 | +Note, however, that listening to system state events on a Movensense device comes with a lot of limitations. First of all, you can only listen to one type of state events at a time. Second, not all Movesense devices seems to support subscription of all types of state events. For example, it seems like only the 'connectors' and 'tap' states are supported on the Movesense MD and HR2 devices. |
| 161 | + |
| 162 | +## Example App |
| 163 | + |
| 164 | +The included example app is very simple. It shows how to connect to a device with a known `address` and once connected, it listens to the heart rate (`hr`) stream and shows it in the app. Use the floating button to (i) connect, (ii) start streaming heart rate data, and (iii) stop streaming again. |
| 165 | + |
| 166 | +## Features and bugs |
| 167 | + |
| 168 | +Please read about existing issues and file new feature requests and bug reports at the issue tracker. |
| 169 | + |
| 170 | +## License |
| 171 | + |
| 172 | +This software is copyright (c) the [Technical University of Denmark](https://dtu.dk/) (DTU) and is part of the [Copenhagen Research Platform](https://carp.dk/). This software is available 'as-is' under a [MIT license](LICENSE). |
0 commit comments