康心伴Logo
康心伴WellAlly
Health

构建React Native ...?看这篇就够了 | WellAlly康心伴

5 分钟阅读

构建React Native BLE智能水杯应用:ESP32硬件集成指南

概述

智能水杯是健康监测应用的重要硬件设备,通过蓝牙(BLE)与手机App连接,实时追踪饮水量和提醒用户补充水分。

本文将介绍如何使用React Native和ESP32构建一个完整的智能水杯系统。


系统架构

code
┌─────────────────┐      BLE         ┌──────────────────┐
│   React Native   │ ◄──────────────► │    ESP32         │
│   手机应用        │  GATT连接       │    微控制器     │
│                 │                  │                  │
│  · 水量记录      │                  │  · 水位传感器    │
│  · 饮水提醒      │                  │  · 温度传感器    │
│  · 数据可视化    │                  │  · 振动传感器    │
└─────────────────┘                  └──────────────────┘
Code collapsed

硬件需求

ESP32配置

组件规格用途
主控ESP32-WROOMBLE通信和数据处理
水位传感器电容式液位传感器检测水位变化
温度传感器DS18B20监测水温
电池18650锂电池 + TP4056供电
振动马达1030扁平马达饮水提醒

电路设计

code
// ESP32引脚定义
#define WATER_LEVEL_PIN 34
#define TEMP_SENSOR_PIN 25
#define VIBRATION_MOTOR_PIN 26
#define BATTERY_PIN 35

void setup() {
    Serial.begin(115200);

    // 初始化BLE
    BLEDevice::init("SmartWaterBottle");

    // 初始化传感器
    pinMode(WATER_LEVEL_PIN, INPUT);
    pinMode(TEMP_SENSOR_PIN, INPUT);
    pinMode(VIBRATION_MOTOR_PIN, OUTPUT);

    // 初始化I2C(用于温度传感器)
    Wire.begin();
}
Code collapsed

ESP32固件开发

BLE服务配置

code
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// 自定义服务UUID
#define WATER_SERVICE_UUID "19B10000-E8F2-537E-4F6C-D104768A1214"
#define WATER_LEVEL_UUID "19B10001-E8F2-537E-4F6C-D104768A1214"
#define BATTERY_UUID "19B10002-E8F2-537E-4F6C-D104768A1214"

// 创建服务和特征
BLEService waterService(WATER_SERVICE_UUID);
BLECharacteristic waterLevelCharacteristic(
    WATER_LEVEL_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);

BLECharacteristic batteryCharacteristic(
    BATTERY_UUID,
    BLECharacteristic::PROPERTY_READ
);

void setupBLE() {
    // 创建服务器
    BLEServer *pServer = BLEDevice::createServer();

    // 设置服务
    pServer->setCallbacks(new ServerCallbacks());

    // 添加特征
    waterService.addCharacteristic(waterLevelCharacteristic);
    waterService.addCharacteristic(batteryCharacteristic);

    pServer->addService(waterService);

    // 启动服务
    BLEAdvertising *pAdvertising = pServer->getAdvertising();
    pAdvertising->start();
}

// 发送水位数据
void sendWaterLevel(int level) {
    uint8_t levelData = (uint8_t)level;
    waterLevelCharacteristic.setValue(&levelData, 1);
    waterLevelCharacteristic.notify();
}
Code collapsed

React Native应用开发

1. 安装依赖

code
npm install react-native-ble-plx
npm install @react-native-async-storage/async-storage
npm install react-native-chart-kit
Code collapsed

2. BLE连接管理

code
// BleManager.ts
import { BleManager } from 'react-native-ble-plx';
import { PermissionsAndroid } from 'react-native';

export class SmartWaterBottleManager {
  private device: any = null;
  private serviceUUID: string = '19B10000-E8F2-537E-4F6C-D104768A1214';

  async connect() {
    // 请求蓝牙权限
    if (Platform.OS === 'android') {
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
      );
      if (!granted) {
        throw new Error('Location permission denied');
      }
    }

    // 扫描设备
    this.device = await BleManager.scanDevices([
      this.serviceUUID
    ]);

    if (this.device.length > 0) {
      // 连接设备
      await BleManager.connect(this.device[0].id);
      console.log('Connected to Smart Water Bottle');
    } else {
      throw new Error('No devices found');
    }
  }

  async disconnect() {
    if (this.device) {
      await BleManager.disconnect(this.device[0].id);
    }
  }
}
Code collapsed

3. 读取水位数据

code
// WaterDataMonitor.ts
export class WaterDataMonitor {
  private waterLevelCharacteristicUUID = '19B10001-E8F2-537E-4F6C-D104768A1214';

  async startMonitoring(deviceId: string) {
    // 启用通知
    await BleManager.startNotification(
      deviceId,
      '19B10000-E8F2-537E-4F6C-D104768A1214',
      this.waterLevelCharacteristicUUID
    );

    // 监听数据更新
    BleManager.addListener('BleManagerDidUpdateValueForCharacteristic',
      ({ value, characteristic }) => {
        if (characteristic === this.waterLevelCharacteristicUUID) {
          const level = value[0]; // 水位 0-100
          this.processWaterLevel(level);
        }
      }
    );
  }

  private processWaterLevel(level: number) {
    // 处理水位数据
    console.log(`Water level: ${level}%`);

    // 保存到本地存储
    this.saveWaterData(level);

    // 发送提醒
    if (level < 20) {
      this.sendLowLevelReminder();
    }
  }

  private async saveWaterData(level: number) {
    const timestamp = Date.now();
    const record = { timestamp, level };

    // 保存到AsyncStorage
    const existingData = await AsyncStorage.getItem('water_records');
    const records = existingData ? JSON.parse(existingData) : [];
    records.push(record);
    await AsyncStorage.setItem('water_records', JSON.stringify(records));
  }
}
Code collapsed

4. 饮水提醒UI组件

code
// WaterReminder.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { WaterDataMonitor } from './WaterDataMonitor';

export function WaterReminder({ deviceId }: { deviceId: string }) {
  const [waterLevel, setWaterLevel] = useState(100);
  const [reminderVisible, setReminderVisible] = useState(false);

  useEffect(() => {
    const monitor = new WaterDataMonitor();
    monitor.startMonitoring(deviceId);

    return () => {
      // 清理
    };
  }, [deviceId]);

  const handleDrinkWater = () => {
    setWaterLevel(100);
    setReminderVisible(false);
    // 发送饮水记录到设备
  };

  return (
    <View style={styles.container}>
      {waterLevel < 20 && reminderVisible && (
        <View style={styles.reminder}>
          <Text style={styles.reminderText}>⚠️ 该喝水了!</Text>
          <Text style={styles.reminderSubText}>
            当前水位: {waterLevel}%
          </Text>
        </View>
      )}

      <View style={styles.waterLevelContainer}>
        <View
          style={[
            styles.waterLevelBar,
            { width: `${waterLevel}%` }
          ]}
        />
      </View>

      <Text style={styles.percentage}>{waterLevel}%</Text>

      {waterLevel < 50 && (
        <TouchableOpacity
          style={styles.drinkButton}
          onPress={handleDrinkWater}
        >
          <Text style={styles.drinkButtonText}>记录饮水</Text>
        </TouchableOpacity>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  reminder: {
    backgroundColor: '#ff6b6b',
    padding: 15,
    borderRadius: 10,
    marginBottom: 20,
  },
  reminderText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#fff',
  },
  waterLevelContainer: {
    height: 200,
    backgroundColor: '#e0e0e0',
    borderRadius: 10,
    overflow: 'hidden',
  },
  waterLevelBar: {
    height: '100%',
    backgroundColor: '#4A90E2',
    borderRadius: 10,
  },
  percentage: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginTop: 10,
  },
});
Code collapsed

数据同步与存储

本地数据管理

code
// WaterDataManager.ts
import AsyncStorage from '@react-native-async-storage/async-storage';

export interface WaterRecord {
  timestamp: number;
  level: number;
  amount?: number; // mL
}

export class WaterDataManager {
  private storageKey = 'water_records';

  async saveRecord(record: WaterRecord) {
    const records = await this.getAllRecords();
    records.push(record);
    await AsyncStorage.setItem(this.storageKey, JSON.stringify(records));
  }

  async getAllRecords(): Promise<WaterRecord[]> {
    const data = await AsyncStorage.getItem(this.storageKey);
    return data ? JSON.parse(data) : [];
  }

  async getTodayRecords(): Promise<WaterRecord[]> {
    const allRecords = await this.getAllRecords();
    const today = new Date().setHours(0, 0, 0, 0);

    return allRecords.filter(record => record.timestamp >= today);
  }

  async getTodayTotal(): Promise<number> {
    const todayRecords = await this.getTodayRecords();

    // 计算今日总饮水量(假设水位从100降到x相当于喝了100-x mL)
    let total = 0;
    for (let i = 1; i < todayRecords.length; i++) {
      const prevLevel = todayRecords[i - 1].level;
      const currLevel = todayRecords[i].level;
      if (currLevel < prevLevel) {
        total += (prevLevel - currLevel);
      }
    }

    return total; // mL
  }
}
Code collapsed

关键要点

  1. ESP32配置BLE服务:定义GATT服务和特征
  2. React Native BLE连接:使用react-native-ble-plx库
  3. 实时数据同步:通过通知机制更新水位数据
  4. 本地数据存储:使用AsyncStorage持久化记录
  5. 提醒机制:基于水位阈值的智能提醒

常见问题

BLE连接不稳定怎么办?

  1. 检查设备广播间隔
  2. 增加连接超时时间
  3. 实现自动重连机制

如何校准水位传感器?

提供校准模式:

  • 空杯时记录0%
  • 满杯时记录100%
  • 中间值线性插值

如何延长电池寿命?

  1. 降低广播频率
  2. 使用深度睡眠模式
  3. 优化传感器采样间隔

参考资料

  • ESP32 BLE官方文档
  • react-native-ble-plx文档
  • Bluetooth GATT规范
  • Apple Core Bluetooth指南

发布日期:2026年3月8日 最后更新:2026年3月8日

免责声明: 本内容仅供教育参考,不能替代专业医疗建议。请咨询医生获取个性化诊断和治疗方案。

#

文章标签

React Native
BLE
ESP32
智能硬件
物联网
健康应用

觉得这篇文章有帮助?

立即体验康心伴,开始您的健康管理之旅