diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailyRestingHeartRateGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailyRestingHeartRateGoogleHealthAvroConverter.kt index 5b4e98f3..99ab089b 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailyRestingHeartRateGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailyRestingHeartRateGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.restingHeartRate +import org.radarbase.googlehealth.util.googleHealthDailyRestingHeartRate class DailyRestingHeartRateGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -36,7 +36,7 @@ class DailyRestingHeartRateGoogleHealthAvroConverter(topic: String) : dateNode["month"].asInt(), dateNode["day"].asInt(), ) - val record = restingHeartRate { + val record = googleHealthDailyRestingHeartRate { date = isoDate timeReceived = nowEpochSeconds() restingHeartRate = bpm diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailySleepTemperatureDerivationsGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailySleepTemperatureDerivationsGoogleHealthAvroConverter.kt index f4c070ba..71e45cc0 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailySleepTemperatureDerivationsGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/DailySleepTemperatureDerivationsGoogleHealthAvroConverter.kt @@ -19,8 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.skinTemperature -import org.radarcns.connector.fitbit.FitbitSkinTemperatureLogType +import org.radarbase.googlehealth.util.googleHealthDailySleepTemperatureDerivations class DailySleepTemperatureDerivationsGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -31,12 +30,20 @@ class DailySleepTemperatureDerivationsGoogleHealthAvroConverter(topic: String) : val data = point["dailySleepTemperatureDerivations"] ?: return emptyList() val nightly = data["nightlyTemperatureCelsius"]?.takeIf { it.isNumber }?.floatValue() ?: return emptyList() val baseline = data["baselineTemperatureCelsius"]?.takeIf { it.isNumber }?.floatValue() ?: return emptyList() - val time = parseDate(data) ?: return emptyList() - val record = skinTemperature { - this.time = epochSeconds(time) + // `date` is the civil date (in the user's timezone) the derivation is for — emit it + // directly as a yyyy-MM-dd string, like DailyRestingHeartRate, rather than as a + // UTC-midnight instant that could shift to the wrong local day downstream. + val dateNode = data["date"] ?: return emptyList() + val isoDate = String.format( + "%04d-%02d-%02d", + dateNode["year"].asInt(), + dateNode["month"].asInt(), + dateNode["day"].asInt(), + ) + val record = googleHealthDailySleepTemperatureDerivations { + date = isoDate timeReceived = nowEpochSeconds() relativeTemperature = nightly - baseline - logType = FitbitSkinTemperatureLogType.UNKNOWN } return listOf(user.observationKey to record) } diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/ExerciseGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/ExerciseGoogleHealthAvroConverter.kt index d5a62552..0751aca1 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/ExerciseGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/ExerciseGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.activityHeartRate +import org.radarbase.googlehealth.util.exerciseHeartRate import org.radarbase.googlehealth.util.activityLogRecord class ExerciseGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -40,10 +40,14 @@ class ExerciseGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConvert val energyKj = caloriesKcal?.let { (it * KCAL_TO_KJ).toFloat() } val stepCount = metrics?.get("steps")?.takeIf { !it.isNull }?.asInt() val avgHr = metrics?.get("averageHeartRateBeatsPerMinute")?.takeIf { !it.isNull }?.asInt() - val avgHeartRate = avgHr?.let { activityHeartRate { mean = it } } + val avgHeartRate = avgHr?.let { exerciseHeartRate { mean = it } } val exerciseType = data["exerciseType"]?.asText() - val activityId = (point["name"]?.asText() ?: exerciseType ?: "") - .hashCode().toLong() + // The exercise (log) id is the last segment of the reconcile data point's `dataPointName` + // (e.g. users/{u}/dataTypes/exercise/dataPoints/7726011858216679720). Exercise is an + // identifiable data type, so this is always present — fail loudly rather than emit a + // fabricated id. It is also the id used to export the session's TCX track. + val activityId = point["dataPointName"]?.asText()?.substringAfterLast('/')?.toLongOrNull() + ?: throw IllegalStateException("Exercise data point has no usable dataPointName log id: $point") val record = activityLogRecord { time = epochSeconds(start) timeReceived = nowEpochSeconds() diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateGoogleHealthAvroConverter.kt index 509f8eaa..e44491c1 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.intradayHeartRate +import org.radarbase.googlehealth.util.googleHealthHeartRate class HeartRateGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { override fun convertDataPoint( @@ -29,7 +29,7 @@ class HeartRateGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConver val data = point["heartRate"] ?: return emptyList() val time = parseSampleTime(data) ?: return emptyList() val bpm = data["beatsPerMinute"]?.asInt() ?: return emptyList() - val record = intradayHeartRate { + val record = googleHealthHeartRate { this.time = epochSeconds(time) timeReceived = nowEpochSeconds() timeInterval = 1 diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateVariabilityGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateVariabilityGoogleHealthAvroConverter.kt index 4ec61852..6930b0dc 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateVariabilityGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/HeartRateVariabilityGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.intradayHeartRateVariability +import org.radarbase.googlehealth.util.googleHealthHeartRateVariability class HeartRateVariabilityGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -31,18 +31,11 @@ class HeartRateVariabilityGoogleHealthAvroConverter(topic: String) : val time = parseSampleTime(data) ?: return emptyList() val rmssd = data["rootMeanSquareOfSuccessiveDifferencesMilliseconds"]?.floatValue() ?: return emptyList() - val record = intradayHeartRateVariability { + val record = googleHealthHeartRateVariability { this.time = epochSeconds(time) timeReceived = nowEpochSeconds() this.rmssd = rmssd - coverage = UNAVAILABLE - highFrequency = UNAVAILABLE - lowFrequency = UNAVAILABLE } return listOf(user.observationKey to record) } - - companion object { - private const val UNAVAILABLE = 0.0f - } } diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/OxygenSaturationGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/OxygenSaturationGoogleHealthAvroConverter.kt index 6e864218..120451d3 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/OxygenSaturationGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/OxygenSaturationGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.intradaySpo2 +import org.radarbase.googlehealth.util.googleHealthOxygenSaturation class OxygenSaturationGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -30,10 +30,10 @@ class OxygenSaturationGoogleHealthAvroConverter(topic: String) : val data = point["oxygenSaturation"] ?: return emptyList() val time = parseSampleTime(data) ?: return emptyList() val pct = data["percentage"]?.floatValue() ?: return emptyList() - val record = intradaySpo2 { + val record = googleHealthOxygenSaturation { this.time = epochSeconds(time) timeReceived = nowEpochSeconds() - spo2 = pct + percentage = pct } return listOf(user.observationKey to record) } diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/RespiratoryRateSleepSummaryGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/RespiratoryRateSleepSummaryGoogleHealthAvroConverter.kt index e5243b2b..a65c221f 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/RespiratoryRateSleepSummaryGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/RespiratoryRateSleepSummaryGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.breathingRate +import org.radarbase.googlehealth.util.googleHealthRespiratoryRateSleepSummary class RespiratoryRateSleepSummaryGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -33,7 +33,7 @@ class RespiratoryRateSleepSummaryGoogleHealthAvroConverter(topic: String) : val full = data["fullSleepStats"]?.get("breathsPerMinute")?.floatValue() ?: UNAVAILABLE val light = data["lightSleepStats"]?.get("breathsPerMinute")?.floatValue() ?: UNAVAILABLE val rem = data["remSleepStats"]?.get("breathsPerMinute")?.floatValue() ?: UNAVAILABLE - val record = breathingRate { + val record = googleHealthRespiratoryRateSleepSummary { this.time = epochSeconds(time) timeReceived = nowEpochSeconds() lightSleep = light diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepClassicGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepClassicGoogleHealthAvroConverter.kt index 51143c31..288aad90 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepClassicGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepClassicGoogleHealthAvroConverter.kt @@ -19,8 +19,8 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.sleepClassic -import org.radarcns.connector.fitbit.FitbitSleepClassicLevel +import org.radarbase.googlehealth.util.googleHealthSleepClassic +import org.radarcns.push.googlehealth.GoogleHealthSleepClassicLevel import java.time.Instant import java.time.LocalDateTime import java.time.ZoneOffset @@ -42,22 +42,24 @@ class SleepClassicGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroCon ?.let { runCatching { Instant.parse(it) }.getOrNull() } ?: return@mapNotNull null val end = stage["endTime"]?.asText() ?.let { runCatching { Instant.parse(it) }.getOrNull() } ?: return@mapNotNull null - val record = sleepClassic { - dateTime = LOCAL_FMT.format(LocalDateTime.ofInstant(start, ZoneOffset.UTC)) + // Render in the stage's own UTC offset so dateTime is the device's local wall clock + // (like Fitbit), not UTC. Google derives its civil fields the same way (physical + offset). + val startZone = ZoneOffset.ofTotalSeconds(parseUtcOffsetSeconds(stage["startUtcOffset"]?.asText())) + val record = googleHealthSleepClassic { + dateTime = LOCAL_FMT.format(LocalDateTime.ofInstant(start, startZone)) this.timeReceived = timeReceived duration = (end.epochSecond - start.epochSecond).toInt().coerceAtLeast(0) level = mapLevel(stageType) - efficiency = null } user.observationKey to record } } - private fun mapLevel(text: String?): FitbitSleepClassicLevel = when (text) { - "ASLEEP" -> FitbitSleepClassicLevel.ASLEEP - "RESTLESS" -> FitbitSleepClassicLevel.RESTLESS - "AWAKE" -> FitbitSleepClassicLevel.AWAKE - else -> FitbitSleepClassicLevel.UNKNOWN + private fun mapLevel(text: String?): GoogleHealthSleepClassicLevel = when (text) { + "ASLEEP" -> GoogleHealthSleepClassicLevel.ASLEEP + "RESTLESS" -> GoogleHealthSleepClassicLevel.RESTLESS + "AWAKE" -> GoogleHealthSleepClassicLevel.AWAKE + else -> GoogleHealthSleepClassicLevel.UNKNOWN } companion object { diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepStageGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepStageGoogleHealthAvroConverter.kt index a6fffddc..1161b77b 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepStageGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/SleepStageGoogleHealthAvroConverter.kt @@ -19,8 +19,8 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.sleepStage -import org.radarcns.connector.fitbit.FitbitSleepStageLevel +import org.radarbase.googlehealth.util.googleHealthSleepStage +import org.radarcns.push.googlehealth.GoogleHealthSleepStageLevel import java.time.Instant import java.time.LocalDateTime import java.time.ZoneOffset @@ -42,23 +42,24 @@ class SleepStageGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConve ?.let { runCatching { Instant.parse(it) }.getOrNull() } ?: return@mapNotNull null val end = stage["endTime"]?.asText() ?.let { runCatching { Instant.parse(it) }.getOrNull() } ?: return@mapNotNull null - val record = sleepStage { - dateTime = LOCAL_FMT.format(LocalDateTime.ofInstant(start, ZoneOffset.UTC)) + + val startZone = ZoneOffset.ofTotalSeconds(parseUtcOffsetSeconds(stage["startUtcOffset"]?.asText())) + val record = googleHealthSleepStage { + dateTime = LOCAL_FMT.format(LocalDateTime.ofInstant(start, startZone)) this.timeReceived = timeReceived duration = (end.epochSecond - start.epochSecond).toInt().coerceAtLeast(0) level = mapLevel(stageType) - efficiency = null } user.observationKey to record } } - private fun mapLevel(text: String?): FitbitSleepStageLevel = when (text) { - "DEEP" -> FitbitSleepStageLevel.DEEP - "LIGHT" -> FitbitSleepStageLevel.LIGHT - "REM" -> FitbitSleepStageLevel.REM - "AWAKE" -> FitbitSleepStageLevel.AWAKE - else -> FitbitSleepStageLevel.UNKNOWN + private fun mapLevel(text: String?): GoogleHealthSleepStageLevel = when (text) { + "DEEP" -> GoogleHealthSleepStageLevel.DEEP + "LIGHT" -> GoogleHealthSleepStageLevel.LIGHT + "REM" -> GoogleHealthSleepStageLevel.REM + "AWAKE" -> GoogleHealthSleepStageLevel.AWAKE + else -> GoogleHealthSleepStageLevel.UNKNOWN } companion object { diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/StepsGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/StepsGoogleHealthAvroConverter.kt index 97c5a185..39f4c311 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/StepsGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/StepsGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.intradaySteps +import org.radarbase.googlehealth.util.googleHealthSteps class StepsGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { override fun convertDataPoint( @@ -29,7 +29,7 @@ class StepsGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter( val data = point["steps"] ?: return emptyList() val (start, end) = parseInterval(data) ?: return emptyList() val count = data["count"]?.asInt() ?: return emptyList() - val record = intradaySteps { + val record = googleHealthSteps { time = epochSeconds(start) timeReceived = nowEpochSeconds() timeInterval = (end.epochSecond - start.epochSecond).toInt().coerceAtLeast(0) diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/TotalCaloriesGoogleHealthAvroConverter.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/TotalCaloriesGoogleHealthAvroConverter.kt index ee7dcb2f..1d3eacc4 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/TotalCaloriesGoogleHealthAvroConverter.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/converter/TotalCaloriesGoogleHealthAvroConverter.kt @@ -19,7 +19,7 @@ package org.radarbase.googlehealth.converter import com.fasterxml.jackson.databind.JsonNode import org.apache.avro.specific.SpecificRecord import org.radarbase.googlehealth.user.User -import org.radarbase.googlehealth.util.intradayCalories +import org.radarbase.googlehealth.util.googleHealthTotalCalories import java.time.Instant class TotalCaloriesGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroConverter(topic) { @@ -30,13 +30,11 @@ class TotalCaloriesGoogleHealthAvroConverter(topic: String) : GoogleHealthAvroCo val start = point["startTime"]?.asText()?.let(Instant::parse) ?: return emptyList() val end = point["endTime"]?.asText()?.let(Instant::parse) ?: return emptyList() val kilocalories = point["totalCalories"]?.get("kcalSum")?.doubleValue() ?: return emptyList() - val record = intradayCalories { + val record = googleHealthTotalCalories { time = epochSeconds(start) timeReceived = nowEpochSeconds() timeInterval = (end.epochSecond - start.epochSecond).toInt().coerceAtLeast(0) calories = kilocalories - level = 0 - mets = 0.0 } return listOf(user.observationKey to record) } diff --git a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/util/AvroBuilders.kt b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/util/AvroBuilders.kt index 49884887..370e6d67 100644 --- a/google-health-library/src/main/kotlin/org/radarbase/googlehealth/util/AvroBuilders.kt +++ b/google-health-library/src/main/kotlin/org/radarbase/googlehealth/util/AvroBuilders.kt @@ -1,50 +1,50 @@ package org.radarbase.googlehealth.util -import org.radarcns.connector.fitbit.FitbitActivityHeartRate -import org.radarcns.connector.fitbit.FitbitActivityLogRecord -import org.radarcns.connector.fitbit.FitbitBreathingRate -import org.radarcns.connector.fitbit.FitbitIntradayCalories -import org.radarcns.connector.fitbit.FitbitIntradayHeartRate -import org.radarcns.connector.fitbit.FitbitIntradayHeartRateVariability -import org.radarcns.connector.fitbit.FitbitIntradaySpo2 -import org.radarcns.connector.fitbit.FitbitIntradaySteps -import org.radarcns.connector.fitbit.FitbitRestingHeartRate -import org.radarcns.connector.fitbit.FitbitSkinTemperature -import org.radarcns.connector.fitbit.FitbitSleepClassic -import org.radarcns.connector.fitbit.FitbitSleepStage +import org.radarcns.push.googlehealth.GoogleHealthExerciseHeartRate +import org.radarcns.push.googlehealth.GoogleHealthExercise +import org.radarcns.push.googlehealth.GoogleHealthRespiratoryRateSleepSummary +import org.radarcns.push.googlehealth.GoogleHealthTotalCalories +import org.radarcns.push.googlehealth.GoogleHealthHeartRate +import org.radarcns.push.googlehealth.GoogleHealthHeartRateVariability +import org.radarcns.push.googlehealth.GoogleHealthOxygenSaturation +import org.radarcns.push.googlehealth.GoogleHealthSteps +import org.radarcns.push.googlehealth.GoogleHealthDailyRestingHeartRate +import org.radarcns.push.googlehealth.GoogleHealthDailySleepTemperatureDerivations +import org.radarcns.push.googlehealth.GoogleHealthSleepClassic +import org.radarcns.push.googlehealth.GoogleHealthSleepStage -inline fun intradaySteps(block: FitbitIntradaySteps.Builder.() -> Unit): FitbitIntradaySteps = - FitbitIntradaySteps.newBuilder().apply(block).build() +inline fun googleHealthSteps(block: GoogleHealthSteps.Builder.() -> Unit): GoogleHealthSteps = + GoogleHealthSteps.newBuilder().apply(block).build() -inline fun intradayHeartRate(block: FitbitIntradayHeartRate.Builder.() -> Unit): FitbitIntradayHeartRate = - FitbitIntradayHeartRate.newBuilder().apply(block).build() +inline fun googleHealthHeartRate(block: GoogleHealthHeartRate.Builder.() -> Unit): GoogleHealthHeartRate = + GoogleHealthHeartRate.newBuilder().apply(block).build() -inline fun intradayHeartRateVariability(block: FitbitIntradayHeartRateVariability.Builder.() -> Unit): FitbitIntradayHeartRateVariability = - FitbitIntradayHeartRateVariability.newBuilder().apply(block).build() +inline fun googleHealthHeartRateVariability(block: GoogleHealthHeartRateVariability.Builder.() -> Unit): GoogleHealthHeartRateVariability = + GoogleHealthHeartRateVariability.newBuilder().apply(block).build() -inline fun intradaySpo2(block: FitbitIntradaySpo2.Builder.() -> Unit): FitbitIntradaySpo2 = - FitbitIntradaySpo2.newBuilder().apply(block).build() +inline fun googleHealthOxygenSaturation(block: GoogleHealthOxygenSaturation.Builder.() -> Unit): GoogleHealthOxygenSaturation = + GoogleHealthOxygenSaturation.newBuilder().apply(block).build() -inline fun restingHeartRate(block: FitbitRestingHeartRate.Builder.() -> Unit): FitbitRestingHeartRate = - FitbitRestingHeartRate.newBuilder().apply(block).build() +inline fun googleHealthDailyRestingHeartRate(block: GoogleHealthDailyRestingHeartRate.Builder.() -> Unit): GoogleHealthDailyRestingHeartRate = + GoogleHealthDailyRestingHeartRate.newBuilder().apply(block).build() -inline fun breathingRate(block: FitbitBreathingRate.Builder.() -> Unit): FitbitBreathingRate = - FitbitBreathingRate.newBuilder().apply(block).build() +inline fun googleHealthRespiratoryRateSleepSummary(block: GoogleHealthRespiratoryRateSleepSummary.Builder.() -> Unit): GoogleHealthRespiratoryRateSleepSummary = + GoogleHealthRespiratoryRateSleepSummary.newBuilder().apply(block).build() -inline fun skinTemperature(block: FitbitSkinTemperature.Builder.() -> Unit): FitbitSkinTemperature = - FitbitSkinTemperature.newBuilder().apply(block).build() +inline fun googleHealthDailySleepTemperatureDerivations(block: GoogleHealthDailySleepTemperatureDerivations.Builder.() -> Unit): GoogleHealthDailySleepTemperatureDerivations = + GoogleHealthDailySleepTemperatureDerivations.newBuilder().apply(block).build() -inline fun sleepClassic(block: FitbitSleepClassic.Builder.() -> Unit): FitbitSleepClassic = - FitbitSleepClassic.newBuilder().apply(block).build() +inline fun googleHealthSleepClassic(block: GoogleHealthSleepClassic.Builder.() -> Unit): GoogleHealthSleepClassic = + GoogleHealthSleepClassic.newBuilder().apply(block).build() -inline fun sleepStage(block: FitbitSleepStage.Builder.() -> Unit): FitbitSleepStage = - FitbitSleepStage.newBuilder().apply(block).build() +inline fun googleHealthSleepStage(block: GoogleHealthSleepStage.Builder.() -> Unit): GoogleHealthSleepStage = + GoogleHealthSleepStage.newBuilder().apply(block).build() -inline fun activityLogRecord(block: FitbitActivityLogRecord.Builder.() -> Unit): FitbitActivityLogRecord = - FitbitActivityLogRecord.newBuilder().apply(block).build() +inline fun activityLogRecord(block: GoogleHealthExercise.Builder.() -> Unit): GoogleHealthExercise = + GoogleHealthExercise.newBuilder().apply(block).build() -inline fun activityHeartRate(block: FitbitActivityHeartRate.Builder.() -> Unit): FitbitActivityHeartRate = - FitbitActivityHeartRate.newBuilder().apply(block).build() +inline fun exerciseHeartRate(block: GoogleHealthExerciseHeartRate.Builder.() -> Unit): GoogleHealthExerciseHeartRate = + GoogleHealthExerciseHeartRate.newBuilder().apply(block).build() -inline fun intradayCalories(block: FitbitIntradayCalories.Builder.() -> Unit): FitbitIntradayCalories = - FitbitIntradayCalories.newBuilder().apply(block).build() +inline fun googleHealthTotalCalories(block: GoogleHealthTotalCalories.Builder.() -> Unit): GoogleHealthTotalCalories = + GoogleHealthTotalCalories.newBuilder().apply(block).build()