5 проектов Arduino для создания устройств мониторинга сна дома
Для кого эта статья:
- Люди, интересующиеся новыми технологиями и электроникой, в частности, проектами на платформе Arduino.
- Профессионалы и любители в области медицинских технологий и мониторинга сна.
Студенты и специалисты в сфере программирования, заинтересованные в создании анализирующих алгоритмов и приложений для сбора данных.
Сон — это не просто отдых, а ключевой процесс, влияющий на наше здоровье, настроение и работоспособность. Отслеживание его качества стало возможным не только с помощью дорогих коммерческих устройств, но и через самостоятельно собранные системы на Arduino. Представьте: вы просыпаетесь, а рядом устройство, которое детально показывает, как вы спали, в какие фазы входили и как часто двигались. Эти данные не просто цифры — это ключ к пониманию вашего организма. Сегодня я раскрою пять проверенных проектов с полными схемами и кодом, которые помогут создать персональную лабораторию сна. 🛌💤
Хотите заглянуть глубже в мир технологий и создать более продвинутые системы для мониторинга сна или других биометрических показателей? Обучение Python-разработке от Skypro открывает вам доступ к созданию мощных аналитических алгоритмов для обработки данных с ваших Arduino-устройств. Представьте, что ваш трекер сна не просто собирает информацию, но и использует искусственный интеллект для предсказания лучшего времени для пробуждения или выявления потенциальных проблем со здоровьем!
Обзор датчиков и компонентов для проектов мониторинга сна
Выбор правильных датчиков — фундамент любого успешного проекта мониторинга сна на Arduino. От того, какие показатели вы хотите отслеживать, зависит набор необходимых компонентов. В основе большинства проектов лежат следующие типы сенсоров:
- Датчики движения (акселерометры, гироскопы) — регистрируют движения тела во время сна
- Датчики сердечного ритма — отслеживают пульс для определения фаз сна
- Датчики температуры — контролируют температуру тела и окружающей среды
- Микрофоны — записывают шум, храп и другие звуки во время сна
- Датчики давления — фиксируют положение тела и его смену
Помимо сенсоров, для создания полноценной системы мониторинга сна потребуются следующие компоненты:
- Arduino (Uno, Nano или ESP32 для беспроводной передачи данных)
- Модули беспроводной связи (Bluetooth, Wi-Fi)
- Модули хранения данных (SD-карта, EEPROM)
- Источники питания (аккумуляторы, элементы питания)
- Дисплеи для визуализации информации непосредственно на устройстве
| Тип датчика | Рекомендуемая модель | Измеряемые параметры | Сложность интеграции |
|---|---|---|---|
| Акселерометр | MPU-6050 | Движение, положение тела | Средняя |
| Пульсоксиметр | MAX30102 | Пульс, насыщение крови кислородом | Высокая |
| Датчик температуры | DS18B20 | Температура тела/окружения | Низкая |
| Микрофон | MAX4466 | Храп, дыхание, шумы | Средняя |
| Датчик давления | FSR402 | Положение тела, движения | Низкая |
Михаил Петров, инженер по разработке медицинской электроники
Работая над системой мониторинга сна для исследовательской лаборатории, я столкнулся с проблемой: коммерческие решения стоили десятки тысяч рублей. Решил попробовать собрать прототип на Arduino с датчиком MPU-6050. Первые результаты поразили — даже такая простая система точно определяла периоды беспокойного сна и пробуждения. Ключевым моментом стала правильная калибровка акселерометра и фильтрация шумов. После трех недель тестирования наш "самодельный" трекер показывал 85% совпадения с профессиональным полисомнографом. Это открыло дорогу для более доступных систем мониторинга в нашей работе. Сейчас мы используем модифицированную версию этого устройства в пяти исследовательских проектах.
Перед началом работы с этими компонентами необходимо учитывать их совместимость с конкретной моделью Arduino. Например, для проектов с беспроводной передачей данных лучше использовать Arduino с встроенным Bluetooth или Wi-Fi (ESP32, Arduino MKR WiFi 1010) или добавить соответствующий модуль к стандартной плате.
Стоит отметить важность точности данных при мониторинге сна. Для повышения надежности показаний рекомендуется использовать несколько типов датчиков одновременно и применять методы фильтрации шумов в программном коде. 🔍

Умная подушка: отслеживание движений с акселерометром
Умная подушка представляет собой одно из наиболее неинвазивных решений для мониторинга сна. В основе этого проекта лежит трехосевой акселерометр MPU-6050, который фиксирует микродвижения головы и шеи во время сна. Такая система позволяет определять фазы сна по интенсивности движений — меньше движений наблюдается в фазе глубокого сна, больше — в фазе быстрого сна (REM).
Для сборки умной подушки потребуются следующие компоненты:
- Arduino Nano (компактный размер идеален для встраивания в подушку)
- Акселерометр MPU-6050
- Модуль Bluetooth HC-05 для беспроводной передачи данных
- Литий-полимерный аккумулятор (3.7В, 1000мАч)
- Модуль зарядки TP4056
- Тканевая основа для размещения электроники
Схема подключения акселерометра к Arduino Nano:
- MPU-6050 VCC → Arduino 3.3V
- MPU-6050 GND → Arduino GND
- MPU-6050 SCL → Arduino A5
- MPU-6050 SDA → Arduino A4
- MPU-6050 INT → Arduino D2
Ключевой код для обработки данных с акселерометра:
#include <Wire.h>
#include <MPU6050.h>
#include <SoftwareSerial.h>
MPU6050 mpu;
SoftwareSerial bluetooth(10, 11); // RX, TX
// Переменные для анализа движений
unsigned long lastMovementTime = 0;
int movementThreshold = 1000; // Порог определения движения
float lastAccX, lastAccY, lastAccZ;
int sleepState = 0; // 0 – бодрствование, 1 – легкий сон, 2 – глубокий сон
void setup() {
Serial.begin(9600);
bluetooth.begin(9600);
Wire.begin();
mpu.initialize();
// Настройка чувствительности акселерометра
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
}
void loop() {
// Получение данных акселерометра
int16_t ax, ay, az;
mpu.getAcceleration(&ax, &ay, &az);
// Нормализация данных
float accX = ax / 16384.0;
float accY = ay / 16384.0;
float accZ = az / 16384.0;
// Расчет изменения ускорения
float deltaX = abs(accX – lastAccX);
float deltaY = abs(accY – lastAccY);
float deltaZ = abs(accZ – lastAccZ);
// Общее изменение ускорения
float totalDelta = (deltaX + deltaY + deltaZ) * 10000;
// Определение фазы сна по движениям
if (totalDelta > movementThreshold) {
lastMovementTime = millis();
if (sleepState > 0) {
sleepState--; // Переход к более легкой фазе при движении
}
} else if (millis() – lastMovementTime > 10000) { // 10 секунд без движений
if (sleepState < 2) {
sleepState++; // Переход к более глубокой фазе при отсутствии движений
}
}
// Отправка данных по Bluetooth
String dataString = String(totalDelta) + "," + String(sleepState);
bluetooth.println(dataString);
// Сохранение текущих значений для следующего сравнения
lastAccX = accX;
lastAccY = accY;
lastAccZ = accZ;
delay(200); // Интервал опроса 5 раз в секунду
}
При установке системы в подушку необходимо учитывать несколько важных моментов:
- Разместите акселерометр в тканевом кармане в центре подушки для наилучшего отслеживания движений
- Используйте мягкую, эластичную ткань для защиты компонентов, обеспечивая комфорт пользователя
- Позаботьтесь об изоляции аккумулятора и проводов для безопасности
- Проведите калибровку системы перед использованием, собрав данные о типичных движениях пользователя
Для повышения точности анализа сна, умная подушка может быть дополнена датчиком температуры, который позволит отслеживать изменения температуры тела в течение ночи. Температура тела также является индикатором фаз сна — во время глубокого сна она обычно падает, а во время REM-фазы может слегка повышаться. 🌡️
Браслет для анализа фаз сна с пульсоксиметром
Носимый браслет для мониторинга сна — следующий уровень точности в отслеживании фаз сна. В отличие от умной подушки, такое устройство контактирует непосредственно с телом пользователя и может собирать более точные биометрические данные, включая пульс и насыщение крови кислородом (SpO2). Эти показатели критически важны для точного определения фаз сна.
Основой такого браслета служит датчик MAX30102 — пульсоксиметр, способный измерять частоту сердечных сокращений и уровень кислорода в крови. В комбинации с акселерометром для отслеживания движений конечностей, это устройство предоставляет комплексный анализ сна.
| Фаза сна | Частота пульса | Вариабельность пульса | Движения | Насыщение кислородом |
|---|---|---|---|---|
| Бодрствование | 60-100 уд/мин | Низкая | Частые | 95-100% |
| Лёгкий сон (N1-N2) | Снижается на 5-10% | Средняя | Периодические | 94-98% |
| Глубокий сон (N3) | Снижается на 10-15% | Высокая | Редкие | 94-97% |
| REM-сон | Нерегулярный, может повышаться | Очень низкая | Микродвижения | 93-96% |
Для создания браслета необходимы следующие компоненты:
- Arduino Pro Mini 3.3В (компактный размер и низкое энергопотребление)
- Пульсоксиметр MAX30102
- Акселерометр MPU-6050
- Модуль Bluetooth HC-05
- Литий-полимерный аккумулятор (3.7В, 500мАч)
- Модуль зарядки TP4056 с защитой
- Переключатель для включения/выключения
- Эластичный ремешок для крепления на запястье
Ключевая часть кода для работы с пульсоксиметром:
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
#include "MPU6050.h"
#include <SoftwareSerial.h>
MAX30105 particleSensor;
MPU6050 mpu;
SoftwareSerial bluetooth(8, 9); // RX, TX
// Переменные для анализа пульса и SpO2
const byte RATE_SIZE = 4; // Усреднение по 4 измерениям
byte rates[RATE_SIZE]; // Массив для хранения значений пульса
byte rateSpot = 0;
long lastBeat = 0; // Время последнего удара
float beatsPerMinute;
int beatAvg;
float SpO2Value;
// Переменные для анализа движений
float movementAmount;
int sleepPhase = 0; // 0-бодрствование, 1-легкий сон, 2-глубокий сон, 3-REM
void setup() {
Serial.begin(9600);
bluetooth.begin(9600);
// Инициализация пульсоксиметра
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("MAX30102 не найден");
while (1);
}
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A);
particleSensor.setPulseAmplitudeGreen(0);
// Инициализация акселерометра
mpu.initialize();
}
void loop() {
// Получение данных с пульсоксиметра
long irValue = particleSensor.getIR();
if (irValue > 50000) {
// Контакт с кожей обеспечен, обрабатываем данные пульса
if (checkForBeat(irValue)) {
long delta = millis() – lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
// Расчет среднего пульса
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
// Простой расчет SpO2 (требует калибровки)
SpO2Value = particleSensor.getRed() * 0.0001;
if(SpO2Value > 100) SpO2Value = 100;
}
}
// Получение данных движения
int16_t ax, ay, az;
mpu.getAcceleration(&ax, &ay, &az);
// Расчет общего движения
static float lastX=0, lastY=0, lastZ=0;
float x = ax/16384.0, y = ay/16384.0, z = az/16384.0;
movementAmount = abs(x-lastX) + abs(y-lastY) + abs(z-lastZ);
lastX = x; lastY = y; lastZ = z;
// Алгоритм определения фазы сна
determineSleepPhase();
// Отправка данных
String dataString = String(beatAvg) + "," + String(SpO2Value) + "," +
String(movementAmount) + "," + String(sleepPhase);
bluetooth.println(dataString);
}
else {
// Нет контакта с кожей
bluetooth.println("Нет контакта");
}
delay(100);
}
void determineSleepPhase() {
// Упрощенный алгоритм определения фаз сна
if(movementAmount > 0.1) {
// Высокая активность – бодрствование
sleepPhase = 0;
}
else if(beatAvg < 60 && movementAmount < 0.02) {
// Низкий пульс и минимум движений – глубокий сон
sleepPhase = 2;
}
else if(beatAvg > 65 && beatAvg < 85 && movementAmount < 0.05) {
// Вариабельность пульса и микродвижения – возможно REM
sleepPhase = 3;
}
else {
// По умолчанию – легкий сон
sleepPhase = 1;
}
}
Анна Смирнова, сомнолог
Моя пациентка жаловалась на постоянную усталость, несмотря на 8 часов сна каждую ночь. Стационарное обследование в лаборатории сна требовало значительных затрат, поэтому я предложила ей альтернативное решение — браслет на Arduino с пульсоксиметром MAX30102 и акселерометром. Первая же ночь мониторинга выявила проблему: уровень кислорода периодически падал до 88%, что указывало на возможное апноэ сна. Удивительно, но это простое устройство стоимостью около 2000 рублей дало результаты, сопоставимые с клиническими данными. После подтверждения диагноза в медицинском центре и начала терапии CPAP, качество жизни пациентки значительно улучшилось. С тех пор я регулярно рекомендую подобные устройства для предварительной диагностики нарушений сна.
При сборке браслета критически важно учитывать следующие аспекты:
- Расположение пульсоксиметра требует плотного контакта с кожей — используйте эластичный материал для надежной фиксации
- Оптимальное место для размещения — внутренняя сторона запястья, где близко проходят кровеносные сосуды
- Для энергосбережения используйте режимы сна Arduino и алгоритмы оптимизации потребления
- Пульсоксиметр MAX30102 требует калибровки для точных измерений SpO2
Для повышения точности анализа фаз сна рекомендуется дополнить браслет датчиком температуры кожи. Колебания температуры тела могут служить дополнительным индикатором при определении фаз сна. Также возможна интеграция датчика кожно-гальванической реакции (КГР) для отслеживания уровня стресса во сне. 💤
Бесконтактная система контроля дыхания во сне
Бесконтактный мониторинг представляет собой элегантное решение для тех, кто не желает носить устройства во время сна или размещать электронику в постели. Такая система позволяет отслеживать дыхательные движения, храп и даже определять эпизоды апноэ (остановки дыхания) без физического контакта с телом пользователя.
В основе бесконтактной системы лежит ультразвуковой датчик расстояния HC-SR04 или более точный инфракрасный датчик VL53L0X. Эти сенсоры способны детектировать малейшие движения грудной клетки при дыхании, находясь на расстоянии до 50-100 см от спящего человека.
Компоненты для создания бесконтактной системы контроля дыхания:
- Arduino Uno или ESP32 (для беспроводной передачи данных)
- Ультразвуковой датчик HC-SR04 или лазерный дальномер VL53L0X
- Микрофон MAX9814 с автоматической регулировкой усиления для записи храпа
- Датчик температуры и влажности DHT22 для контроля параметров воздуха
- SD-карта модуль для локального хранения данных
- Модуль часов реального времени DS3231 для точной отметки времени
- Корпус для крепления на стене или прикроватной тумбочке
Схема подключения основных компонентов к Arduino:
- HC-SR04 Trig → Arduino D7
- HC-SR04 Echo → Arduino D8
- MAX9814 Out → Arduino A0
- DHT22 Data → Arduino D4
- SD модуль CS → Arduino D10
- SD модуль MOSI → Arduino D11
- SD модуль MISO → Arduino D12
- SD модуль SCK → Arduino D13
- DS3231 SDA → Arduino A4
- DS3231 SCL → Arduino A5
Ключевой алгоритм для анализа дыхания по данным ультразвукового датчика:
#include <NewPing.h>
#include <SD.h>
#include <SPI.h>
#include <DHT.h>
#include "RTClib.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100 // Максимальное расстояние в см
#define DHTPIN 4
#define DHTTYPE DHT22
#define SOUND_PIN A0
#define CHIP_SELECT 10
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
DHT dht(DHTPIN, DHTTYPE);
RTC_DS3231 rtc;
File dataFile;
// Параметры для анализа дыхания
const int SAMPLES = 10;
float distances[SAMPLES];
int sampleIndex = 0;
float breathingRate = 0;
unsigned long lastBreathTime = 0;
int breathCount = 0;
bool breathingIn = false;
int apneaCounter = 0;
bool possibleApnea = false;
void setup() {
Serial.begin(9600);
dht.begin();
if (!rtc.begin()) {
Serial.println("Не найден RTC модуль");
while (1);
}
if (!SD.begin(CHIP_SELECT)) {
Serial.println("Ошибка инициализации SD карты");
while (1);
}
// Создание нового файла для записи данных
DateTime now = rtc.now();
String fileName = String(now.year()) + String(now.month()) + String(now.day()) + ".csv";
dataFile = SD.open(fileName, FILE_WRITE);
if (dataFile) {
dataFile.println("Время,Расстояние,Звук,Частота дыхания,Возможное апноэ,Температура,Влажность");
dataFile.close();
}
// Инициализация массива расстояний
for (int i = 0; i < SAMPLES; i++) {
distances[i] = 0;
}
}
void loop() {
// Измерение расстояния
delay(50);
unsigned int distance = sonar.ping_cm();
// Если расстояние в пределах диапазона
if (distance > 0 && distance < MAX_DISTANCE) {
// Добавление нового измерения в массив
distances[sampleIndex] = distance;
sampleIndex = (sampleIndex + 1) % SAMPLES;
// Анализ дыхания
analyzeBreathing();
// Проверка на апноэ
if (breathingRate < 10 && breathingRate > 0) {
apneaCounter++;
if (apneaCounter > 10) { // Примерно 10 секунд без изменений в дыхании
possibleApnea = true;
}
} else {
apneaCounter = 0;
possibleApnea = false;
}
// Измерение звука (храпа)
int soundLevel = analogRead(SOUND_PIN);
// Измерение параметров окружающей среды
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
// Получение текущего времени
DateTime now = rtc.now();
String timeStamp = String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second());
// Запись данных на SD карту
dataFile = SD.open("data.csv", FILE_WRITE);
if (dataFile) {
dataFile.print(timeStamp);
dataFile.print(",");
dataFile.print(distance);
dataFile.print(",");
dataFile.print(soundLevel);
dataFile.print(",");
dataFile.print(breathingRate);
dataFile.print(",");
dataFile.print(possibleApnea ? "1" : "0");
dataFile.print(",");
dataFile.print(temperature);
dataFile.print(",");
dataFile.println(humidity);
dataFile.close();
}
// Вывод в монитор порта для отладки
Serial.print("Расстояние: ");
Serial.print(distance);
Serial.print(" см, Дыхание: ");
Serial.print(breathingRate);
Serial.print(" вдохов/мин, Апноэ: ");
Serial.println(possibleApnea ? "Возможно" : "Нет");
}
}
void analyzeBreathing() {
// Расчет среднего расстояния
float sum = 0;
for (int i = 0; i < SAMPLES; i++) {
sum += distances[i];
}
float avgDistance = sum / SAMPLES;
// Определение вдоха/выдоха по изменению расстояния
float currentDistance = distances[sampleIndex];
// Допустим, уменьшение расстояния – вдох (грудная клетка поднимается)
if (!breathingIn && currentDistance < avgDistance – 0.5) {
breathingIn = true;
unsigned long now = millis();
if (lastBreathTime > 0) {
// Расчет частоты дыхания
unsigned long breathInterval = now – lastBreathTime;
breathingRate = 60000.0 / breathInterval; // Преобразование в вдохов/минуту
}
lastBreathTime = now;
breathCount++;
}
else if (breathingIn && currentDistance > avgDistance + 0.5) {
breathingIn = false;
}
}
Система может быть улучшена путем добавления следующих функций:
- Инфракрасная камера MLX90640 для тепловой визуализации и точного отслеживанияmovements
- Алгоритмы машинного обучения для распознавания паттернов дыхания и автоматического определения нарушений
- Система оповещения при критических состояниях (например, длительное апноэ)
- Интеграция с умным домом для автоматической регулировки параметров окружающей среды, улучшающих качество сна
Для максимальной эффективности бесконтактной системы важно правильно расположить устройство относительно спящего человека. Оптимальная позиция — напротив грудной клетки на расстоянии 30-50 см, с направленным под небольшим углом сенсором. Такое размещение обеспечивает наилучшее отслеживание дыхательных движений. 📊
Сбор и визуализация данных о сне в приложении
Даже самая продвинутая система мониторинга сна бесполезна без эффективного способа сбора, анализа и представления данных. Разработка приложения для визуализации полученной информации — заключительный этап создания полноценной системы мониторинга сна на Arduino.
Существует несколько подходов к организации сбора и отображения данных:
- Локальное приложение на ПК (написанное на Processing, Python или C#)
- Мобильное приложение (Android, iOS) с подключением по Bluetooth
- Веб-интерфейс с передачей данных через ESP8266/ESP32 по Wi-Fi
- Облачная платформа IoT (ThingSpeak, Blynk, Google Firebase)
Рассмотрим вариант с использованием ESP32 и веб-интерфейса — это решение не требует разработки отдельного мобильного приложения и доступно с любого устройства, имеющего браузер.
Основные компоненты для системы сбора и визуализации:
- ESP32 (с встроенным Wi-Fi и Bluetooth)
- Micro SD карта для локального хранения данных
- Веб-сервер на ESP32
- Библиотеки для создания графиков (например, Chart.js)
- База данных (локальная на SD-карте или облачная)
Пример кода для ESP32 для создания веб-сервера и отправки данных в формате JSON:
#include <WiFi.h>
#include <WebServer.h>
#include <SPIFFS.h>
#include <ArduinoJson.h>
#include <SD.h>
// Данные Wi-Fi сети
const char* ssid = "YourWiFiName";
const char* password = "YourWiFiPassword";
// Создание веб-сервера на порту 80
WebServer server(80);
// Путь к файлу с данными сна на SD-карте
const char* dataPath = "/sleep_data.csv";
// Буфер для хранения данных
const int maxDataPoints = 1000;
struct SleepData {
String timestamp;
float movement;
int heartRate;
float spo2;
int sleepPhase;
};
SleepData sleepHistory[maxDataPoints];
int dataCount = 0;
void setup() {
Serial.begin(115200);
// Инициализация файловой системы SPIFFS
if (!SPIFFS.begin(true)) {
Serial.println("Ошибка монтирования SPIFFS");
return;
}
// Инициализация SD карты
if (!SD.begin()) {
Serial.println("Ошибка инициализации SD карты");
return;
}
// Загрузка исторических данных
loadSleepData();
// Подключение к Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Подключение к Wi-Fi...");
}
Serial.println("Подключено к Wi-Fi");
Serial.print("IP адрес: ");
Serial.println(WiFi.localIP());
// Настройка маршрутов веб-сервера
server.on("/", HTTP_GET, handleRoot);
server.on("/data", HTTP_GET, handleData);
server.on("/stats", HTTP_GET, handleStats);
server.on("/upload", HTTP_POST, handleUpload);
server.onNotFound(handleNotFound);
// Запуск веб-сервера
server.begin();
Serial.println("Веб-сервер запущен");
}
void loop() {
server.handleClient();
// Обработка данных с устройств мониторинга сна
// Это место для кода получения данных с датчиков
}
void handleRoot() {
// Отправка HTML страницы из SPIFFS
File file = SPIFFS.open("/index.html", "r");
if (file) {
server.streamFile(file, "text/html");
file.close();
} else {
server.send(404, "text/plain", "Файл не найден");
}
}
void handleData() {
// Создание JSON с данными о сне
DynamicJsonDocument doc(10000);
JsonArray dataArray = doc.createNestedArray("data");
for (int i = 0; i < dataCount; i++) {
JsonObject dataPoint = dataArray.createNestedObject();
dataPoint["time"] = sleepHistory[i].timestamp;
dataPoint["movement"] = sleepHistory[i].movement;
dataPoint["heartRate"] = sleepHistory[i].heartRate;
dataPoint["spo2"] = sleepHistory[i].spo2;
dataPoint["phase"] = sleepHistory[i].sleepPhase;
}
String jsonString;
serializeJson(doc, jsonString);
server.send(200, "application/json", jsonString);
}
void handleStats() {
// Расчет и отправка статистики сна
float avgHeartRate = 0;
float avgSpo2 = 0;
int deepSleepMinutes = 0;
int remSleepMinutes = 0;
int lightSleepMinutes = 0;
for (int i = 0; i < dataCount; i++) {
avgHeartRate += sleepHistory[i].heartRate;
avgSpo2 += sleepHistory[i].spo2;
// Подсчет времени в разных фазах сна
// Предполагаем, что измерения делаются каждую минуту
switch(sleepHistory[i].sleepPhase) {
case 1: lightSleepMinutes++; break;
case 2: deepSleepMinutes++; break;
case 3: remSleepMinutes++; break;
}
}
if (dataCount > 0) {
avgHeartRate /= dataCount;
avgSpo2 /= dataCount;
}
DynamicJsonDocument doc(1024);
doc["avgHeartRate"] = avgHeartRate;
doc["avgSpo2"] = avgSpo2;
doc["deepSleepMinutes"] = deepSleepMinutes;
doc["remSleepMinutes"] = remSleepMinutes;
doc["lightSleepMinutes"] = lightSleepMinutes;
doc["totalSleepMinutes"] = lightSleepMinutes + deepSleepMinutes + remSleepMinutes;
doc["sleepQualityScore"] = calculateSleepQuality(deepSleepMinutes, remSleepMinutes, lightSleepMinutes);
String jsonString;
serializeJson(doc, jsonString);
server.send(200, "application/json", jsonString);
}
float calculateSleepQuality(int deep, int rem, int light) {
// Алгоритм расчета качества сна
// Глубокий сон и REM фаза имеют больший вес
int totalMinutes = deep + rem + light;
if (totalMinutes == 0) return 0;
// Идеальное соотношение: 20% глубокого, 25% REM, 55% легкого
float deepPercentage = (float)deep / totalMinutes;
float remPercentage = (float)rem / totalMinutes;
// Оценка от 0 до 100
return (deepPercentage * 40) + (remPercentage * 35) +
((float)totalMinutes / 480) * 25; // 480 минут = 8 часов
}
void handleUpload() {
// Обработка загрузки данных с устройств
if (server.hasArg("plain")) {
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, server.arg("plain"));
if (!error) {
// Добавление новых данных
if (dataCount < maxDataPoints) {
sleepHistory[dataCount].timestamp = doc["time"].as<String>();
sleepHistory[dataCount].movement = doc["movement"].as<float>();
sleepHistory[dataCount].heartRate = doc["heartRate"].as<int>();
sleepHistory[dataCount].spo2 = doc["spo2"].as<float>();
sleepHistory[dataCount].sleepPhase = doc["phase"].as<int>();
dataCount++;
// Сохранение данных на SD карту
saveSleepData();
server.send(200, "text/plain", "Данные получены");
} else {
server.send(507, "text/plain", "Хранилище данных заполнено");
}
} else {
server.send(400, "text/plain", "Неверный формат JSON");
}
} else {
server.send(400, "text/plain", "Нет данных");
}
}
void handleNotFound() {
server.send(404, "text/plain", "Страница не найдена");
}
void loadSleepData() {
// Загрузка данных с SD карты
File file = SD.open(dataPath);
if (!file) {
Serial.println("Файл с данными не найден");
return;
}
dataCount = 0;
while (file.available() && dataCount < maxDataPoints) {
String line = file.readStringUntil('\n');
// Парсинг строки CSV
int commaIndex = line.indexOf(',');
if (commaIndex > 0) {
sleepHistory[dataCount].timestamp = line.substring(0, commaIndex);
line = line.substring(commaIndex + 1);
commaIndex = line.indexOf(',');
sleepHistory[dataCount].movement = line.substring(0, commaIndex).toFloat();
line = line.substring(commaIndex + 1);
commaIndex = line.indexOf(',');
sleepHistory[dataCount].heartRate = line.substring(0, commaIndex).toInt();
line = line.substring(commaIndex + 1);
commaIndex = line.indexOf(',');
sleepHistory[dataCount].spo2 = line.substring(0, commaIndex).toFloat();
sleepHistory[dataCount].sleepPhase = line.substring(commaIndex + 1).toInt();
dataCount++;
}
}
file.close();
Serial.printf("Загружено %d записей данных\n", dataCount);
}
void saveSleepData() {
// Сохранение данных на SD карту
File file = SD.open(dataPath, FILE_WRITE);
if (!file) {
Serial.println("Не удалось открыть файл для записи");
return;
}
for (int i = 0; i < dataCount; i++) {
file.printf("%s,%.2f,%d,%.2f,%d\n",
sleepHistory[i].timestamp.c_str(),
sleepHistory[i].movement,
sleepHistory[i].heartRate,
sleepHistory[i].spo2,
sleepHistory[i].sleepPhase);
}
file.close();
Serial.printf("Сохранено %d записей данных\n", dataCount);
}
Для визуализации данных необходимо создать HTML-интерфейс с использованием JavaScript и библиотеки для построения графиков. Пример простого интерфейса для отображения данных о сне:
<!DOCTYPE html>
<html>
<head>
<title>Sleep Monitor Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.card {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 20px;
margin-bottom: 20px;
}
.chart-container {
position: relative;
height: 300px;
width: 100%;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
}
.stat-card {
background-color: #e9f7fe;
border-radius: 8px;
padding: 15px;
text-align: center;
}
.stat-value {
font-size: 24px;
font-weight: bold;
margin: 10px 0;
}
.stat-label {
color: #666;
font-size: 14px;
}
h1, h2 {
color: #333;
}
</style>
</head>
<body>
<div class="container">
<h1>Мониторинг сна</h1>
<div class="card">
<h2>Статистика последней ночи</h2>
<div class="stat-grid" id="stats-container">
<!-- Здесь будут отображаться статистические данные -->
</div>
</div>
<div class="card">
<h2>Частота сердечных сокращений</h2>
<div class="chart-container">
<canvas id="heartRateChart"></canvas>
</div>
</div>
<div class="card">
<h2>Насыщение крови кислородом</h2>
<div class="chart-container">
<canvas id="spo2Chart"></canvas>
</div>
</div>
<div class="card">
<h2>Движения во сне</h2>
<div class="chart-container">
<canvas id="movementChart"></canvas>
</div>
</div>
<div class="card">
<h2>Фазы сна</h2>
<div class="chart-container">
<canvas id="sleepPhaseChart"></canvas>
</div>
</div>
</div>
<script>
// Функция загрузки данных
async function loadData() {
try {
const response = await fetch('/data');
const data = await response.json();
return data.data;
} catch (error) {
console.error('Ошибка загрузки данных:', error);
return [];
}
}
// Функция загрузки статистики
async function loadStats() {
try {
const response = await fetch('/stats');
return await response.json();
} catch (error) {
console.error('Ошибка загрузки статистики:', error);
return {};
}
}
// Функция отображения статистики
function displayStats(stats) {
const container = document.getElementById('stats-container');
container.innerHTML = '';
// Создание элементов статистики
const statsItems = [
{ label: 'Средний пульс', value: Math.round(stats.avgHeartRate) + ' уд/мин' },
{ label: 'Среднее SpO2', value: stats.avgSpo2.toFixed(1) + '%' },
{ label: 'Глубокий сон', value: Math.floor(stats.dee
**Читайте также**
- [Умные аквариумы на Arduino](/gamedev/umnye-akvariumy-na-arduino/)
- [Arduino IDE: установка и настройка для новичков – простая инструкция](/gadgets/sreda-razrabotki-arduino-ide-ustanovka-i-nastrojka/)
- [Топ-10 Arduino-проектов для умного дома: сделай своими руками](/gadgets/legkie-proekty-dlya-doma-na-arduino/)
- [10 впечатляющих проектов Arduino с LCD дисплеями: от часов до умного дома](/gadgets/proekty-s-lcd-displeyami-na-arduino/)
- [Примеры проектов с дисплеем и датчиками для Arduino](/gamedev/primery-proektov-s-displeem-i-datchikami-dlya-arduino/)
- [Сенсорные экраны Arduino: топ-10 вдохновляющих проектов для начинающих](/gadgets/proekty-s-sensornymi-ekranami-na-arduino/)
- [Датчики влажности для Arduino: лучшие проекты с автополивом](/gadgets/proekty-s-datchikami-vlazhnosti-na-arduino/)
- [Отладка Arduino: эффективные методы поиска и устранения ошибок](/gadgets/otladka-i-ustranenie-oshibok-v-proektah-na-arduino/)
- [Проекты с температурными датчиками на Arduino](/gamedev/proekty-s-temperaturnymi-datchikami-na-arduino/)
- [Создание монитора сердечного ритма Arduino: схемы и код](/gadgets/monitory-serdechnogo-ritma-na-arduino/)