Framework

MetaWear

Develop Bluetooth Low Energy apps using our sensors and Combine

Overview

This SDK abstracts CoreBluetooth and our MetaWear C/C++ API using concise Combine publishers and presets. It offers three optional imports:

  • MetaWearSync — track groups of MetaWears across Apple devices using iCloud key-value storage

  • MetaWearCpp — mix our C/C++ API with Combine publishers for additional flexibility

  • MetaWearFirmware — update firmware over Bluetooth

MetaMotion S.

Getting Started

Beyond this guide, you can ramp up with an interactive From Zero to Machine Learning tutorial to build a simple app, similar to our barebones integration test host app. Existing MetaWear developers can orient with Migrating from the Bolts SDK. You can also examine the source code of our cross-platform MetaBase app.

1. Entitlements

For each target in your project, go to the Signing & Capabilities tab. For macOS, go to App Sandbox and check Bluetooth. For iOS, add Background Modes and check Uses Bluetooth LE accessories.

Optionally, for MetaWearSync, add iCloud and check Key value storage. If your plan to update MetaWear firmware in your app using MetaWearFirmware, for macOS in App Sandbox check Outgoing Connections.

For all platforms, go to the Info tab and add and provide a message for:

  • Privacy - Bluetooth Always Usage Description

  • Privacy - Bluetooth Peripheral Usage Description

2. Find nearby MetaWears

Create a MetaWearScanner instance or use the sharedRestore singleton.

Goal

API

Search

startScan(higherPerformanceMode:)

Stop searching

stopScan()

Individual discovery events

didDiscover

Refreshing dictionary of devices

discoveredDevicesPublisher

Bluetooth power and authorization

bluetoothState

A restored device may not be nearby right now, but was connected in a previous session. As with all MetaWear interactions, you’ll receive updates on that scanner’s bleQueue.

If you wish to sync MetaWear identities via iCloud, only use the scanner to start/stop scanning and observe Bluetooth state. Use the MetaWearSyncStore to retrieve, remember, and forget MetaWears. It will monitor the scanner’s output for you.

3. Interact

First, to connect to a MetaWear, call connect() or use the connectPublisher(). You can observe connection state via the connectionStatePublisher.

Since nearly every MetaWear interaction is an asynchronous call and response over a potentially low strength Bluetooth connection, this SDK reasons about these events and streams of data through Apple’s Combine framework. If unfamiliar with Combine, the From Zero to Machine Learning tutorial has some basics. A good reference is Joseph Heck’s Using Combine.

Most of this SDK’s functions extend Combine publishers that emit a MetaWear.

Fires

API

On every connection

publishWhenConnected()

First connection only

publishWhenConnected() .first()

On every disconnection

publishWhenDisconnected()

Now, failing if not connected

publishIfConnected()

Now

publish()

From those publishers, autocompletion will reveal MetaWear operators.

Operator

Example

.command()

rename(advertisingName:)

.read()

batteryLevel

.stream()

sensorFusionQuaternion(mode:)

.log()

gyroscope(rate:range:)

.downloadLogs(:)

Returns MWDataTable array and percent progress

Example: Wait until first connection, stream accelerometer vectors, update UI on main
Performing multiple interactions at once

To chain logging or other commands, you can use .optionallyLog() and/or .macro(executeOnBoot:actions:).

To stream an arbitrary number of sensors, you can setup individual pipelines, perhaps coordinated by prefix(untilOutputFrom:). You could also convert the myriad MWStreamable outputs to the same type, such as MWDataTable, and form an array of publishers consumable by Combine’s MergeMany.

Beware that Bluetooth Low Energy usually can’t deliver above 100 Hz without dropping some data. Also, the prefix(untilOutputFrom:) operator must output on the bleQueue to avoid undefined behavior.

Using onboard timers

For logging, you can program a MetaWear to fire an onboard timer to poll a signal (direct from sensor or after some data processing) or fire an event after some trigger.

Operator

Output Reference Pointer

Input

.createPollingTimer()

Data signal embedded in the timer

Publisher<(MetaWear, MWDataSignal)>

.createTimer()

Timer

Publisher<(MetaWear, MWDataSignal)>

.createTimedEvent()

Event timer

Publisher and a closure of commands to execute upon firing

An MWDataSignal is a type alias for OpaquePointer, which is simply a reference to a C type not exposed to Swift.

4. Debugging

Bytes transmitted over Bluetooth and other MetaWear actions can be viewed using the MWConsoleLogger. Just assign a reference to that logger to a MetaWear’s logDelegate property.

Sometimes an incomplete or incorrect command can put a MetaWear in a bad state, which will crash when you reconnect. If reseting the device via unit test our apps fails, manually reset by connecting the MetaWear to power at the same time as pressing the mechanical button for 10 seconds.

5. Testing

Unit test targets can call on a host app that exposes a MetaWearScanner, but XCTest cannot instantiate its own MetaWearScanner with Bluetooth permission on its own.

UI test targets may also improperly parse Swift Package Manager dependencies. (If encountered, please file feedback with Apple.)

Topics

Getting Started

Essentials

Using any MWPublisher ensures calls into the C++ library and reads of any properties occur on the bleQueue.

Interact

The .command(), .log(), .read(), and .stream() operators accept value types conforming to these protocols, which describe communication methods with the MetaWear.

Data Output

Streaming data arrives in Swift types, such as SIMD3<Float>. Logs download in a string-based MWDataTable that can output a .csv file.

Modules

Misc Signals & Commands

Reset or Restart Commands

Utilities

Identifiers

Each machine assigns a MetaWear a unique local UUID, but once connected info contains a stable MAC address.

C++ Bridging

When interacting with the C++ library, use these functions to reference Swift objects.

Opaque Pointer & C++ Aliases

When interacting with the C++ library or forming your own publishers, these type aliases hint at the identity of an OpaquePointer or an integer identifier.

C++ Constants

Useful only when interacting with the C++ library.

Enumerations