构建React Native BLE智能水杯应用:ESP32硬件集成指南
概述
智能水杯是健康监测应用的重要硬件设备,通过蓝牙(BLE)与手机App连接,实时追踪饮水量和提醒用户补充水分。
本文将介绍如何使用React Native和ESP32构建一个完整的智能水杯系统。
系统架构
code
┌─────────────────┐ BLE ┌──────────────────┐
│ React Native │ ◄──────────────► │ ESP32 │
│ 手机应用 │ GATT连接 │ 微控制器 │
│ │ │ │
│ · 水量记录 │ │ · 水位传感器 │
│ · 饮水提醒 │ │ · 温度传感器 │
│ · 数据可视化 │ │ · 振动传感器 │
└─────────────────┘ └──────────────────┘
Code collapsed
硬件需求
ESP32配置
| 组件 | 规格 | 用途 |
|---|---|---|
| 主控 | ESP32-WROOM | BLE通信和数据处理 |
| 水位传感器 | 电容式液位传感器 | 检测水位变化 |
| 温度传感器 | 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
关键要点
- ESP32配置BLE服务:定义GATT服务和特征
- React Native BLE连接:使用react-native-ble-plx库
- 实时数据同步:通过通知机制更新水位数据
- 本地数据存储:使用AsyncStorage持久化记录
- 提醒机制:基于水位阈值的智能提醒
常见问题
BLE连接不稳定怎么办?
- 检查设备广播间隔
- 增加连接超时时间
- 实现自动重连机制
如何校准水位传感器?
提供校准模式:
- 空杯时记录0%
- 满杯时记录100%
- 中间值线性插值
如何延长电池寿命?
- 降低广播频率
- 使用深度睡眠模式
- 优化传感器采样间隔
参考资料
- ESP32 BLE官方文档
- react-native-ble-plx文档
- Bluetooth GATT规范
- Apple Core Bluetooth指南
发布日期:2026年3月8日 最后更新:2026年3月8日