Реализация трекинга сна через мобильное приложение
Трекинг сна на телефоне без носимого — это акселерометр под подушкой или матрасом. С носимым — ЧСС + акселерометр для классификации фаз. Оба подхода работают, но имеют принципиально разные точности и технические сложности.
Без носимого: акселерометр как датчик движения
Классика — телефон кладут рядом на матрас. Движения тела во сне передаются через матрас к телефону. Задача: классифицировать периоды движения (беспокойный сон, пробуждения) и покоя (глубокий/лёгкий сон).
Алгоритм:
- Записываем акселерометр на 10 Гц (батарейно-оптимально, достаточно для детекции движений тела)
- Каждые 30 секунд — эпоха: считаем
activity_count = sum(|delta_x| + |delta_y| + |delta_z|)за эпоху - Классификация:
activity_count < threshold → SLEEP, > threshold → WAKE - Паттерны из N эпох → определяем начало и конец сна
Порог активности подбирается эмпирически — зависит от расположения телефона, жёсткости матраса. Поэтому первые 3–7 ночей — калибровка через feedback («я заснул в 23:15, данные верны?»).
Точность определения фаз сна (REM/N1/N2/N3) — ниже 60% без ЧСС. Только движения — это грубое деление на «спокойный/беспокойный». Если продукт претендует на медицинский класс — нужен носимый датчик.
С носимым: HealthKit Sleep / Health Connect Sleep
iOS + Apple Watch:
Apple Watch автоматически записывает сон через собственные алгоритмы (акселерометр + ЧСС + кожная температура на Series 8+). Результат — в HealthKit как HKCategoryValueSleepAnalysis:
let sleepType = HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!
let query = HKSampleQuery(
sampleType: sleepType,
predicate: HKQuery.predicateForSamples(withStart: startDate, end: endDate),
limit: HKObjectQueryNoLimit,
sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true)]
) { _, samples, _ in
guard let samples = samples as? [HKCategorySample] else { return }
samples.forEach { sample in
switch sample.value {
case HKCategoryValueSleepAnalysis.asleepCore.rawValue:
// N1/N2 — лёгкий сон (watchOS 9+)
case HKCategoryValueSleepAnalysis.asleepDeep.rawValue:
// N3 — глубокий сон
case HKCategoryValueSleepAnalysis.asleepREM.rawValue:
// REM
case HKCategoryValueSleepAnalysis.awake.rawValue:
// Пробуждение
default: break
}
}
}
До watchOS 9 была только inBed и asleep — без фаз. Если приложение должно показывать фазы сна от Apple Watch — минимум iOS 16 / watchOS 9.
Android + Health Connect:
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = SleepSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
response.records.forEach { session ->
val duration = Duration.between(session.startTime, session.endTime)
session.stages.forEach { stage ->
when (stage.stage) {
SleepSessionRecord.STAGE_TYPE_DEEP -> { /* глубокий */ }
SleepSessionRecord.STAGE_TYPE_REM -> { /* REM */ }
SleepSessionRecord.STAGE_TYPE_LIGHT -> { /* лёгкий */ }
SleepSessionRecord.STAGE_TYPE_AWAKE -> { /* пробуждение */ }
}
}
}
Запись сна (собственные данные)
Если приложение само анализирует сон (через акселерометр телефона):
iOS — запись в HealthKit:
let sleepSample = HKCategorySample(
type: HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!,
value: HKCategoryValueSleepAnalysis.asleepCore.rawValue,
start: phaseStart,
end: phaseEnd
)
healthStore.save(sleepSample) { success, error in }
Умный будильник
Фишка большинства трекеров сна — будить в «лёгкую» фазу в пределах окна (например, ±30 мин от желаемого времени). Реализация на телефоне: приложение активно в фоне, анализирует акселерометр, при обнаружении активности в окне будильника — срабатывает через UNUserNotificationCenter (iOS) или AlarmManager.setAlarmClock() (Android).
AlarmManager.setAlarmClock() — единственный будильник на Android, который гарантированно срабатывает при строгом режиме экономии батареи (Doze mode). Обычные setExact() и setAlarmClock() могут задержаться на несколько минут.
Типичные ошибки
- Не учитывать разрыв сна (человек встал ночью на 20 минут) — алгоритм разбивает одну сессию на две
- Забыть про летнее/зимнее время — временные метки в UTC, перевод в локальное время только для отображения
- Не фильтровать «сон» продолжительностью < 30 минут — дневной отдых или ошибки классификации попадают в статистику
Сроки
Базовый трекер с акселерометром и будильником — 3–5 недель. С интеграцией HealthKit/Health Connect, фазами сна и аналитикой за период — 6–10 недель.







