BLE_PROTOCOL.md: - ESP32 BLE provisioning protocol spec - Characteristics UUIDs and data formats - WiFi credential exchange flow - Security considerations - Error handling SENSORS_IMPLEMENTATION_PLAN.md: - Complete implementation roadmap - Phase 1: BLE scanning and connection - Phase 2: WiFi provisioning - Phase 3: Device management - Phase 4: Status monitoring - API endpoints and data models - Testing checklist Technical reference for: - Backend developers - Mobile developers - QA team
20 KiB
WellNuo Sensors - Implementation Plan
🎯 Цель
Заменить мок-данные в экране equipment.tsx на реальное управление WP сенсорами через Bluetooth Low Energy (BLE).
⚠️ КРИТИЧНО: Bluetooth в iOS Simulator
iOS Simulator НЕ ПОДДЕРЖИВАЕТ Bluetooth!
Решение:
- На реальном устройстве: полный BLE функционал
- В Simulator: показываем mock-данные + предупреждение
Проверка доступности BLE:
import * as Device from 'expo-device';
import { Platform } from 'react-native';
const isBLEAvailable = Platform.OS !== 'web' && Device.isDevice;
// Device.isDevice = false в Simulator, true на реальном устройстве
📚 Библиотека: react-native-ble-plx
Рекомендуемая библиотека: react-native-ble-plx
- ✅ Поддержка Expo (через config plugin)
- ✅ Кроссплатформенность (iOS + Android)
- ✅ Активная поддержка
- ✅ TypeScript типы
Установка:
npx expo install react-native-ble-plx
Конфигурация app.json:
{
"expo": {
"plugins": [
[
"react-native-ble-plx",
{
"isBackgroundEnabled": true,
"modes": ["peripheral", "central"],
"bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to WellNuo sensors"
}
]
]
}
}
🏗️ Архитектура
1. BLE Service (services/ble/)
services/ble/
├── BLEManager.ts # Центральный менеджер BLE
├── WellPlugDevice.ts # Класс для работы с WP устройствами
├── BLECommands.ts # Константы команд (pin|7856, w, W, a, s, D)
├── MockBLEManager.ts # Mock для Simulator
└── types.ts # TypeScript типы
2. Context (contexts/BLEContext.tsx)
Глобальный контекст для управления BLE состоянием:
- Список найденных устройств
- Состояние сканирования
- Подключенные устройства
- Ошибки
3. Хуки (hooks/)
// hooks/useBLE.ts
export function useBLE() {
// Доступ к BLEContext
// Scan, connect, disconnect
}
// hooks/useWellPlugDevice.ts
export function useWellPlugDevice(deviceId: string) {
// Управление конкретным WP устройством
// getWiFiList(), setWiFi(), checkCurrentWiFi()
}
🎨 Экраны и User Flow
Экран 1: Equipment List (текущий equipment.tsx)
Функционал:
- ✅ Показать список привязанных WP сенсоров к beneficiary
- ✅ Статус онлайн/офлайн через API
request_devices(fresh=true) - ✅ Последний раз виден (Last seen)
- ✅ Текущая WiFi сеть (получаем через BLE команду
a) - ✅ Кнопка "Настроить" → переход на Device Settings
- ✅ Кнопка "Добавить сенсор" → Scan Screen
Данные:
interface WPSensor {
deviceId: string; // device_id из PostgreSQL
wellId: number; // well_id (497, 523)
mac: string; // MAC адрес (142B2F81A14C)
name: string; // "WP_497_81a14c"
// Статус (из API)
status: 'online' | 'offline';
lastSeen: Date; // timestamp из device_list API
// WiFi (из BLE)
currentWiFi?: {
ssid: string; // "FrontierTower"
rssi: number; // -67 dBm
};
// Привязка
beneficiaryId: string;
deploymentId: number;
}
API для получения списка:
// services/api.ts
async getDevicesForBeneficiary(beneficiaryId: string): Promise<WPSensor[]> {
// 1. Получить deployment_id для beneficiary из PostgreSQL
// 2. Вызвать Legacy API: device_list_by_deployment
// 3. Вызвать request_devices(fresh=true) для онлайн статуса
// 4. Объединить данные
}
BLE для текущего WiFi:
- При открытии экрана → подключаемся к каждому устройству по BLE
- Отправляем команду
a - Парсим ответ:
mac,XXXXXX|a|SSID,RSSI - Обновляем UI
Экран 2: Add Sensor (новый add-sensor.tsx)
Путь: app/(tabs)/beneficiaries/[id]/add-sensor.tsx
Функционал:
- ✅ Сканирование BLE устройств с именем
WP_* - ✅ Показать список найденных (с RSSI - сила сигнала)
- ✅ Сортировка по близости (RSSI)
- ✅ Выбор устройства → переход на Setup WiFi Screen
UI:
┌─────────────────────────┐
│ ← Scan for Sensors │
├─────────────────────────┤
│ │
│ 📡 Scanning... │
│ │
│ WP_497_81a14c │
│ Signal: ████░░ -55dBm │
│ [Connect] │
│ │
│ WP_523_81aad4 │
│ Signal: ███░░░ -67dBm │
│ [Connect] │
│ │
│ [Rescan] │
│ │
└─────────────────────────┘
Алгоритм сканирования:
async function scanForWPDevices() {
const manager = new BleManager();
// Сканируем 10 секунд
manager.startDeviceScan(
null, // serviceUUIDs (можем фильтровать по service UUID)
null, // options
(error, device) => {
if (error) {
// Handle error
return;
}
// Фильтруем только WP_ устройства
if (device.name?.startsWith('WP_')) {
// Добавляем в список
// Сортируем по RSSI (ближе = выше значение)
}
}
);
// Через 10 секунд останавливаем
setTimeout(() => manager.stopDeviceScan(), 10000);
}
Экран 3: Setup WiFi (новый setup-wifi.tsx)
Путь: app/(tabs)/beneficiaries/[id]/setup-wifi.tsx
Параметры: ?deviceName=WP_497_81a14c&beneficiaryId=123
Функционал:
Шаг 1: Подключение к устройству
┌─────────────────────────┐
│ ← Setup WP_497 │
├─────────────────────────┤
│ │
│ 📱 Connecting to │
│ WP_497_81a14c... │
│ │
│ ⏳ Please wait │
│ │
└─────────────────────────┘
Шаг 2: Unlock (автоматически)
- Отправляем
pin|7856 - Ждём ответ
pin|ok
Шаг 3: Получение списка WiFi
┌─────────────────────────┐
│ ← Select WiFi Network │
├─────────────────────────┤
│ │
│ 📶 FrontierTower │
│ Signal: ████░ -55 │
│ [Select] │
│ │
│ 📶 HomeNetwork │
│ Signal: ███░░ -67 │
│ [Select] │
│ │
│ 📶 TP-Link_5G │
│ Signal: ██░░░ -75 │
│ [Select] │
│ │
│ [Rescan] │
│ │
└─────────────────────────┘
Алгоритм:
- Отправляем команду
w - Ждём ответ:
mac,XXXXXX|w|3|SSID1,RSSI1|SSID2,RSSI2|SSID3,RSSI3 - Парсим список
- Сортируем по RSSI (сильный сигнал первым)
Шаг 4: Ввод пароля
┌─────────────────────────┐
│ ← WiFi Password │
├─────────────────────────┤
│ │
│ Network: FrontierTower │
│ │
│ Password: │
│ [**************] │
│ [ ] Show password │
│ │
│ [Connect] │
│ │
└─────────────────────────┘
Шаг 5: Настройка WiFi
- Отправляем
W|FrontierTower,password123 - Ждём ответ
mac,XXXXXX|W|okилиmac,XXXXXX|W|fail - Если
ok→ ждём 5 секунд → проверяем командойa
Шаг 6: Проверка подключения
┌─────────────────────────┐
│ ✅ Connected! │
├─────────────────────────┤
│ │
│ Network: FrontierTower │
│ Signal: ████░ -67 dBm │
│ │
│ Device is now online │
│ and sending data │
│ │
│ [Continue] │
│ │
└─────────────────────────┘
Экран 4: Device Settings (новый device-settings.tsx)
Путь: app/(tabs)/beneficiaries/[id]/device-settings/[deviceId].tsx
Функционал:
- ✅ Показать текущую WiFi (команда
a) - ✅ Изменить WiFi → Setup WiFi Screen
- ✅ Перезагрузить устройство (команда
s) - ✅ Отвязать от beneficiary (Detach)
- ✅ Проверить статус онлайн/офлайн
UI:
┌─────────────────────────┐
│ ← Device Settings │
│ WP_497_81a14c │
├─────────────────────────┤
│ │
│ Status │
│ 🟢 Online │
│ Last seen: 2 min ago │
│ │
│ WiFi Network │
│ 📶 FrontierTower │
│ Signal: ████░ -67 dBm │
│ [Change WiFi] │
│ │
│ Device Info │
│ MAC: 142B2F81A14C │
│ Well ID: 497 │
│ │
│ Actions │
│ [🔄 Reboot Device] │
│ [🔗 Detach Device] │
│ │
└─────────────────────────┘
🔌 API Integration
Legacy API Endpoints
1. Получить список устройств deployment:
POST https://eluxnetworks.net/function/well-api/api
{
function: 'device_list_by_deployment',
user_name: 'USER',
token: 'TOKEN',
deployment_id: 70,
first: 0,
last: 100
}
2. Проверить онлайн статус (batch):
POST https://eluxnetworks.net/function/well-api/api
{
function: 'request_devices',
user_name: 'USER',
token: 'TOKEN',
deployment_id: 70,
group_id: 'All',
location: 'All',
fresh: true // ← Только онлайн устройства
}
3. Привязать устройство к deployment:
POST https://eluxnetworks.net/function/well-api/api
{
function: 'set_deployment',
// ... все параметры из BLE_PROTOCOL.md
devices: [497, 523], // well_ids
wifis: ["FrontierTower|password123"]
}
PostgreSQL
Получить deployment_id для beneficiary:
SELECT d.deployment_id, pd.access_to_deployments
FROM person_details pd
JOIN deployments d ON d.deployment_id = ANY(string_to_array(pd.access_to_deployments, ',')::int[])
WHERE pd.user_id = $1;
🧩 Компоненты
1. DeviceCard Component
Переиспользуемая карточка устройства:
<DeviceCard
device={sensor}
onPress={() => router.push(`/device-settings/${sensor.deviceId}`)}
onDetach={() => handleDetach(sensor)}
showWiFi={true}
/>
2. WiFiNetworkItem Component
Элемент списка WiFi сетей:
<WiFiNetworkItem
ssid="FrontierTower"
rssi={-67}
onSelect={() => handleSelectNetwork('FrontierTower')}
/>
3. BLEScanner Component
Компонент сканирования:
<BLEScanner
isScanning={scanning}
devices={foundDevices}
onDeviceSelect={(device) => handleConnect(device)}
onRescan={() => startScan()}
/>
4. SimulatorWarning Component
Предупреждение для Simulator:
{!Device.isDevice && (
<SimulatorWarning
message="Bluetooth is not available in iOS Simulator. Please test on a real device."
/>
)}
🔐 Permissions
iOS (Info.plist через app.json)
{
"expo": {
"ios": {
"infoPlist": {
"NSBluetoothAlwaysUsageDescription": "WellNuo needs Bluetooth to connect to your wellness sensors",
"NSBluetoothPeripheralUsageDescription": "WellNuo needs Bluetooth to manage your sensors"
}
}
}
}
Android (AndroidManifest.xml через app.json)
{
"expo": {
"android": {
"permissions": [
"android.permission.BLUETOOTH",
"android.permission.BLUETOOTH_ADMIN",
"android.permission.BLUETOOTH_CONNECT",
"android.permission.BLUETOOTH_SCAN",
"android.permission.ACCESS_FINE_LOCATION"
]
}
}
}
📱 Mock Data для Simulator
// services/ble/MockBLEManager.ts
export class MockBLEManager implements IBLEManager {
async scanDevices(): Promise<WPDevice[]> {
// Возвращаем фейковые WP устройства
return [
{
id: 'mock-1',
name: 'WP_497_81a14c',
rssi: -55,
mac: '142B2F81A14C'
},
{
id: 'mock-2',
name: 'WP_523_81aad4',
rssi: -67,
mac: '142B2F81AAD4'
}
];
}
async connect(deviceId: string): Promise<boolean> {
// Симулируем задержку
await delay(1000);
return true;
}
async getWiFiList(): Promise<WiFiNetwork[]> {
return [
{ ssid: 'FrontierTower', rssi: -55 },
{ ssid: 'HomeNetwork', rssi: -67 },
{ ssid: 'TP-Link_5G', rssi: -75 }
];
}
async setWiFi(ssid: string, password: string): Promise<boolean> {
await delay(2000);
return true;
}
async getCurrentWiFi(): Promise<{ ssid: string; rssi: number }> {
return { ssid: 'FrontierTower', rssi: -67 };
}
}
🧪 Тестирование
1. На iOS Simulator
- ❌ BLE не работает
- ✅ Показываем mock данные
- ✅ Проверяем UI/UX флоу
2. На реальном iPhone
- ✅ Полный BLE функционал
- ✅ Подключение к WP устройствам
- ✅ Настройка WiFi
3. Android Emulator
- ⚠️ Может работать с пробросом Bluetooth
- Не рекомендуется для основной разработки
📋 План Реализации (По Шагам)
Фаза 1: Инфраструктура (2-3 часа)
- ✅ Установить
react-native-ble-plx - ✅ Настроить permissions (iOS + Android)
- ✅ Создать
services/ble/BLEManager.ts - ✅ Создать
services/ble/MockBLEManager.ts - ✅ Создать
contexts/BLEContext.tsx - ✅ Добавить проверку
Device.isDevice
Фаза 2: API Integration (1-2 часа)
- ✅ Добавить методы в
services/api.ts:getDevicesForBeneficiary()getDeviceStatus()attachDeviceToDeployment()
- ✅ Интегрировать Legacy API endpoints
- ✅ Добавить PostgreSQL queries
Фаза 3: Equipment Screen (1-2 часа)
- ✅ Заменить mock данные на реальные API calls
- ✅ Добавить BLE функционал для getCurrentWiFi
- ✅ Обновить UI для WP сенсоров
- ✅ Добавить SimulatorWarning
Фаза 4: Add Sensor Screen (2-3 часа)
- ✅ Создать новый экран
add-sensor.tsx - ✅ Реализовать BLE сканирование
- ✅ Показать список устройств с RSSI
- ✅ Добавить кнопку подключения
Фаза 5: Setup WiFi Screen (3-4 часа)
- ✅ Создать экран
setup-wifi.tsx - ✅ Реализовать мульти-шаговый флоу:
- Connect → Unlock → Get WiFi List → Enter Password → Set WiFi → Verify
- ✅ Обработка ошибок
- ✅ Привязка к deployment через API
Фаза 6: Device Settings Screen (1-2 часа)
- ✅ Создать экран
device-settings.tsx - ✅ Показать текущую WiFi
- ✅ Кнопки: Change WiFi, Reboot, Detach
- ✅ Статус онлайн/офлайн
Фаза 7: Тестирование (2-3 часа)
- ✅ Тест на Simulator (mock данные)
- ✅ Тест на реальном iPhone с WP устройствами
- ✅ Проверить все флоу
- ✅ Обработка edge cases
🚨 Edge Cases
1. Bluetooth выключен
if (!isBluetoothEnabled) {
Alert.alert(
'Bluetooth Disabled',
'Please enable Bluetooth to connect to sensors',
[
{ text: 'Open Settings', onPress: () => Linking.openSettings() },
{ text: 'Cancel' }
]
);
}
2. Нет permission
const status = await manager.requestPermissions();
if (status !== 'granted') {
// Показать инструкцию
}
3. Устройство не найдено
- Показать "No devices found"
- Кнопка Rescan
- Проверить что устройство включено
4. Не подключается к WiFi
- Показать ошибку от устройства
- Предложить повторить
- Проверить правильность пароля
5. Устройство оффлайн
- Показать серым
- Не пытаться подключаться по BLE
- Показать Last seen
🎯 Итоговый User Flow
1. Юзер открывает Equipment Screen
→ Видит список WP сенсоров (если есть)
→ Статус: онлайн/оффлайн (из API)
→ Текущая WiFi (из BLE)
2. Юзер нажимает "Add Sensor"
→ Открывается Add Sensor Screen
→ Сканирование BLE (10 сек)
→ Список найденных WP_* устройств
→ Сортировка по близости (RSSI)
3. Юзер выбирает устройство
→ Подключение по BLE
→ Автоматический unlock (pin|7856)
→ Получение списка WiFi сетей
→ Показ списка с сигналом
4. Юзер выбирает WiFi сеть
→ Ввод пароля
→ Отправка credentials (W|SSID,PASS)
→ Ожидание подключения (5 сек)
→ Проверка (команда a)
5. Success!
→ Устройство подключено к WiFi
→ Привязка к beneficiary через API
→ Возврат на Equipment Screen
→ Устройство появляется в списке как "online"
📝 Changelog
- 2026-01-14 - Создан план реализации функционала сенсоров
- Определена архитектура BLE управления
- Спроектированы все экраны
- Решена проблема с Simulator (mock данные)