Add BLE cleanup on user logout
Implement comprehensive BLE cleanup functionality that properly disconnects all devices and releases resources when user logs out. Changes: - Add cleanup() method to BLEManager and MockBLEManager - Update IBLEManager interface to include cleanup - Add cleanupBLE() to BLEContext to disconnect all devices - Implement callback mechanism in api.ts for BLE cleanup on logout - Wire up BLE cleanup in app layout to trigger on logout - Add unit tests for BLE cleanup functionality This ensures no BLE connections remain active after logout, preventing resource leaks and potential connection issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2d7a5336b4
commit
2b2bd88726
@ -10,8 +10,9 @@ import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
|
|||||||
import { ToastProvider } from '@/components/ui/Toast';
|
import { ToastProvider } from '@/components/ui/Toast';
|
||||||
import { AuthProvider, useAuth } from '@/contexts/AuthContext';
|
import { AuthProvider, useAuth } from '@/contexts/AuthContext';
|
||||||
import { BeneficiaryProvider } from '@/contexts/BeneficiaryContext';
|
import { BeneficiaryProvider } from '@/contexts/BeneficiaryContext';
|
||||||
import { BLEProvider } from '@/contexts/BLEContext';
|
import { BLEProvider, useBLE } from '@/contexts/BLEContext';
|
||||||
import { useColorScheme } from '@/hooks/use-color-scheme';
|
import { useColorScheme } from '@/hooks/use-color-scheme';
|
||||||
|
import { setOnLogoutBLECleanupCallback } from '@/services/api';
|
||||||
|
|
||||||
// Stripe publishable key (test mode) - must match backend STRIPE_PUBLISHABLE_KEY
|
// Stripe publishable key (test mode) - must match backend STRIPE_PUBLISHABLE_KEY
|
||||||
const STRIPE_PUBLISHABLE_KEY = 'pk_test_51P3kdqP0gvUw6M9C7ixPQHqbPcvga4G5kAYx1h6QXQAt1psbrC2rrmOojW0fTeQzaxD1Q9RKS3zZ23MCvjjZpWLi00eCFWRHMk';
|
const STRIPE_PUBLISHABLE_KEY = 'pk_test_51P3kdqP0gvUw6M9C7ixPQHqbPcvga4G5kAYx1h6QXQAt1psbrC2rrmOojW0fTeQzaxD1Q9RKS3zZ23MCvjjZpWLi00eCFWRHMk';
|
||||||
@ -25,12 +26,18 @@ let splashHidden = false;
|
|||||||
function RootLayoutNav() {
|
function RootLayoutNav() {
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
const { isAuthenticated, isInitializing } = useAuth();
|
const { isAuthenticated, isInitializing } = useAuth();
|
||||||
|
const { cleanupBLE } = useBLE();
|
||||||
const segments = useSegments();
|
const segments = useSegments();
|
||||||
const navigationState = useRootNavigationState();
|
const navigationState = useRootNavigationState();
|
||||||
|
|
||||||
// Track if initial redirect was done
|
// Track if initial redirect was done
|
||||||
const hasInitialRedirect = useRef(false);
|
const hasInitialRedirect = useRef(false);
|
||||||
|
|
||||||
|
// Set up BLE cleanup callback for logout
|
||||||
|
useEffect(() => {
|
||||||
|
setOnLogoutBLECleanupCallback(cleanupBLE);
|
||||||
|
}, [cleanupBLE]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Wait for navigation to be ready
|
// Wait for navigation to be ready
|
||||||
if (!navigationState?.key) {
|
if (!navigationState?.key) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ interface BLEContextType {
|
|||||||
setWiFi: (deviceId: string, ssid: string, password: string) => Promise<boolean>;
|
setWiFi: (deviceId: string, ssid: string, password: string) => Promise<boolean>;
|
||||||
getCurrentWiFi: (deviceId: string) => Promise<WiFiStatus | null>;
|
getCurrentWiFi: (deviceId: string) => Promise<WiFiStatus | null>;
|
||||||
rebootDevice: (deviceId: string) => Promise<void>;
|
rebootDevice: (deviceId: string) => Promise<void>;
|
||||||
|
cleanupBLE: () => Promise<void>;
|
||||||
clearError: () => void;
|
clearError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +146,30 @@ export function BLEProvider({ children }: { children: ReactNode }) {
|
|||||||
setError(null);
|
setError(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const cleanupBLE = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
console.log('[BLEContext] Cleanup called - cleaning up all BLE connections');
|
||||||
|
|
||||||
|
// Stop any ongoing scan
|
||||||
|
if (isScanning) {
|
||||||
|
stopScan();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup via bleManager (disconnects all devices)
|
||||||
|
await bleManager.cleanup();
|
||||||
|
|
||||||
|
// Clear context state
|
||||||
|
setFoundDevices([]);
|
||||||
|
setConnectedDevices(new Set());
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
console.log('[BLEContext] Cleanup complete');
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('[BLEContext] Cleanup error:', err);
|
||||||
|
// Don't throw - we want to allow logout to proceed even if BLE cleanup fails
|
||||||
|
}
|
||||||
|
}, [isScanning, stopScan]);
|
||||||
|
|
||||||
const value: BLEContextType = {
|
const value: BLEContextType = {
|
||||||
foundDevices,
|
foundDevices,
|
||||||
isScanning,
|
isScanning,
|
||||||
@ -159,6 +184,7 @@ export function BLEProvider({ children }: { children: ReactNode }) {
|
|||||||
setWiFi,
|
setWiFi,
|
||||||
getCurrentWiFi,
|
getCurrentWiFi,
|
||||||
rebootDevice,
|
rebootDevice,
|
||||||
|
cleanupBLE,
|
||||||
clearError,
|
clearError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
112
services/__tests__/api.logout.test.ts
Normal file
112
services/__tests__/api.logout.test.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* API Logout Tests
|
||||||
|
* Tests for logout functionality including BLE cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { api, setOnLogoutBLECleanupCallback } from '../api';
|
||||||
|
import * as SecureStore from 'expo-secure-store';
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
// Mock dependencies
|
||||||
|
jest.mock('expo-secure-store');
|
||||||
|
jest.mock('@react-native-async-storage/async-storage');
|
||||||
|
|
||||||
|
describe('API logout with BLE cleanup', () => {
|
||||||
|
let bleCleanupCallback: jest.Mock;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Reset mocks
|
||||||
|
jest.clearAllMocks();
|
||||||
|
|
||||||
|
// Create mock BLE cleanup callback
|
||||||
|
bleCleanupCallback = jest.fn().mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('logout without BLE cleanup callback', () => {
|
||||||
|
it('should clear all auth tokens and data', async () => {
|
||||||
|
await api.logout();
|
||||||
|
|
||||||
|
// Verify SecureStore items are deleted
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('accessToken');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('userId');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('userEmail');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('onboardingCompleted');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('legacyAccessToken');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('privileges');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('maxRole');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('userAvatar');
|
||||||
|
|
||||||
|
// Verify AsyncStorage items are removed
|
||||||
|
expect(AsyncStorage.removeItem).toHaveBeenCalledWith('wellnuo_local_beneficiaries');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should complete logout even if no BLE callback is set', async () => {
|
||||||
|
// Should not throw
|
||||||
|
await expect(api.logout()).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('logout with BLE cleanup callback', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Set the BLE cleanup callback
|
||||||
|
setOnLogoutBLECleanupCallback(bleCleanupCallback);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call BLE cleanup callback before clearing data', async () => {
|
||||||
|
await api.logout();
|
||||||
|
|
||||||
|
// Verify BLE cleanup was called
|
||||||
|
expect(bleCleanupCallback).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
// Verify auth data was still cleared
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('accessToken');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should continue logout even if BLE cleanup fails', async () => {
|
||||||
|
// Make BLE cleanup fail
|
||||||
|
bleCleanupCallback.mockRejectedValue(new Error('BLE cleanup failed'));
|
||||||
|
|
||||||
|
// Logout should still complete
|
||||||
|
await expect(api.logout()).resolves.not.toThrow();
|
||||||
|
|
||||||
|
// Verify BLE cleanup was attempted
|
||||||
|
expect(bleCleanupCallback).toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Verify auth data was still cleared despite BLE failure
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('accessToken');
|
||||||
|
expect(SecureStore.deleteItemAsync).toHaveBeenCalledWith('userId');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log error but not throw if BLE cleanup fails', async () => {
|
||||||
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
||||||
|
bleCleanupCallback.mockRejectedValue(new Error('BLE error'));
|
||||||
|
|
||||||
|
await api.logout();
|
||||||
|
|
||||||
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||||
|
'[API] BLE cleanup failed during logout:',
|
||||||
|
expect.any(Error)
|
||||||
|
);
|
||||||
|
|
||||||
|
consoleErrorSpy.mockRestore();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('BLE cleanup callback registration', () => {
|
||||||
|
it('should allow setting BLE cleanup callback', () => {
|
||||||
|
const callback = jest.fn();
|
||||||
|
expect(() => setOnLogoutBLECleanupCallback(callback)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow replacing BLE cleanup callback', () => {
|
||||||
|
const callback1 = jest.fn().mockResolvedValue(undefined);
|
||||||
|
const callback2 = jest.fn().mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
setOnLogoutBLECleanupCallback(callback1);
|
||||||
|
setOnLogoutBLECleanupCallback(callback2);
|
||||||
|
|
||||||
|
// Only callback2 should be called
|
||||||
|
expect(callback1).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -11,6 +11,13 @@ export function setOnUnauthorizedCallback(callback: () => void) {
|
|||||||
onUnauthorizedCallback = callback;
|
onUnauthorizedCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback for BLE cleanup on logout
|
||||||
|
let onLogoutBLECleanupCallback: (() => Promise<void>) | null = null;
|
||||||
|
|
||||||
|
export function setOnLogoutBLECleanupCallback(callback: () => Promise<void>) {
|
||||||
|
onLogoutBLECleanupCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
const API_BASE_URL = 'https://eluxnetworks.net/function/well-api/api';
|
const API_BASE_URL = 'https://eluxnetworks.net/function/well-api/api';
|
||||||
const CLIENT_ID = 'MA_001';
|
const CLIENT_ID = 'MA_001';
|
||||||
|
|
||||||
@ -194,6 +201,16 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async logout(): Promise<void> {
|
async logout(): Promise<void> {
|
||||||
|
// Call BLE cleanup callback if set
|
||||||
|
if (onLogoutBLECleanupCallback) {
|
||||||
|
try {
|
||||||
|
await onLogoutBLECleanupCallback();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[API] BLE cleanup failed during logout:', error);
|
||||||
|
// Continue with logout even if BLE cleanup fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clear WellNuo API auth data
|
// Clear WellNuo API auth data
|
||||||
await SecureStore.deleteItemAsync('accessToken');
|
await SecureStore.deleteItemAsync('accessToken');
|
||||||
await SecureStore.deleteItemAsync('userId');
|
await SecureStore.deleteItemAsync('userId');
|
||||||
|
|||||||
@ -526,4 +526,33 @@ export class RealBLEManager implements IBLEManager {
|
|||||||
// Remove from connected devices
|
// Remove from connected devices
|
||||||
this.connectedDevices.delete(deviceId);
|
this.connectedDevices.delete(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup all BLE connections and state
|
||||||
|
* Should be called on app logout to properly release resources
|
||||||
|
*/
|
||||||
|
async cleanup(): Promise<void> {
|
||||||
|
console.log('[BLE] Cleanup: disconnecting all devices');
|
||||||
|
|
||||||
|
// Stop any ongoing scan
|
||||||
|
if (this.scanning) {
|
||||||
|
this.stopScan();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect all connected devices
|
||||||
|
const deviceIds = Array.from(this.connectedDevices.keys());
|
||||||
|
for (const deviceId of deviceIds) {
|
||||||
|
try {
|
||||||
|
await this.disconnectDevice(deviceId);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[BLE] Cleanup: error disconnecting device', deviceId, error);
|
||||||
|
// Continue cleanup even if one device fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the map
|
||||||
|
this.connectedDevices.clear();
|
||||||
|
|
||||||
|
console.log('[BLE] Cleanup: complete');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,4 +109,21 @@ export class MockBLEManager implements IBLEManager {
|
|||||||
await delay(500);
|
await delay(500);
|
||||||
this.connectedDevices.delete(deviceId);
|
this.connectedDevices.delete(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup all BLE connections and state
|
||||||
|
* Should be called on app logout to properly release resources
|
||||||
|
*/
|
||||||
|
async cleanup(): Promise<void> {
|
||||||
|
console.log('[MockBLE] Cleanup: disconnecting all devices');
|
||||||
|
|
||||||
|
// Disconnect all connected devices
|
||||||
|
const deviceIds = Array.from(this.connectedDevices);
|
||||||
|
for (const deviceId of deviceIds) {
|
||||||
|
await this.disconnectDevice(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connectedDevices.clear();
|
||||||
|
console.log('[MockBLE] Cleanup: complete');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
127
services/ble/__tests__/BLEManager.cleanup.test.ts
Normal file
127
services/ble/__tests__/BLEManager.cleanup.test.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* BLE Manager Cleanup Tests
|
||||||
|
* Tests for BLE cleanup functionality on logout
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RealBLEManager } from '../BLEManager';
|
||||||
|
import { MockBLEManager } from '../MockBLEManager';
|
||||||
|
|
||||||
|
describe('BLEManager cleanup', () => {
|
||||||
|
describe('RealBLEManager', () => {
|
||||||
|
let manager: RealBLEManager;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
manager = new RealBLEManager();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have cleanup method', () => {
|
||||||
|
expect(manager.cleanup).toBeDefined();
|
||||||
|
expect(typeof manager.cleanup).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not throw when cleaning up with no connections', async () => {
|
||||||
|
await expect(manager.cleanup()).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should stop scanning when cleanup is called during scan', async () => {
|
||||||
|
// Mock the scanning state
|
||||||
|
(manager as any).scanning = true;
|
||||||
|
const stopScanSpy = jest.spyOn(manager, 'stopScan');
|
||||||
|
|
||||||
|
await manager.cleanup();
|
||||||
|
|
||||||
|
expect(stopScanSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear connected devices map after cleanup', async () => {
|
||||||
|
// Simulate connected devices
|
||||||
|
const mockDevice = { id: 'device-1' } as any;
|
||||||
|
(manager as any).connectedDevices.set('device-1', mockDevice);
|
||||||
|
|
||||||
|
await manager.cleanup();
|
||||||
|
|
||||||
|
expect((manager as any).connectedDevices.size).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should attempt to disconnect all connected devices', async () => {
|
||||||
|
// Mock connected devices
|
||||||
|
const device1 = { id: 'device-1', cancelConnection: jest.fn().mockResolvedValue(undefined) } as any;
|
||||||
|
const device2 = { id: 'device-2', cancelConnection: jest.fn().mockResolvedValue(undefined) } as any;
|
||||||
|
|
||||||
|
(manager as any).connectedDevices.set('device-1', device1);
|
||||||
|
(manager as any).connectedDevices.set('device-2', device2);
|
||||||
|
|
||||||
|
await manager.cleanup();
|
||||||
|
|
||||||
|
expect(device1.cancelConnection).toHaveBeenCalled();
|
||||||
|
expect(device2.cancelConnection).toHaveBeenCalled();
|
||||||
|
expect((manager as any).connectedDevices.size).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should continue cleanup even if one device disconnection fails', async () => {
|
||||||
|
const device1 = {
|
||||||
|
id: 'device-1',
|
||||||
|
cancelConnection: jest.fn().mockRejectedValue(new Error('Connection lost'))
|
||||||
|
} as any;
|
||||||
|
const device2 = {
|
||||||
|
id: 'device-2',
|
||||||
|
cancelConnection: jest.fn().mockResolvedValue(undefined)
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
(manager as any).connectedDevices.set('device-1', device1);
|
||||||
|
(manager as any).connectedDevices.set('device-2', device2);
|
||||||
|
|
||||||
|
// Should not throw even if one device fails
|
||||||
|
await expect(manager.cleanup()).resolves.not.toThrow();
|
||||||
|
|
||||||
|
// Both should have been attempted
|
||||||
|
expect(device1.cancelConnection).toHaveBeenCalled();
|
||||||
|
expect(device2.cancelConnection).toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Map should still be cleared
|
||||||
|
expect((manager as any).connectedDevices.size).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MockBLEManager', () => {
|
||||||
|
let manager: MockBLEManager;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
manager = new MockBLEManager();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have cleanup method', () => {
|
||||||
|
expect(manager.cleanup).toBeDefined();
|
||||||
|
expect(typeof manager.cleanup).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not throw when cleaning up with no connections', async () => {
|
||||||
|
await expect(manager.cleanup()).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear connected devices set after cleanup', async () => {
|
||||||
|
// Simulate connected devices
|
||||||
|
await manager.connectDevice('mock-743');
|
||||||
|
await manager.connectDevice('mock-769');
|
||||||
|
|
||||||
|
expect((manager as any).connectedDevices.size).toBe(2);
|
||||||
|
|
||||||
|
await manager.cleanup();
|
||||||
|
|
||||||
|
expect((manager as any).connectedDevices.size).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call disconnectDevice for each connected device', async () => {
|
||||||
|
await manager.connectDevice('mock-743');
|
||||||
|
await manager.connectDevice('mock-769');
|
||||||
|
|
||||||
|
const disconnectSpy = jest.spyOn(manager, 'disconnectDevice');
|
||||||
|
|
||||||
|
await manager.cleanup();
|
||||||
|
|
||||||
|
expect(disconnectSpy).toHaveBeenCalledTimes(2);
|
||||||
|
expect(disconnectSpy).toHaveBeenCalledWith('mock-743');
|
||||||
|
expect(disconnectSpy).toHaveBeenCalledWith('mock-769');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -36,6 +36,7 @@ export const bleManager: IBLEManager = {
|
|||||||
setWiFi: (deviceId: string, ssid: string, password: string) => getBLEManager().setWiFi(deviceId, ssid, password),
|
setWiFi: (deviceId: string, ssid: string, password: string) => getBLEManager().setWiFi(deviceId, ssid, password),
|
||||||
getCurrentWiFi: (deviceId: string) => getBLEManager().getCurrentWiFi(deviceId),
|
getCurrentWiFi: (deviceId: string) => getBLEManager().getCurrentWiFi(deviceId),
|
||||||
rebootDevice: (deviceId: string) => getBLEManager().rebootDevice(deviceId),
|
rebootDevice: (deviceId: string) => getBLEManager().rebootDevice(deviceId),
|
||||||
|
cleanup: () => getBLEManager().cleanup(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Re-export types
|
// Re-export types
|
||||||
|
|||||||
@ -57,4 +57,5 @@ export interface IBLEManager {
|
|||||||
setWiFi(deviceId: string, ssid: string, password: string): Promise<boolean>;
|
setWiFi(deviceId: string, ssid: string, password: string): Promise<boolean>;
|
||||||
getCurrentWiFi(deviceId: string): Promise<WiFiStatus | null>;
|
getCurrentWiFi(deviceId: string): Promise<WiFiStatus | null>;
|
||||||
rebootDevice(deviceId: string): Promise<void>;
|
rebootDevice(deviceId: string): Promise<void>;
|
||||||
|
cleanup(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user