// Mock BLE Manager для iOS Simulator (Bluetooth недоступен) import { IBLEManager, WPDevice, WiFiNetwork, WiFiStatus, BLEConnectionState, BLEDeviceConnection, BLEEventListener, BLEConnectionEvent, } from './types'; const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); export class MockBLEManager implements IBLEManager { private connectedDevices = new Set(); private connectionStates = new Map(); private eventListeners: BLEEventListener[] = []; private connectingDevices = new Set(); // Track devices currently being connected private mockDevices: WPDevice[] = [ { id: 'mock-743', name: 'WP_497_81a14c', mac: '142B2F81A14C', rssi: -55, wellId: 497, }, { id: 'mock-769', name: 'WP_523_81aad4', mac: '142B2F81AAD4', rssi: -67, wellId: 523, }, ]; /** * Update connection state and notify listeners */ private updateConnectionState( deviceId: string, state: BLEConnectionState, deviceName?: string, error?: string ): void { const existing = this.connectionStates.get(deviceId); const now = Date.now(); const connection: BLEDeviceConnection = { deviceId, deviceName: deviceName || existing?.deviceName || deviceId, state, error, connectedAt: state === BLEConnectionState.CONNECTED ? now : existing?.connectedAt, lastActivity: now, }; this.connectionStates.set(deviceId, connection); this.emitEvent(deviceId, 'state_changed', { state, error }); } /** * Emit event to all registered listeners */ private emitEvent(deviceId: string, event: BLEConnectionEvent, data?: any): void { this.eventListeners.forEach((listener) => { try { listener(deviceId, event, data); } catch { // Listener error should not crash the app } }); } /** * Get current connection state for a device */ getConnectionState(deviceId: string): BLEConnectionState { const connection = this.connectionStates.get(deviceId); return connection?.state || BLEConnectionState.DISCONNECTED; } /** * Get all active connections */ getAllConnections(): Map { return new Map(this.connectionStates); } /** * Add event listener */ addEventListener(listener: BLEEventListener): void { if (!this.eventListeners.includes(listener)) { this.eventListeners.push(listener); } } /** * Remove event listener */ removeEventListener(listener: BLEEventListener): void { const index = this.eventListeners.indexOf(listener); if (index > -1) { this.eventListeners.splice(index, 1); } } async scanDevices(): Promise { await delay(2000); // Simulate scan delay return this.mockDevices; } stopScan(): void { } async connectDevice(deviceId: string): Promise { try { // Check if connection is already in progress if (this.connectingDevices.has(deviceId)) { throw new Error('Connection already in progress for this device'); } // Check if already connected if (this.connectedDevices.has(deviceId)) { this.updateConnectionState(deviceId, BLEConnectionState.READY); this.emitEvent(deviceId, 'ready'); return true; } // Mark device as connecting this.connectingDevices.add(deviceId); this.updateConnectionState(deviceId, BLEConnectionState.CONNECTING); await delay(500); this.updateConnectionState(deviceId, BLEConnectionState.CONNECTED); await delay(300); this.updateConnectionState(deviceId, BLEConnectionState.DISCOVERING); await delay(200); this.connectedDevices.add(deviceId); this.updateConnectionState(deviceId, BLEConnectionState.READY); this.emitEvent(deviceId, 'ready'); return true; } catch (error: any) { const errorMessage = error?.message || 'Connection failed'; this.updateConnectionState(deviceId, BLEConnectionState.ERROR, undefined, errorMessage); this.emitEvent(deviceId, 'connection_failed', { error: errorMessage }); return false; } finally { // Always remove from connecting set when done (success or failure) this.connectingDevices.delete(deviceId); } } async disconnectDevice(deviceId: string): Promise { this.updateConnectionState(deviceId, BLEConnectionState.DISCONNECTING); await delay(500); this.connectedDevices.delete(deviceId); this.updateConnectionState(deviceId, BLEConnectionState.DISCONNECTED); this.emitEvent(deviceId, 'disconnected'); } isDeviceConnected(deviceId: string): boolean { return this.connectedDevices.has(deviceId); } async sendCommand(deviceId: string, command: string): Promise { await delay(500); // Simulate responses if (command === 'pin|7856') { return 'pin|ok'; } if (command === 'w') { return 'mac,142b2f81a14c|w|3|FrontierTower,-55|HomeNetwork,-67|TP-Link_5G,-75'; } if (command === 'a') { return 'mac,142b2f81a14c|a|FrontierTower,-67'; } if (command.startsWith('W|')) { return 'mac,142b2f81a14c|W|ok'; } return 'ok'; } async getWiFiList(deviceId: string): Promise { await delay(1500); return [ { ssid: 'FrontierTower', rssi: -55 }, { ssid: 'HomeNetwork', rssi: -67 }, { ssid: 'TP-Link_5G', rssi: -75 }, { ssid: 'Office-WiFi', rssi: -80 }, ]; } async setWiFi( deviceId: string, ssid: string, password: string ): Promise { await delay(2000); return true; } async getCurrentWiFi(deviceId: string): Promise { await delay(1000); return { ssid: 'FrontierTower', rssi: -67, connected: true, }; } async rebootDevice(deviceId: string): Promise { await delay(500); this.connectedDevices.delete(deviceId); } /** * Cleanup all BLE connections and state * Should be called on app logout to properly release resources */ async cleanup(): Promise { // Disconnect all connected devices const deviceIds = Array.from(this.connectedDevices); for (const deviceId of deviceIds) { await this.disconnectDevice(deviceId); } this.connectedDevices.clear(); this.connectionStates.clear(); this.connectingDevices.clear(); this.eventListeners = []; } }