Реалізація трекінгу сну через мобільне приложення
Трекінг сну на телефоні без носимого — це акселерометр під подушкою або матрацом. З носимим — ЧСС + акселерометр для класифікації фаз. Обидва підходи працюють, але мають принципово різні точності та технічні складності.
Без носимого: акселерометр як датчик руху
Класика — телефон кладуть рядом на матрац. Рухи тіла під час сну передаються через матрац до телефону. Завдання: класифікувати періоди руху (неспокійний сон, пробудження) та спокою (глибокий/легкий сон).
Алгоритм:
- Записуємо акселерометр на 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 тижнів.







