Skip to content

Commit

Permalink
Merge pull request #424 from cph-cachet/main
Browse files Browse the repository at this point in the history
Rebase w. updated health package
  • Loading branch information
bardram authored Sep 24, 2024
2 parents 547593b + b259233 commit 5bf0175
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 91 deletions.
2 changes: 2 additions & 0 deletions packages/carp_health_package/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## 2.11.0

* upgrading to health v. 11.x
* upgrade to carp_core v. 1.8 & carp_serialization v. 2.0
* type safe `fromJson()` methods & nested json serialization

## 2.10.0

Expand Down
16 changes: 4 additions & 12 deletions packages/carp_health_package/LICENSE
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
MIT License.

Copyright 2020 Copenhagen Center for Health Technology (CACHET) at the Technical University of Denmark (DTU).
Copyright 2020 the Technical University of Denmark (DTU).

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the ”Software”), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ”Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ”AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED ”AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 changes: 7 additions & 8 deletions packages/carp_health_package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ this package only works together with `carp_mobile_sensing`.

`````dart
dependencies:
flutter:
sdk: flutter
carp_core: ^latest
carp_mobile_sensing: ^latest
carp_health_package: ^latest
Expand Down Expand Up @@ -102,7 +100,8 @@ To use this package, import it into your app together with the
`````dart
import 'package:carp_core/carp_core.dart';
import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';
import 'package:carp_health_package/health.dart';
import 'package:carp_health_package/health_package.dart';
import 'package:health/health.dart';
`````

Before creating a study and running it, register this package in the
Expand Down Expand Up @@ -163,7 +162,7 @@ The `HealthSamplingConfiguration` can be configured to collect a set of [`Health

See the [`HealthDataType`](https://pub.dev/documentation/health/latest/health/HealthDataType.html) documentation for a complete list.

A `HealthSamplingConfiguration` is a [`HistoricSamplingConfiguration`](https://pub.dev/documentation/carp_mobile_sensing/latest/domain/HistoricSamplingConfiguration-class.html). This means that when triggered, the task and measure will try to collect data back to the last time data was collected. Hence, this probe is suited for configuration using some trigger that collects data on a regular basis, like the `PeriodicTrigger` used above.
A `HealthSamplingConfiguration` is a [`HistoricSamplingConfiguration`](https://pub.dev/documentation/carp_mobile_sensing/latest/domain/HistoricSamplingConfiguration-class.html). This means that when triggered, the task and measure will try to collect data back to the last time data was collected. Hence, this measure is suited for configuration using some trigger that collects data on a regular basis, like the `PeriodicTrigger` used above.
However, it can also be configured using as an [`AppTask`](https://pub.dev/documentation/carp_mobile_sensing/latest/domain/AppTask-class.html) that asks the user to collect the data.

```dart
Expand Down Expand Up @@ -212,15 +211,15 @@ The data collected is contained in a [`HealthData`](https://pub.dev/documentatio
"date_from": "2023-11-19T09:43:19.841907Z",
"date_to": "2023-11-19T17:43:19.841907Z",
"data_type": "WORKOUT",
"platform": "IOS",
"platform": "APPLE_HEALTH",
"device_id": "1234",
"source_id": "4321",
"source_name": "4321"
}
}
```

Step count collected from Android / Health Connect would look like this.
Similarly, step counts collected from Google Health Connect would look like this.

```json
{
Expand All @@ -236,12 +235,12 @@ Step count collected from Android / Health Connect would look like this.
"date_from": "2024-01-06T23:00:00.000Z",
"date_to": "2024-01-07T22:59:59.999Z",
"data_type": "STEPS",
"platform": "ANDROID",
"platform": "GOOGLE_HEALTH_CONNECT",
"device_id": "SP1A.210812.016",
"source_id": "",
"source_name": "com.sec.android.app.shealth"
}
}
```

The type of the collected health data is `dk.cachet.carp.health.workout` or `dk.cachet.carp.health.steps`. In general, the collected health data has the type of `dk.cachet.carp.health.<health_type>`, where `health_type` is the lower-case version of [`HealthDataType`](https://pub.dev/documentation/health/latest/health/HealthDataType.html).
The type of the collected health data is `dk.cachet.carp.health.workout` or `dk.cachet.carp.health.steps`. In general, the collected health data has the type of `dk.cachet.carp.health.<health_type>`, where `health_type` is the lower-case version of the [`HealthDataType`](https://pub.dev/documentation/health/latest/health/HealthDataType.html).
6 changes: 3 additions & 3 deletions packages/carp_health_package/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: carp_health_package_example
description: Examples of how to use the CANS Health Package.
version: 2.10.0
version: 2.11.0
publish_to: none

environment:
Expand All @@ -11,8 +11,8 @@ dependencies:
flutter:
sdk: flutter

carp_serializable: ^1.1.0
carp_core: ^1.2.0
carp_serializable: ^2.0.0
carp_core: ^1.8.0
carp_mobile_sensing: ^1.9.0

carp_health_package:
Expand Down
49 changes: 26 additions & 23 deletions packages/carp_health_package/lib/health_domain.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
part of 'health_package.dart';

String enumToString(dynamic enumeration) =>
enumeration.toString().split('.').last;

/// Diet, Alcohol, Smoking, Exercise, Sleep (DASES) data types.
enum DasesHealthDataType {
/// Number of calories consumed.
Expand All @@ -27,6 +24,12 @@ enum DasesHealthDataType {
SLEEP,
}

/// Types of health platforms.
enum HealthPlatform {
APPLE_HEALTH,
GOOGLE_HEALTH_CONNECT,
}

/// Map a [DasesHealthDataType] to a [HealthDataUnit].
const Map<DasesHealthDataType, HealthDataUnit> dasesDataTypeToUnit = {
DasesHealthDataType.CALORIES_INTAKE: HealthDataUnit.KILOCALORIE,
Expand All @@ -42,7 +45,7 @@ const Map<DasesHealthDataType, HealthDataUnit> dasesDataTypeToUnit = {
///
/// The [healthDataTypes] parameter specifies which [HealthDataType]
/// to collect.
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
@JsonSerializable(includeIfNull: false, explicitToJson: true)
class HealthSamplingConfiguration extends HistoricSamplingConfiguration {
/// The list of [HealthDataType] to collect.
List<HealthDataType> healthDataTypes;
Expand All @@ -56,7 +59,7 @@ class HealthSamplingConfiguration extends HistoricSamplingConfiguration {
Map<String, dynamic> toJson() => _$HealthSamplingConfigurationToJson(this);

factory HealthSamplingConfiguration.fromJson(Map<String, dynamic> json) =>
FromJsonFactory().fromJson(json) as HealthSamplingConfiguration;
FromJsonFactory().fromJson<HealthSamplingConfiguration>(json);
}

/// A no-op function for deserializing a HealthValue - never used.
Expand Down Expand Up @@ -89,8 +92,8 @@ class HealthData extends Data {
/// Note that the uppercase version is used, e.g. `STEPS`.
String dataType;

/// The platform from which this health data point came from (ANDROID, IOS).
String platform;
/// The platform from which this health data point came from
HealthPlatform platform;

/// The device id of the phone.
String deviceId;
Expand Down Expand Up @@ -119,24 +122,24 @@ class HealthData extends Data {
}

/// Create a [HealthData] from a [HealthDataPoint] health data object.
factory HealthData.fromHealthDataPoint(HealthDataPoint healthDataPoint) {
String uuid =
Uuid().v5(Uuid.NAMESPACE_URL, healthDataPoint.toJson().toString());
return HealthData(
uuid,
healthDataPoint.value,
healthDataPoint.unitString,
healthDataPoint.typeString,
healthDataPoint.dateFrom.toUtc(),
healthDataPoint.dateTo.toUtc(),
enumToString(healthDataPoint.sourcePlatform),
healthDataPoint.sourceDeviceId,
healthDataPoint.sourceId,
healthDataPoint.sourceName);
}
factory HealthData.fromHealthDataPoint(HealthDataPoint healthDataPoint) =>
HealthData(
const Uuid().v1,
healthDataPoint.value,
healthDataPoint.unitString,
healthDataPoint.typeString,
healthDataPoint.dateFrom.toUtc(),
healthDataPoint.dateTo.toUtc(),
HealthPlatform.values[healthDataPoint.sourcePlatform.index],
healthDataPoint.sourceDeviceId,
healthDataPoint.sourceId,
healthDataPoint.sourceName);

@override
Function get fromJsonFunction => _$HealthDataFromJson;

factory HealthData.fromJson(Map<String, dynamic> json) =>
_$HealthDataFromJson(json);
FromJsonFactory().fromJson<HealthData>(json);

@override
Map<String, dynamic> toJson() => _$HealthDataToJson(this);
Expand Down
26 changes: 16 additions & 10 deletions packages/carp_health_package/lib/health_package.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
/*
* Copyright 2020 Copenhagen Center for Health Technology (CACHET) at the
* Technical University of Denmark (DTU).
* Copyright 2020 the Technical University of Denmark (DTU).
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/

/// A CAMS sampling package for collecting health information from Apple Health
/// or Google Fit.
/// or Google Health Connect.
/// Is using the [health](https://pub.dev/packages/health) plugin.
/// Can be configured to collect the different [HealthDataType](https://pub.dev/documentation/health/latest/health/HealthDataType-class.html).
library health_package;

import 'dart:async';
import 'dart:io';
import 'package:json_annotation/json_annotation.dart';
import 'package:uuid/uuid.dart';

import 'package:carp_serializable/carp_serializable.dart';
import 'package:carp_core/carp_core.dart';
Expand Down Expand Up @@ -72,6 +70,7 @@ class HealthSamplingPackage extends SmartphoneSamplingPackage {
static const String HEALTH = HEALTH_NAMESPACE;

/// Returns a health measure for the specified list of health data [types].
///
/// Data will be collected [days] days back in time. If not specified,
/// data will be collected for the last 30 days, which is the maximum
/// that Google Health Connect allow.
Expand Down Expand Up @@ -105,8 +104,17 @@ class HealthSamplingPackage extends SmartphoneSamplingPackage {
FromJsonFactory().registerAll([
HealthService(),
HealthSamplingConfiguration(healthDataTypes: []),
HealthData('', NumericHealthValue(numericValue: 6), '', '',
DateTime.now(), DateTime.now(), '', '', '', ''),
HealthData(
'',
NumericHealthValue(numericValue: 6),
'',
'',
DateTime.now(),
DateTime.now(),
HealthPlatform.APPLE_HEALTH,
'',
'',
''),
]);
}

Expand All @@ -117,7 +125,7 @@ class HealthSamplingPackage extends SmartphoneSamplingPackage {
DeviceManager get deviceManager => _deviceManager;
}

/// Data types available on iOS.
/// Data types available on iOS via Apple Health.
const List<HealthDataType> dataTypesIOS = [
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.AUDIOGRAM,
Expand Down Expand Up @@ -172,9 +180,7 @@ const List<HealthDataType> dataTypesIOS = [
HealthDataType.NUTRITION,
];

/// Data types available on Android.
///
/// Note that these are only the ones supported in Android's Health Connect API.
/// Data types available on Android via the Google Health Connect API.
const List<HealthDataType> dataTypesAndroid = [
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.BASAL_ENERGY_BURNED,
Expand Down
13 changes: 10 additions & 3 deletions packages/carp_health_package/lib/health_package.g.dart

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

10 changes: 4 additions & 6 deletions packages/carp_health_package/lib/health_services.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/*
* Copyright 2024 Copenhagen Center for Health Technology (CACHET) at the
* Technical University of Denmark (DTU).
* Copyright 2024 the Technical University of Denmark (DTU).
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/

part of 'health_package.dart';

/// An [OnlineService] for the [health](https://pub.dev/packages/health) service.
///
/// On Android, this health package always uses Google [Health Connect](https://developer.android.com/health-and-fitness/guides/health-connect).
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
@JsonSerializable(includeIfNull: false, explicitToJson: true)
class HealthService extends OnlineService {
/// The type of the health service.
static const String DEVICE_TYPE =
Expand All @@ -25,7 +23,7 @@ class HealthService extends OnlineService {
@override
Function get fromJsonFunction => _$HealthServiceFromJson;
factory HealthService.fromJson(Map<String, dynamic> json) =>
FromJsonFactory().fromJson(json) as HealthService;
FromJsonFactory().fromJson<HealthService>(json);
@override
Map<String, dynamic> toJson() => _$HealthServiceToJson(this);
}
Expand Down Expand Up @@ -54,7 +52,7 @@ class HealthServiceManager extends OnlineServiceManager<HealthService> {
HealthServiceManager([
HealthService? configuration,
]) : super(HealthService.DEVICE_TYPE, configuration) {
Health().configure(useHealthConnectIfAvailable: true);
Health().configure();
}

@override
Expand Down
3 changes: 1 addition & 2 deletions packages/carp_health_package/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ dependencies:
flutter:
sdk: flutter

# carp_serializable: ^1.1.0
carp_serializable: ^2.0.0
carp_core: ^1.8.0
carp_mobile_sensing: ^1.10.0

health: ^11.0.0
json_annotation: ^4.8.0
uuid: '>=3.0.1 <5.0.0'

# Overriding carp libraries to use the local copy
# Remove this before release of package
Expand Down
Loading

0 comments on commit 5bf0175

Please sign in to comment.