Skip to content

Commit

Permalink
Merge branch 'release/0.4.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
emersonf committed Feb 23, 2016
2 parents 865f9ae + 01369fd commit fcea586
Show file tree
Hide file tree
Showing 50 changed files with 974 additions and 631 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ subprojects {

ext {
javaVersion = 1.8
shimmerVersion = '0.4.2'
omhSchemaSdkVersion = '1.0.3'
shimmerVersion = '0.4.3'
omhSchemaSdkVersion = '1.0.5'
}

sourceCompatibility = javaVersion
Expand Down
2 changes: 1 addition & 1 deletion shim-server-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "shim-server-ui",
"version": "0.4.2",
"version": "0.4.3",
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.5",
Expand Down
2 changes: 1 addition & 1 deletion shim-server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
}

ext {
springBootVersion = "1.3.1.RELEASE"
springBootVersion = "1.3.2.RELEASE"
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import static org.openmhealth.schema.domain.omh.DurationUnit.DAY;
import static org.openmhealth.schema.domain.omh.DurationUnit.MILLISECOND;
import static org.openmhealth.schema.domain.omh.KcalUnit.KILOCALORIE;
import static org.openmhealth.schema.domain.omh.LengthUnit.KILOMETER;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.*;

Expand Down Expand Up @@ -95,6 +96,9 @@ protected Optional<DataPoint<PhysicalActivity>> asDataPoint(JsonNode node) {
activityBuilder.setDistance(new LengthUnitValue(KILOMETER, distance.get()));
}

asOptionalDouble(node, "calories")
.ifPresent(calories -> activityBuilder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, calories)));

PhysicalActivity measure = activityBuilder.build();
Optional<Long> externalId = asOptionalLong(node, "logId");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public ShimDataType[] getShimDataTypes() {
BODY_MASS_INDEX,
HEART_RATE,
STEP_COUNT,
SLEEP_DURATION
SLEEP_DURATION,
OXYGEN_SATURATION
};
}

Expand Down Expand Up @@ -164,7 +165,8 @@ public enum IHealthDataTypes implements ShimDataType {
BODY_MASS_INDEX(singletonList("weight.json")),
HEART_RATE(newArrayList("bp.json", "spo2.json")),
STEP_COUNT(singletonList("activity.json")),
SLEEP_DURATION(singletonList("sleep.json"));
SLEEP_DURATION(singletonList("sleep.json")),
OXYGEN_SATURATION(singletonList("spo2.json"));

private List<String> endPoint;

Expand Down Expand Up @@ -296,6 +298,9 @@ else if (endPoint == "spo2.json") {
mapper = new IHealthBloodOxygenEndpointHeartRateDataPointMapper();
break;
}
case OXYGEN_SATURATION:
mapper = new IHealthOxygenSaturationDataPointMapper();
break;
default:
throw new UnsupportedOperationException();
}
Expand Down Expand Up @@ -339,6 +344,8 @@ private List<String> getSvValues(IHealthDataTypes dataType) {
return singletonList(serialValues.get("sleepSV"));
case HEART_RATE:
return newArrayList(serialValues.get("bloodPressureSV"), serialValues.get("spo2SV"));
case OXYGEN_SATURATION:
return singletonList(serialValues.get("spo2SV"));
default:
throw new UnsupportedOperationException();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2016 Open mHealth
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openmhealth.shim.ihealth.mapper;

import com.fasterxml.jackson.databind.JsonNode;
import org.openmhealth.schema.domain.omh.DataPoint;
import org.openmhealth.schema.domain.omh.OxygenSaturation;
import org.openmhealth.schema.domain.omh.TypedUnitValue;

import java.math.BigDecimal;
import java.util.Optional;

import static java.math.BigDecimal.ZERO;
import static org.openmhealth.schema.domain.omh.OxygenSaturation.MeasurementMethod.PULSE_OXIMETRY;
import static org.openmhealth.schema.domain.omh.OxygenSaturation.MeasurementSystem.PERIPHERAL_CAPILLARY;
import static org.openmhealth.schema.domain.omh.PercentUnit.PERCENT;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.asRequiredBigDecimal;


/**
* A mapper that translates responses from the iHealth <code>/spo2.json</code> endpoint into {@link OxygenSaturation}
* measures.
*
* @author Chris Schaefbauer
* @see <a href="http://developer.ihealthlabs.com/dev_documentation_RequestfordataofBloodOxygen.htm">endpoint
* documentation</a>
*/
public class IHealthOxygenSaturationDataPointMapper extends IHealthDataPointMapper<OxygenSaturation> {

@Override
protected String getListNodeName() {
return "BODataList";
}

@Override
protected Optional<String> getMeasureUnitNodeName() {

return Optional.empty();
}

@Override
protected Optional<DataPoint<OxygenSaturation>> asDataPoint(JsonNode listEntryNode,
Integer measureUnitMagicNumber) {

BigDecimal bloodOxygenValue = asRequiredBigDecimal(listEntryNode, "BO");

// iHealth has stated that missing values would most likely be represented as a 0 value for the field
if (bloodOxygenValue.compareTo(ZERO) == 0) {
return Optional.empty();
}

OxygenSaturation.Builder oxygenSaturationBuilder =
new OxygenSaturation.Builder(new TypedUnitValue<>(PERCENT, bloodOxygenValue))
.setMeasurementMethod(PULSE_OXIMETRY)
.setMeasurementSystem(PERIPHERAL_CAPILLARY);

getEffectiveTimeFrameAsDateTime(listEntryNode).ifPresent(oxygenSaturationBuilder::setEffectiveTimeFrame);
getUserNoteIfExists(listEntryNode).ifPresent(oxygenSaturationBuilder::setUserNotes);

OxygenSaturation oxygenSaturation = oxygenSaturationBuilder.build();

return Optional.of(new DataPoint<>(createDataPointHeader(listEntryNode, oxygenSaturation), oxygenSaturation));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

import com.fasterxml.jackson.databind.JsonNode;
import org.openmhealth.schema.domain.omh.DataPoint;
import org.openmhealth.schema.domain.omh.KcalUnitValue;
import org.openmhealth.schema.domain.omh.PhysicalActivity;

import java.time.ZoneOffset;
import java.util.Optional;

import static org.openmhealth.schema.domain.omh.KcalUnit.KILOCALORIE;
import static org.openmhealth.schema.domain.omh.TimeInterval.ofStartDateTimeAndEndDateTime;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.*;

Expand Down Expand Up @@ -81,6 +83,9 @@ protected Optional<DataPoint<PhysicalActivity>> asDataPoint(JsonNode listEntryNo
getDateTimeWithCorrectOffset(endTimeUnixEpochSecs.get(), ZoneOffset.of(timeZoneString))));
}

asOptionalDouble(listEntryNode, "Calories").ifPresent(
calories -> physicalActivityBuilder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, calories)));

PhysicalActivity physicalActivity = physicalActivityBuilder.build();

return Optional.of(new DataPoint<>(createDataPointHeader(listEntryNode, physicalActivity), physicalActivity));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

import com.fasterxml.jackson.databind.JsonNode;
import org.openmhealth.schema.domain.omh.DurationUnitValue;
import org.openmhealth.schema.domain.omh.KcalUnitValue;
import org.openmhealth.schema.domain.omh.LengthUnitValue;
import org.openmhealth.schema.domain.omh.PhysicalActivity;
import org.openmhealth.schema.domain.omh.PhysicalActivity.SelfReportedIntensity;

import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.HashMap;
Expand All @@ -34,6 +36,7 @@
import static java.time.Instant.ofEpochSecond;
import static java.time.OffsetDateTime.ofInstant;
import static org.openmhealth.schema.domain.omh.DurationUnit.SECOND;
import static org.openmhealth.schema.domain.omh.KcalUnit.KILOCALORIE;
import static org.openmhealth.schema.domain.omh.LengthUnit.METER;
import static org.openmhealth.schema.domain.omh.PhysicalActivity.SelfReportedIntensity.*;
import static org.openmhealth.schema.domain.omh.TimeInterval.ofEndDateTimeAndDuration;
Expand Down Expand Up @@ -107,10 +110,23 @@ protected Optional<PhysicalActivity> getMeasure(JsonNode workoutNode) {
Optional<ZoneId> timeZoneId = asOptionalZoneId(workoutNode, "details.tz");

if (endTimestamp.isPresent() && durationInSec.isPresent() && timeZoneId.isPresent()) {
DurationUnitValue durationUnitValue = new DurationUnitValue(SECOND, durationInSec.get());

OffsetDateTime endDateTime = ofInstant(ofEpochSecond(endTimestamp.get()),
JawboneDataPointMapper.getTimeZoneForTimestamp(workoutNode, endTimestamp.get()));
builder.setEffectiveTimeFrame(ofEndDateTimeAndDuration(endDateTime, durationUnitValue));
getTimeZoneForTimestamp(workoutNode, endTimestamp.get()));

builder.setEffectiveTimeFrame(
ofEndDateTimeAndDuration(endDateTime, new DurationUnitValue(SECOND, durationInSec.get())));
}

Optional<BigDecimal> totalCalories = asOptionalBigDecimal(workoutNode, "details.calories");

if (totalCalories.isPresent()) {

asOptionalBigDecimal(workoutNode, "details.bmr_calories")
.ifPresent(bmrCalories -> {
BigDecimal caloriesBurned = totalCalories.get().subtract(bmrCalories);
builder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, caloriesBurned));
});
}

asOptionalInteger(workoutNode, "details.intensity")
Expand Down Expand Up @@ -151,7 +167,7 @@ public String getActivityName(@Nullable String title, @Nullable Integer workoutT
*/
public SelfReportedIntensity asSelfReportedIntensity(int intensityValue) {

switch ( intensityValue ) {
switch (intensityValue) {
case 1:
return LIGHT;
case 2:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@
package org.openmhealth.shim.misfit.mapper;

import com.fasterxml.jackson.databind.JsonNode;
import org.openmhealth.schema.domain.omh.DataPoint;
import org.openmhealth.schema.domain.omh.DurationUnitValue;
import org.openmhealth.schema.domain.omh.LengthUnitValue;
import org.openmhealth.schema.domain.omh.PhysicalActivity;
import org.openmhealth.schema.domain.omh.*;

import java.time.OffsetDateTime;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.openmhealth.schema.domain.omh.DurationUnit.SECOND;
import static org.openmhealth.schema.domain.omh.KcalUnit.KILOCALORIE;
import static org.openmhealth.schema.domain.omh.LengthUnit.MILE;
import static org.openmhealth.schema.domain.omh.TimeInterval.ofStartDateTimeAndDuration;
import static org.openmhealth.shim.common.mapper.JsonNodeMappingSupport.*;
Expand Down Expand Up @@ -69,6 +67,9 @@ public Optional<DataPoint<PhysicalActivity>> asDataPoint(JsonNode sessionNode) {
builder.setEffectiveTimeFrame(ofStartDateTimeAndDuration(startDateTime.get(), durationUnitValue));
}

asOptionalBigDecimal(sessionNode, "calories")
.ifPresent(calories -> builder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, 96.8)));

PhysicalActivity measure = builder.build();

Optional<String> externalId = asOptionalString(sessionNode, "id");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ public void initializeResponseNode() throws IOException {
@Test
public void asDataPointsShouldReturnCorrectNumberOfDataPoints() {

List<DataPoint<StepCount>> dataPoints = mapper.asDataPoints(singletonList(responseNode));
assertThat(dataPoints.size(), equalTo(2));
assertThat(mapper.asDataPoints(singletonList(responseNode)).size(), equalTo(2));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.openmhealth.schema.domain.omh.DurationUnit.*;
import static org.openmhealth.schema.domain.omh.DurationUnit.DAY;
import static org.openmhealth.schema.domain.omh.KcalUnit.*;
import static org.openmhealth.schema.domain.omh.LengthUnit.KILOMETER;


Expand Down Expand Up @@ -62,21 +64,23 @@ public void asDataPointsShouldReturnCorrectDataPointForSingleActivity() {

List<DataPoint<PhysicalActivity>> dataPoints = mapper.asDataPoints(singleActivityResponseNode);

assertThatDataPointMatches(dataPoints.get(0), "Walk", "2014-06-19", "09:00", 3.36, 3600000L, 79441095L);
assertThatDataPointMatches(dataPoints.get(0), "Walk", "2014-06-19", "09:00", 3.36, 3600000L, 79441095L, 128.0);
}

@Test
public void asDataPointsShouldReturnCorrectDataPointsForMultipleActivities() {

List<DataPoint<PhysicalActivity>> dataPoints = mapper.asDataPoints(multipleActivityResponseNode);

assertThatDataPointMatches(dataPoints.get(0), "Run", "2015-06-23", "11:55", 6.43738, 1440000L, 253202765L);
assertThatDataPointMatches(dataPoints.get(1), "Swimming", "2015-06-23", "10:00", null, null, 253246706L);
assertThatDataPointMatches(dataPoints.get(2), "Walk", "2015-06-23", 6.43738, 253202766L);
assertThatDataPointMatches(dataPoints.get(0), "Run", "2015-06-23", "11:55", 6.43738, 1440000L, 253202765L,
150.0);
assertThatDataPointMatches(dataPoints.get(1), "Swimming", "2015-06-23", "10:00", null, null, 253246706L, null);
assertThatDataPointMatches(dataPoints.get(2), "Walk", "2015-06-23", 6.43738, 253202766L, 200.0);
}

public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, String expectedActivityName,
String expectedEffectiveDate, Double expectedDistance, Long expectedExternalId) {
String expectedEffectiveDate, Double expectedDistance, Long expectedExternalId,
Double expectedCaloriesBurned) {

OffsetDateTime expectedEffectiveStartDateTime =
OffsetDateTime.of(LocalDate.parse(expectedEffectiveDate).atStartOfDay(), UTC);
Expand All @@ -85,11 +89,12 @@ public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, St
TimeInterval.ofStartDateTimeAndDuration(expectedEffectiveStartDateTime, new DurationUnitValue(DAY, 1)));

assertThatDataPointMatches(dataPoint, expectedActivityName, expectedTimeFrame, expectedDistance,
expectedExternalId);
expectedExternalId, expectedCaloriesBurned);
}

public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, String expectedActivityName,
TimeFrame expectedTimeFrame, Double expectedDistance, Long expectedExternalId) {
TimeFrame expectedTimeFrame, Double expectedDistance, Long expectedExternalId,
Double expectedCaloriesBurned) {

PhysicalActivity.Builder expectedMeasureBuilder = new PhysicalActivity.Builder(expectedActivityName);

Expand All @@ -99,6 +104,10 @@ public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, St
expectedMeasureBuilder.setDistance(new LengthUnitValue(KILOMETER, expectedDistance));
}

if (expectedCaloriesBurned != null) {
expectedMeasureBuilder.setCaloriesBurned(new KcalUnitValue(KILOCALORIE, expectedCaloriesBurned));
}

PhysicalActivity expectedPhysicalActivity = expectedMeasureBuilder.build();

assertThat(dataPoint.getBody(), equalTo(expectedPhysicalActivity));
Expand All @@ -111,15 +120,15 @@ public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, St

public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, String expectedActivityName,
String expectedEffectiveDate, String expectedEffectiveStartTime, Double expectedDistance,
Long expectedDurationInMs, Long expectedExternalId) {
Long expectedDurationInMs, Long expectedExternalId, Double expectedCaloriesBurned) {

OffsetDateTime expectedEffectiveStartDateTime = OffsetDateTime
.of(LocalDate.parse(expectedEffectiveDate), LocalTime.parse(expectedEffectiveStartTime), UTC);

TimeFrame expectedTimeFrame;

if (expectedDurationInMs != null) {
DurationUnitValue expectedDuration = new DurationUnitValue(DurationUnit.MILLISECOND, expectedDurationInMs);
DurationUnitValue expectedDuration = new DurationUnitValue(MILLISECOND, expectedDurationInMs);

expectedTimeFrame = new TimeFrame(
TimeInterval.ofStartDateTimeAndDuration(expectedEffectiveStartDateTime, expectedDuration));
Expand All @@ -129,6 +138,6 @@ public void assertThatDataPointMatches(DataPoint<PhysicalActivity> dataPoint, St
}

assertThatDataPointMatches(dataPoint, expectedActivityName, expectedTimeFrame, expectedDistance,
expectedExternalId);
expectedExternalId, expectedCaloriesBurned);
}
}
Loading

0 comments on commit fcea586

Please sign in to comment.