# 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 { // 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 router.push(`/device-settings/${sensor.deviceId}`)} onDetach={() => handleDetach(sensor)} showWiFi={true} /> ``` ### 2. WiFiNetworkItem Component Элемент списка WiFi сетей: ```tsx handleSelectNetwork('FrontierTower')} /> ``` ### 3. BLEScanner Component Компонент сканирования: ```tsx handleConnect(device)} onRescan={() => startScan()} /> ``` ### 4. SimulatorWarning Component Предупреждение для Simulator: ```tsx {!Device.isDevice && ( )} ``` --- ## 🔐 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 { // Возвращаем фейковые 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 { // Симулируем задержку await delay(1000); return true; } async getWiFiList(): Promise { return [ { ssid: 'FrontierTower', rssi: -55 }, { ssid: 'HomeNetwork', rssi: -67 }, { ssid: 'TP-Link_5G', rssi: -75 } ]; } async setWiFi(ssid: string, password: string): Promise { 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 данные)