Connecting a device
Scan for Movesense sensors, connect to one and follow its connection status.
Your app finds Movesense sensors with a Bluetooth Low Energy (BLE) scan. It then connects to a sensor through the Movesense mobile library (MDS), which the plugin bundles. The sensor is ready for requests and data streams once its status is connected:
sequenceDiagram
participant A as Your app
participant D as MovesenseDevice
participant P as Plugin and MDS
participant S as Sensor
A->>P: startScan()
Note over S: advertises
P-->>A: MovesenseDevice on scanResults
A->>D: connect()
D->>P: connect(address)
P-->>D: command accepted
D-->>A: connect() completes
P->>S: BLE and MDS connection
P-->>D: bleConnected event
P-->>D: connected event
D->>S: GET /Info, GET /System/States/1
S-->>D: device info, battery state
D-->>A: statusEvents: connected
- Your app calls
startScan()on aMovesenseclient. When a sensor advertises a Movesense service,scanResultsemits aMovesenseDevicefor it. - Your app calls
connect()on theMovesenseDevice. The status changes toconnecting, andconnect()completes as soon as the platform accepts the command. - The plugin connects to the sensor. When the BLE link is up, it reports a
bleConnectedevent, and the status staysconnecting. - When MDS completes the connection, the plugin reports a
connectedevent with the serial number of the sensor.MovesenseDevicestores it inserial. MovesenseDevicereads the/Inforesource intodeviceInfoand the battery state intobatteryLevel. The connection completes even when these reads fail.- The status changes to
connected, andstatusEventsemits it.
For deviceInfo and batteryLevel, see Device status.
Scan for sensors
startScan() on a Movesense client starts a scan that runs until you call stopScan(). On iOS, connect() also stops it. The scan reports only sensors that advertise one of the two Movesense service UUIDs:
61353090-8231-49cc-b57a-8863707400410000FDF3-0000-1000-8000-00805F9B34FB
scanResults emits a new MovesenseDevice for every advertisement it receives, so each sensor in range is reported many times. On Android, name may be null. On iOS, the plugin skips sensors without a name.
scanResults is a broadcast stream, so it drops the reports that arrive while nothing listens. Listen before you call startScan(), and deduplicate the reports by address:
The map keeps the first MovesenseDevice of each sensor. Each object tracks its own status, so connect that object and keep using it for the sensor. A sensor's name, such as Movesense 233830000816, ends with its serial number, which helps the user pick a sensor.
startScan() completes when the platform accepts the command. Scan errors arrive later on scanResults, as an MdsError with a status and an error message:
| Platform | Status | Message | Cause |
|---|---|---|---|
| Android | 0 | Bluetooth LE scanner is not available. | Bluetooth is off, or the phone has no Bluetooth. |
| Android | 0 | The message of the SecurityException from Android, or Missing Bluetooth scan permission. | The app does not have the Bluetooth scan permission. |
| Android | The Android error code | BLE scan failed with code <code> | Android failed to start the scan. The code is one of the SCAN_FAILED_* constants of ScanCallback. |
| iOS | 0 | Bluetooth is not powered on. | Bluetooth is off, not ready yet or not available to the app, for example after the user denied Bluetooth access. The plugin starts the scan once Bluetooth is on and the app has access. |
An error does not close scanResults. On Android 11 and lower, a scan without the location permission reports no error and finds no sensors. For the permissions, see Request permissions at runtime.
Connect to a sensor
connect() starts the connection and completes as soon as the platform accepts the command, not when the sensor is connected. Follow the outcome on statusEvents, which emits each change of the MovesenseDeviceStatus:
| Status | When it is set |
|---|---|
disconnected | When you create the MovesenseDevice, when you call disconnect(), and when the plugin reports that the sensor disconnected. |
connecting | When you call connect(). It lasts while MDS connects and MovesenseDevice reads /Info and the battery state. |
connected | When the sensor is ready for requests and data streams. |
error | When connect() throws, or when the plugin reports a connection error for the sensor. |
status holds the current status, and isConnected is true while it is connected. statusEvents is a broadcast stream that emits changes only, so listen to it before you call connect(). serial holds the serial number that MDS reported, from the connected event until the sensor disconnects or a connection error occurs.
connect() does nothing while the status is connecting or connected. When the platform rejects the command, connect() sets the status to error and throws the platform's exception. For example, it throws a PlatformException on macOS, which the plugin does not support.
This function connects to a sensor and waits up to 30 seconds for the outcome:
The status leaves connecting when the sensor is ready, when the plugin reports an error, or when the connection drops. After an error or a timeout, disconnect() ends the attempt and sets the status to disconnected, ready for a new connect(). The timeout matters most on iOS, where the plugin reports no error when a connection attempt fails.
Connect by address
When you know the address of a sensor, for example from an earlier scan, create a MovesenseDevice for it:
The constructor takes these parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
address | String | Yes | — | The address of the sensor on this platform. |
name | String? | No | null | The name of the sensor, such as Movesense 233830000816. The plugin does not use it to connect. |
movesense | Movesense? | No | A new Movesense() | The client that sends the commands of this MovesenseDevice. |
The address depends on the platform:
| Platform | Address | Example |
|---|---|---|
| Android | The Bluetooth MAC address of the sensor, in uppercase | 0C:8C:DC:1B:23:BF |
| iOS | A UUID that iOS assigns to the sensor on this phone | 89BD8BF8-C9E7-0395-3B1D-119082516DDE |
iOS assigns the UUID the first time the phone encounters the sensor, so a UUID stored on one iPhone may not work on another phone. Store the address from a scan on the same phone; if the sensor does not connect, scan again. On iOS, the plugin reports an error event with the message Invalid device UUID. for an address that is not a UUID.
All Movesense clients created without a platform share one platform instance, so they see the same scan results and connection events. A MovesenseDevice that creates its own client therefore works like one from a scan.
To use a client with another platform, such as a fake platform in tests, pass it as movesense. See Testing without a sensor.
Disconnect
disconnect() ends the connection, or stops an attempt that is still running. It does nothing when the status is already disconnected.
Otherwise it sends the command to the platform and does not wait for the sensor. It clears serial, resets batteryLevel to unknown and sets the status to disconnected; deviceInfo keeps its last value.
The plugin does not close open data streams when a sensor disconnects, so cancel them first. To stop a data stream, see Stop a stream.
When you no longer need the MovesenseDevice, call dispose(). It stops following connection events and closes statusEvents, but it does not disconnect the sensor:
Do not use a MovesenseDevice after dispose(): its statusEvents is closed, so you cannot follow its status. To connect to the sensor again, create a new MovesenseDevice.
Handle a lost connection
When the connection to the sensor drops, the plugin reports a disconnected event, and statusEvents emits disconnected. The plugin adds no reconnection logic of its own.
On Android, call connect() again, for example with connectWithTimeout(). Your app's own disconnect() calls, such as the one in connectWithTimeout(), also set the status to disconnected, so reconnect only after a drop.
On iOS, MDS reconnects to the sensor by itself, also in the background. Unless you have disposed it, the MovesenseDevice then reads the device information again and changes to connected without a new connect() call.
The plugin does not restart data streams after a reconnection. To stream across reconnections, see Stop a stream.
Follow all connections
connectionEvents on a Movesense client emits a MovesenseConnectionEvent for every sensor, whichever client or MovesenseDevice started the connection. Use it to follow several sensors in one place. It also lets you connect without a MovesenseDevice: the client has its own connect() and disconnect() methods, which take the address.
The type of an event is a MovesenseConnectionEventType, and each type sets some of the fields address, serial and error:
| Type | Meaning | Fields set |
|---|---|---|
bleConnected | The BLE link is up, and MDS is still setting up its connection. | address |
connected | MDS has completed the connection. | address, serial |
disconnected | The connection has ended. | On Android, address. On iOS, serial, and address when the plugin reported the connection. |
error | A connection attempt failed, or the plugin rejected it. | address, error |
The error message comes from MDS or from the plugin, such as Already connected to <address> on Android or Invalid device UUID. on iOS. A MovesenseDevice picks the events of its sensor by address, ignoring case, or by serial. That is how a disconnected event without an address still reaches it.
This listener logs the events of every sensor:
Platform differences
- When Bluetooth is off,
startScan()reportsBluetooth LE scanner is not available.and does not scan when Bluetooth turns on later. Once Bluetooth is on, callstartScan()again. - A scan failure reports the Android error code as
status, for example1whenstartScan()is called during a scan. The running scan continues. - Connecting to a sensor does not stop a running scan.
- Connecting to an address that is already connected or connecting reports an
errorevent withAlready connected to <address>. EveryMovesenseDevicewith that address that has calledconnect()then changes toerror, including a connected one. The connected one loses itsserialwhile the sensor stays connected, so itsrequest()calls and new streams fail with aStateError. Keep one object per sensor.
connect()stops a running scan. To find more sensors, callstartScan()again.startScan()reportsBluetooth is not powered on.when Bluetooth is not ready for the app: it is off, it is still starting, or the app has no access. The plugin then starts the scan by itself once Bluetooth is on and the app has access. AstartScan()call during a scan is ignored.- The plugin reports no
errorevent when a connection attempt fails, so the status staysconnecting. End such an attempt with a timeout, asconnectWithTimeout()does. - A
disconnectedevent carries the serial, and the address only when the plugin reported theconnectedevent of the sensor. - After a connection drops, MDS reconnects to the sensor by itself, also in the background. See Handle a lost connection.