Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/movesense_plus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.2.1

* update of example app to run on iOS incl. docs

## 1.2.0

* connect and disconnect method not async
Expand Down
33 changes: 17 additions & 16 deletions packages/movesense_plus/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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.
A Flutter plugin for accessing the [Movesense](https://www.movesense.com/) family of ECG devices. This is a developer-friendly and strongly typed wrapper of the [mdsflutter](https://pub.dev/packages/mdsflutter) plugin.

## Features

Expand All @@ -16,25 +16,21 @@ This plugin supports the following features, which is the most commonly used sub

## Getting started

Similar to the [mdsflutter](https://pub.dev/packages/mdsflutter) plugin, the Movesense library needs to be installed in your app.

> **NOTE:** This plugin does not handle permission to access Bluetooth. Use the [permission_handler](https://pub.dev/packages/permission_handler) plugin to request access to scan and connect to BLE devices. See the example app.

### iOS

Install the Movesense iOS library using CocoaPods with adding this line to your app's Podfile:
Similar to the [mdsflutter](https://pub.dev/packages/mdsflutter) plugin, the Movesense library needs to be installed in your app.

```shell
pod 'Movesense', :git => 'ssh://git@altssh.bitbucket.org:443/movesense/movesense-mobile-lib.git'
```
### iOS

Then set up your `ios/Podfile` as follows:
The Movesense iOS library is installed using CocoaPods by adding the following lines to your app's `ios/Podfile`:

```pod
```ruby
target 'Runner' do
# replace "use_frameworks!" with static packages for the Movesense pod
use_modular_headers!
use_frameworks! :linkage => :static

# add Movesense pod
pod 'Movesense', :git => 'https://bitbucket.org/movesense/movesense-mobile-lib.git'

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
Expand All @@ -45,7 +41,7 @@ This will ensure that the MDS library is linked correctly. If you need to use fr

### Android

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.
Download the latest `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.

In the `build.gradle` of your android project, add the following lines (assuming `.aar` file is in `android/libs`) for Groovy:

Expand Down Expand Up @@ -84,7 +80,7 @@ Movesense().stopScan();

### Connecting to a device

Scanning return a `MovesenseDevice` which can be used to connect to the device, like:
Scanning returns a `MovesenseDevice` which can be used to initiate connection to the device, like:

```dart
if (!device.isConnected) {
Expand All @@ -100,6 +96,11 @@ final MovesenseDevice device = MovesenseDevice(address: '0C:8C:DC:1B:23:BF');
device.connect();
```

> **NOTE:** The `address` format is platform dependent:
>
> * On Android, the address is the Bluetooth MAC address (e.g. "0C:8C:DC:1B:23:BF").
> * On iOS, the address is the UUID of the device (e.g. "89BD8BF8-C9E7-0395-3B1D-119082516DDE").

Connection status is available in the `status` field and is also emitted in the `statusEvents` stream.

```dart
Expand All @@ -112,10 +113,10 @@ device.statusEvents.listen((status) {

### Accessing device information, battery status, and system states

The following device information and status is available as getter methods:
Once connected, the following device information is available as getter methods:

* `getDeviceInfo` - get the full [device info](https://www.movesense.com/docs/esw/api_reference/#info) of this Movesense device.
* `getBatteryStatus` - get the [battery level](https://www.movesense.com/docs/esw/api_reference/#systemstates) ("OK" or "LOW") from the device.
* `getBatteryStatus` - get the [battery level](https://www.movesense.com/docs/esw/api_reference/#systemstates) ("OK" or "LOW") of the device.
* `getState` - get the [system state](https://www.movesense.com/docs/esw/api_reference/#systemstates) from the device (movement, connectors, doubleTap, tap, freeFall).

For example, getting device info and battery level:
Expand Down Expand Up @@ -163,7 +164,7 @@ stateSubscription = device
});
```

> **NOTE:** Listening to system state events on a Movensense device comes with some limitations. First of all, you can [only listen to one type of state event at a time](https://github.com/petri-lipponen-movesense/mdsflutter/issues/15). 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.
> **NOTE:** Listening to system state events on a Movensense device comes with some limitations. First of all, you can [only listen to one type of state event at a time](https://github.com/petri-lipponen-movesense/mdsflutter/issues/15). Second, not all Movesense devices 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.

## Example App

Expand Down
8 changes: 7 additions & 1 deletion packages/movesense_plus/example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe
flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
# replace "use_frameworks!" with static packages for the Movesense pod
use_modular_headers!
use_frameworks! :linkage => :static

# add Movesense pod
pod 'Movesense', :git => 'https://bitbucket.org/movesense/movesense-mobile-lib.git'

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

target 'RunnerTests' do
inherit! :search_paths
end
Expand Down
111 changes: 111 additions & 0 deletions packages/movesense_plus/example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
objects = {

/* Begin PBXBuildFile section */
11390E964DF93FDD14862162 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584E34BC3BE863F3647682CF /* Pods_RunnerTests.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
791D520225B2BE29FE5603AD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA74802E011D97599336CEDA /* Pods_Runner.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
Expand Down Expand Up @@ -42,9 +44,15 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
150F41D93EA1EE707B6893C2 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3578B4A11D7A13B0C0C33880 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B5C5141498770A8AAD787CE /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
584E34BC3BE863F3647682CF /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5A6C914EA16E1B268034F434 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
625F34F7B39D92A952210EAB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
Expand All @@ -55,13 +63,24 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BFE8844EA1B8DAD0F91BE8D4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
EA74802E011D97599336CEDA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
676BC7E19FDCF896DDE6CA2D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
11390E964DF93FDD14862162 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
791D520225B2BE29FE5603AD /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -76,6 +95,15 @@
path = RunnerTests;
sourceTree = "<group>";
};
3D6E6CF464A086B475403C84 /* Frameworks */ = {
isa = PBXGroup;
children = (
EA74802E011D97599336CEDA /* Pods_Runner.framework */,
584E34BC3BE863F3647682CF /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
Expand All @@ -94,6 +122,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
B9133924A445600D0E2D6A71 /* Pods */,
3D6E6CF464A086B475403C84 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -121,15 +151,30 @@
path = Runner;
sourceTree = "<group>";
};
B9133924A445600D0E2D6A71 /* Pods */ = {
isa = PBXGroup;
children = (
5A6C914EA16E1B268034F434 /* Pods-Runner.debug.xcconfig */,
BFE8844EA1B8DAD0F91BE8D4 /* Pods-Runner.release.xcconfig */,
625F34F7B39D92A952210EAB /* Pods-Runner.profile.xcconfig */,
3B5C5141498770A8AAD787CE /* Pods-RunnerTests.debug.xcconfig */,
3578B4A11D7A13B0C0C33880 /* Pods-RunnerTests.release.xcconfig */,
150F41D93EA1EE707B6893C2 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
DC21CCCA15BD9223F44BF528 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
676BC7E19FDCF896DDE6CA2D /* Frameworks */,
);
buildRules = (
);
Expand All @@ -145,12 +190,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
DD496E7827A31159F1F69860 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
0C28527E7CE60DAE47A7373A /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -222,6 +269,23 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
0C28527E7CE60DAE47A7373A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
Expand Down Expand Up @@ -253,6 +317,50 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
DC21CCCA15BD9223F44BF528 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
DD496E7827A31159F1F69860 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
Expand Down Expand Up @@ -379,6 +487,7 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3B5C5141498770A8AAD787CE /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
Expand All @@ -396,6 +505,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3578B4A11D7A13B0C0C33880 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
Expand All @@ -411,6 +521,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 150F41D93EA1EE707B6893C2 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion packages/movesense_plus/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,16 @@ class MovesenseHomePage extends StatefulWidget {
}

class MovesenseHomePageState extends State<MovesenseHomePage> {
// Test Movesense device address:
// Name: Movesense 233830000816
// Android : 0C:8C:DC:1B:23:BF
// iOS : 89BD8BF8-C9E7-0395-3B1D-119082516DDE

// Replace with your Movesense device address.
final MovesenseDevice device = MovesenseDevice(address: '0C:8C:DC:1B:23:BF');
// final MovesenseDevice device = MovesenseDevice(address: '0C:8C:DC:1B:23:BF');
final MovesenseDevice device = MovesenseDevice(
address: '89BD8BF8-C9E7-0395-3B1D-119082516DDE',
);
bool isSampling = false;
StreamSubscription<MovesenseHR>? hrSubscription;
StreamSubscription<MovesenseState>? stateSubscription;
Expand All @@ -33,6 +41,11 @@ class MovesenseHomePageState extends State<MovesenseHomePage> {
void initState() {
super.initState();
requestPermissions();

// Movesense().scan();
// Movesense().devices.listen((device) {
// debugPrint('>> Device: ${device.address} - ${device.name}');
// });
}

Future<void> requestPermissions() async {
Expand Down
Loading