WellNuo/docs/SENSORS_IMPLEMENTATION_PLAN.md
Sergei 2b68b70584 Add sensor system documentation
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
2026-01-14 19:08:19 -08:00

694 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WellNuo Sensors - Implementation Plan
## 🎯 Цель
Заменить мок-данные в экране `equipment.tsx` на реальное управление WP сенсорами через Bluetooth Low Energy (BLE).
---
## ⚠️ КРИТИЧНО: Bluetooth в iOS Simulator
**iOS Simulator НЕ ПОДДЕРЖИВАЕТ Bluetooth!**
### Решение:
- **На реальном устройстве:** полный BLE функционал
- **В Simulator:** показываем mock-данные + предупреждение
### Проверка доступности BLE:
```typescript
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 типы
### Установка:
```bash
npx expo install react-native-ble-plx
```
### Конфигурация `app.json`:
```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/`)
```typescript
// 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
**Данные:**
```typescript
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 для получения списка:**
```typescript
// 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] │
│ │
└─────────────────────────┘
```
**Алгоритм сканирования:**
```typescript
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:**
```typescript
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):**
```typescript
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:**
```typescript
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:**
```sql
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
Переиспользуемая карточка устройства:
```tsx
<DeviceCard
device={sensor}
onPress={() => router.push(`/device-settings/${sensor.deviceId}`)}
onDetach={() => handleDetach(sensor)}
showWiFi={true}
/>
```
### 2. WiFiNetworkItem Component
Элемент списка WiFi сетей:
```tsx
<WiFiNetworkItem
ssid="FrontierTower"
rssi={-67}
onSelect={() => handleSelectNetwork('FrontierTower')}
/>
```
### 3. BLEScanner Component
Компонент сканирования:
```tsx
<BLEScanner
isScanning={scanning}
devices={foundDevices}
onDeviceSelect={(device) => handleConnect(device)}
onRescan={() => startScan()}
/>
```
### 4. SimulatorWarning Component
Предупреждение для Simulator:
```tsx
{!Device.isDevice && (
<SimulatorWarning
message="Bluetooth is not available in iOS Simulator. Please test on a real device."
/>
)}
```
---
## 🔐 Permissions
### iOS (Info.plist через app.json)
```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)
```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
```typescript
// 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 часа)
1. ✅ Установить `react-native-ble-plx`
2. ✅ Настроить permissions (iOS + Android)
3. ✅ Создать `services/ble/BLEManager.ts`
4. ✅ Создать `services/ble/MockBLEManager.ts`
5. ✅ Создать `contexts/BLEContext.tsx`
6. ✅ Добавить проверку `Device.isDevice`
### Фаза 2: API Integration (1-2 часа)
1. ✅ Добавить методы в `services/api.ts`:
- `getDevicesForBeneficiary()`
- `getDeviceStatus()`
- `attachDeviceToDeployment()`
2. ✅ Интегрировать Legacy API endpoints
3. ✅ Добавить PostgreSQL queries
### Фаза 3: Equipment Screen (1-2 часа)
1. ✅ Заменить mock данные на реальные API calls
2. ✅ Добавить BLE функционал для getCurrentWiFi
3. ✅ Обновить UI для WP сенсоров
4. ✅ Добавить SimulatorWarning
### Фаза 4: Add Sensor Screen (2-3 часа)
1. ✅ Создать новый экран `add-sensor.tsx`
2. ✅ Реализовать BLE сканирование
3. ✅ Показать список устройств с RSSI
4. ✅ Добавить кнопку подключения
### Фаза 5: Setup WiFi Screen (3-4 часа)
1. ✅ Создать экран `setup-wifi.tsx`
2. ✅ Реализовать мульти-шаговый флоу:
- Connect → Unlock → Get WiFi List → Enter Password → Set WiFi → Verify
3. ✅ Обработка ошибок
4. ✅ Привязка к deployment через API
### Фаза 6: Device Settings Screen (1-2 часа)
1. ✅ Создать экран `device-settings.tsx`
2. ✅ Показать текущую WiFi
3. ✅ Кнопки: Change WiFi, Reboot, Detach
4. ✅ Статус онлайн/офлайн
### Фаза 7: Тестирование (2-3 часа)
1. ✅ Тест на Simulator (mock данные)
2. ✅ Тест на реальном iPhone с WP устройствами
3. ✅ Проверить все флоу
4. ✅ Обработка edge cases
---
## 🚨 Edge Cases
### 1. Bluetooth выключен
```tsx
if (!isBluetoothEnabled) {
Alert.alert(
'Bluetooth Disabled',
'Please enable Bluetooth to connect to sensors',
[
{ text: 'Open Settings', onPress: () => Linking.openSettings() },
{ text: 'Cancel' }
]
);
}
```
### 2. Нет permission
```tsx
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 данные)