2024-01-10 18:54:00 +01:00
|
|
|
/* Copyright (C) 2019-2024 José Rebelo, Petr Vaněk, Q-er
|
2019-11-23 21:52:46 +01:00
|
|
|
|
|
|
|
This file is part of Gadgetbridge.
|
|
|
|
|
|
|
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Affero General Public License as published
|
|
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Gadgetbridge is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
2024-01-10 18:54:00 +01:00
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
2019-09-17 00:47:10 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Date;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
|
|
|
|
|
|
|
public class SleepAnalysis {
|
|
|
|
|
|
|
|
public static final long MIN_SESSION_LENGTH = 5 * 60;
|
|
|
|
public static final long MAX_WAKE_PHASE_LENGTH = 2 * 60 * 60;
|
|
|
|
|
|
|
|
public List<SleepSession> calculateSleepSessions(List<? extends ActivitySample> samples) {
|
|
|
|
List<SleepSession> result = new ArrayList<>();
|
|
|
|
|
|
|
|
ActivitySample previousSample = null;
|
|
|
|
Date sleepStart = null;
|
|
|
|
Date sleepEnd = null;
|
|
|
|
long lightSleepDuration = 0;
|
|
|
|
long deepSleepDuration = 0;
|
2022-08-24 12:21:59 +02:00
|
|
|
long remSleepDuration = 0;
|
2019-09-17 00:47:10 +02:00
|
|
|
long durationSinceLastSleep = 0;
|
|
|
|
|
|
|
|
for (ActivitySample sample : samples) {
|
|
|
|
if (isSleep(sample)) {
|
|
|
|
if (sleepStart == null)
|
|
|
|
sleepStart = getDateFromSample(sample);
|
|
|
|
sleepEnd = getDateFromSample(sample);
|
|
|
|
|
|
|
|
durationSinceLastSleep = 0;
|
2021-09-17 17:58:40 +02:00
|
|
|
} else {
|
|
|
|
//exclude "not worn" times from sleep sessions as this makes a discrepancy with the charts
|
2022-08-24 12:21:59 +02:00
|
|
|
if (lightSleepDuration + deepSleepDuration + remSleepDuration > MIN_SESSION_LENGTH)
|
|
|
|
result.add(new SleepSession(sleepStart, sleepEnd, lightSleepDuration, deepSleepDuration, remSleepDuration));
|
2021-09-17 17:58:40 +02:00
|
|
|
sleepStart = null;
|
|
|
|
sleepEnd = null;
|
|
|
|
lightSleepDuration = 0;
|
|
|
|
deepSleepDuration = 0;
|
2022-08-24 12:21:59 +02:00
|
|
|
remSleepDuration = 0;
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (previousSample != null) {
|
|
|
|
long durationSinceLastSample = sample.getTimestamp() - previousSample.getTimestamp();
|
|
|
|
if (sample.getKind() == ActivityKind.TYPE_LIGHT_SLEEP) {
|
|
|
|
lightSleepDuration += durationSinceLastSample;
|
|
|
|
} else if (sample.getKind() == ActivityKind.TYPE_DEEP_SLEEP) {
|
|
|
|
deepSleepDuration += durationSinceLastSample;
|
2022-08-24 12:21:59 +02:00
|
|
|
} else if (sample.getKind() == ActivityKind.TYPE_REM_SLEEP) {
|
|
|
|
remSleepDuration += durationSinceLastSample;
|
2019-09-17 00:47:10 +02:00
|
|
|
} else {
|
|
|
|
durationSinceLastSleep += durationSinceLastSample;
|
|
|
|
if (sleepStart != null && durationSinceLastSleep > MAX_WAKE_PHASE_LENGTH) {
|
2022-08-24 12:21:59 +02:00
|
|
|
if (lightSleepDuration + deepSleepDuration + remSleepDuration > MIN_SESSION_LENGTH)
|
|
|
|
result.add(new SleepSession(sleepStart, sleepEnd, lightSleepDuration, deepSleepDuration, remSleepDuration));
|
2019-09-17 00:47:10 +02:00
|
|
|
sleepStart = null;
|
|
|
|
sleepEnd = null;
|
|
|
|
lightSleepDuration = 0;
|
|
|
|
deepSleepDuration = 0;
|
2022-08-24 12:21:59 +02:00
|
|
|
remSleepDuration = 0;
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
previousSample = sample;
|
|
|
|
}
|
2022-08-24 12:21:59 +02:00
|
|
|
if (lightSleepDuration + deepSleepDuration + remSleepDuration > MIN_SESSION_LENGTH) {
|
|
|
|
result.add(new SleepSession(sleepStart, sleepEnd, lightSleepDuration, deepSleepDuration, remSleepDuration));
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isSleep(ActivitySample sample) {
|
2022-08-24 12:21:59 +02:00
|
|
|
return sample.getKind() == ActivityKind.TYPE_DEEP_SLEEP ||
|
|
|
|
sample.getKind() == ActivityKind.TYPE_LIGHT_SLEEP ||
|
|
|
|
sample.getKind() == ActivityKind.TYPE_REM_SLEEP;
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private Date getDateFromSample(ActivitySample sample) {
|
|
|
|
return new Date(sample.getTimestamp() * 1000L);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static class SleepSession {
|
|
|
|
private final Date sleepStart;
|
|
|
|
private final Date sleepEnd;
|
|
|
|
private final long lightSleepDuration;
|
|
|
|
private final long deepSleepDuration;
|
2022-08-24 12:21:59 +02:00
|
|
|
private final long remSleepDuration;
|
2019-09-17 00:47:10 +02:00
|
|
|
|
|
|
|
private SleepSession(Date sleepStart,
|
|
|
|
Date sleepEnd,
|
|
|
|
long lightSleepDuration,
|
2022-08-24 12:21:59 +02:00
|
|
|
long deepSleepDuration,
|
|
|
|
long remSleepDuration) {
|
2019-09-17 00:47:10 +02:00
|
|
|
this.sleepStart = sleepStart;
|
|
|
|
this.sleepEnd = sleepEnd;
|
|
|
|
this.lightSleepDuration = lightSleepDuration;
|
|
|
|
this.deepSleepDuration = deepSleepDuration;
|
2022-08-24 12:21:59 +02:00
|
|
|
this.remSleepDuration = remSleepDuration;
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public Date getSleepStart() {
|
|
|
|
return sleepStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Date getSleepEnd() {
|
|
|
|
return sleepEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getLightSleepDuration() {
|
|
|
|
return lightSleepDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getDeepSleepDuration() {
|
|
|
|
return deepSleepDuration;
|
|
|
|
}
|
2022-08-24 12:21:59 +02:00
|
|
|
|
|
|
|
public long getRemSleepDuration() {
|
|
|
|
return remSleepDuration;
|
|
|
|
}
|
2019-09-17 00:47:10 +02:00
|
|
|
}
|
|
|
|
}
|