CARP Data Backend

pub package pub points github stars MIT License arXiv

This package integrates the CARP Mobile Sensing Framework with the CARP Web Services (CAWS) backend.

For an overview of all CAMS packages, see CARP Mobile Sensing in Flutter. For documentation on how to use CAMS, see the CAMS wiki.

This library supports:

  • downloading a study invitation
  • download a study deployment
  • getting and uploading resources
    • informed consent document
    • translation files
    • messages
  • uploading collected data

from/to a CAWS server.

Note

This package does nothing on its own and is only to be used as part of the overall CARP Mobile Sensing ecosystem. See the CAMS wiki for documentation on how to use CAMS, and checkout the CARP Mobile Sening Demo App for a full example of an app using CARP Mobile Sensing and CAWS, including this library.

Using the Plugin

Add carp_backend as a dependency in your pubspec.yaml file and import the library along with the other CAMS libraries.

import 'package:carp_core/carp_core.dart';
import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';
import 'package:carp_webservices/carp_auth/carp_auth.dart';
import 'package:carp_webservices/carp_services/carp_services.dart';
import 'package:carp_backend/carp_backend.dart';

Configuration

This library uses the carp_webservices API for accessing CAWS. In order to access CAWS, a CarpApp needs to be configured like this:

  // Configure an app that points to the CARP web services (CAWS)
  final Uri uri = Uri(
    scheme: 'https',
    host: 'dev.carp.dk',
  );

  late CarpApp app = CarpApp(
    name: "CAWS @ DTU",
    uri: uri,
    studyId: '<the_study_id_if_known>',
    studyDeploymentId: '<the_study_deployment_id_if_known>',
  );

  // The authentication configuration
  late CarpAuthProperties authProperties = CarpAuthProperties(
    authURL: uri,
    clientId: 'studies-app',
    redirectURI: Uri.parse('carp-studies-auth://auth'),
    // For authentication at CAWS the path is '/auth/realms/Carp'
    discoveryURL: uri.replace(pathSegments: [
      'auth',
      'realms',
      'Carp',
    ]),
  );

  // Configure the CAWS services
  await CarpAuthService().configure(authProperties);
  CarpService().configure(app);

  // Authenticate at CAWS using username and password
  await CarpAuthService().authenticateWithUsernamePassword(
    username: 'the_username',
    password: 'the_password',
  );

// Configure the other services needed.
// Note that these CAWS services work as singletons and can be
// accessed throughout the app.
CarpParticipationService().configureFrom(CarpService());
CarpDeploymentService().configureFrom(CarpService());

Downloading a study invitation and deployment from CAWS

Getting a study invitation and deployment from CAWS is done using the CarpParticipationService and CarpDeploymentService services, respectively.

// Get the invitations to studies from CARP for this user.
List<ActiveParticipationInvitation> invitations =
    await CarpParticipationService().getActiveParticipationInvitations();

// Use the first (i.e. latest) invitation.
final invitation = invitations[0];

The invitation contains information about the deployment, including the studyDeploymentId and the device roleName. This invitation is used to configure a study, which can be deployed and started in a SmartPhoneClientManager.

// Create and configure a client manager for this phone.
// If no deployment service is specified in the configure method,
// the default CarpDeploymentService() singleton is used.
final client = SmartPhoneClientManager();
await client.configure();

// Define the study based on the invitation and add it to the client.
final study = await client.addStudy(
  invitation.studyDeploymentId!,
  invitation.assignedDevices!.first.device.roleName,
);

// Get the study controller and try to deploy the study.
//
// If "useCached" is true and the study has already been deployed on this
// phone, the local cache will be used (default behavior).
// If not deployed before (i.e., cached) the study deployment will be
// fetched from the deployment service.
final controller = client.getStudyRuntime(study);
await controller?.tryDeployment(useCached: false);

// Configure the controller
await controller?.configure();

// Start sampling
controller?.start();

Getting and Uploading Resources

CAWS handles three types of special-purpose resources:

  • The informed consent document to be shown to the user
  • A set of messages and news items to be show to the user
  • Translation files that can help translate the text used in a study deployment protocol (like the text is a user survey)

Each of the are handled by an InformedConsentManager, MessageManager, and LocalizationManager, respectively. All of these managers are implemented in the CarpResourceManager manager.

Here is an example of uploading and downloading an informed consent document to be shown to the user (via the Research Package):

  // Create and initialize the informed consent manager.
  //
  // The CarpResourceManager() is a singleton that uses the
  // the CarpService() singleton for accessing CAWS. Hence,
  // CarpService needs to be authenticated and initialized before
  // using the CarpResourceManager.
  CarpResourceManager icManager = CarpResourceManager();
  icManager.initialize();

  // Create a simple informed consent...
  final consent = RPOrderedTask(identifier: '12', steps: [
    RPInstructionStep(
      identifier: "1",
      title: "Welcome!",
    )..text = "Welcome to this study! ",
    RPCompletionStep(
        identifier: "2",
        title: "Thank You!",
        text: "We saved your consent document."),
  ]);
  // .. and upload it to CAWS.
  await icManager.setInformedConsent(consent);

  // Get the informed consent back as a RPOrderedTask, if available.
  RPOrderedTask? myConsent = await icManager.getInformedConsent();

Messages

Below are examples of how messages are handled:

  // Create and initialize the message manager.
  MessageManager messageManager = CarpResourceManager();
  messageManager.initialize();

  // Create a message and upload it to CAWS.
  messageManager.setMessage(Message(
    id: '123',
    title: 'Great News!',
    message: 'There are great news from CARP',
    type: MessageType.news,
  ));

  // Get all messages from CAWS.
  messageManager.getMessages().then((messages) {
    print('Messages: $messages');
  });

  // Get a specific message from CAWS.
  messageManager.getMessage('123').then((message) {
    print('Message: $message');
  });

  // Delete a specific message from CAWS.
  messageManager.deleteMessage('123').then((_) {
    print('Message deleted...');
  });

Translations Files

Translations files can be up- and downloaded like this:

  // Create and initialize the message manager.
  LocalizationManager localizationManager = CarpResourceManager();
  localizationManager.initialize();

  // A Danish locale
  var locale = Locale('da');

  // Create a translation file for Danish and upload it to CAWS.
  localizationManager.setLocalizations(locale, {
    'morning': 'morgen',
    'midday': 'middag',
    'evening': 'aften',
  });

  // Get translation file for Danish
  if (localizationManager.isSupported(locale)) {
    localizationManager.getLocalizations(locale);
  }

Using translations in an app is a whole separate topic, which is supported by the Research Package and described in this tutorial on Localization Support in Research Package. An example of using localization downloaded from CAWS can be found in the CARP Studies App. In the carp_study_app.dart file a RPLocalizationsDelegate is used, which again used a ResourceLocalizationLoader to load the translations from CAWS.

Uploading of Data to CARP

Configuration of data upload is done as a DataEndPoint, which is part of a SmartphoneStudyProtocol.

CAWS and hence this plugin supports three methods of data upload:

Specifying a CARP Data Endpoint

Create a CarpDataEndPoint that specify which method to use for uploading data, and the details. For example, a streaming data upload is created like this:

// Using the (default) data stream batch upload method
var streamingEndPoint = CarpDataEndPoint();

Upload methods are defined in the uploadMethod property. A data point upload method is created like this:

// Using the "legacy" DataPoint endpoint for uploading batches of data points.
var dataPointEndPoint =
    CarpDataEndPoint(uploadMethod: CarpUploadMethod.datapoint);

Similarly, an endpoint uploading the raw SQLite db files can be specified:

// Using the file method would upload SQLite db files.
var fileEndPoint = CarpDataEndPoint(uploadMethod: CarpUploadMethod.file);

There are some details in how the three different types of endpoints work:

  • Streaming - Using the streaming data method requires that the study deployment has been obtained from CAWS via an invitation, as shown above. This ensures that there is a linkage between the study deployment ID from the deployment and the ID in the data being streamed back to CAWS.

  • Data Point & File - The data point and file endpoints need the study ID and study deployment ID. This can be obtained via the invitation (as above), but it can also be specified when creating the CarpApp configuration. Hence, the data point and file endpoints can be used if these IDs are known, e.g., are static to the app.

For all three upload types (stream, data point, and file), additional parameters can be specified for a an endpoint.

/// Specify parameters on upload interval (in minutes), if upload only
/// should happen when the phone is connected to WiFi, and whether data
/// buffered locally on the phone should be deleted when uploaded.
streamingEndPoint = CarpDataEndPoint(
  uploadInterval: 20,
  onlyUploadOnWiFi: true,
  deleteWhenUploaded: false,
);

Adding a Data Endpoint to the Study Protocol

To use the data endpoint, add it to the study protocol like this:

// Create a study protocol with a specific data endpoint.
SmartphoneStudyProtocol protocol = SmartphoneStudyProtocol(
  ownerId: 'AB',
  name: 'Track patient movement',
  dataEndPoint: streamingEndPoint,
);

Register the Data Manager

In order to use the CAWS data manger for uploading of data, you should register its factory in the DataManagerRegistry.

// Register CAWS as a data backend where data can be uploaded.
DataManagerRegistry().register(CarpDataManagerFactory());

Features and bugs

Please file feature requests and bug reports at the issue tracker. Remember to specify which CARP library you're filing an issue for (in this case carp_backend).

License

This software is copyright (c) Copenhagen Center for Health Technology (CACHET) at the Technical University of Denmark (DTU). This software is made available 'as-is' in a MIT license.

Libraries

carp_backend