-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice_manager.py
More file actions
232 lines (194 loc) · 7.16 KB
/
device_manager.py
File metadata and controls
232 lines (194 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
"""
Device Manager for Instagram Bot
Handles both USB (physical) and network (emulator) device connections
"""
import os
import subprocess
import sys
from typing import Literal, Optional
DeviceType = Literal["usb", "network"]
class DeviceManager:
"""Manages ADB device connections for both USB and network devices"""
def __init__(self, device_id: str):
self.device_id = device_id
self.device_type = self.detect_device_type(device_id)
@staticmethod
def detect_device_type(device_id: str) -> DeviceType:
"""
Detect if device is USB or network based on device ID format
USB format: alphanumeric (e.g., fbc9d1f30eb2)
Network format: IP:port (e.g., 127.0.0.1:21533)
"""
if ":" in device_id and "." in device_id:
return "network"
return "usb"
def ensure_connected(self, logger=None) -> bool:
"""
Ensure device is connected
- USB devices: Just check connection
- Network devices: Attempt connection if not connected
Returns True if device is connected, False otherwise
"""
def log(msg: str, level: str = "INFO"):
if logger:
getattr(logger, level.lower())(msg)
else:
print(f"{level} | {msg}")
# Check if device is already connected
if self.is_device_connected():
log(f"Device {self.device_id} is already connected ({self.device_type})")
return True
# For network devices, attempt connection
if self.device_type == "network":
log(f"Network device {self.device_id} not found, attempting connection...")
return self.connect_network_device(logger)
# For USB devices, can't auto-connect
log(f"USB device {self.device_id} not found. Please check USB connection.", "ERROR")
return False
def is_device_connected(self) -> bool:
"""Check if device is in adb devices list"""
try:
result = subprocess.run(
["adb", "devices"],
capture_output=True,
text=True,
timeout=10
)
return self.device_id in result.stdout
except Exception:
return False
def connect_network_device(self, logger=None) -> bool:
"""Connect to network device (emulator)"""
def log(msg: str, level: str = "INFO"):
if logger:
getattr(logger, level.lower())(msg)
else:
print(f"{level} | {msg}")
try:
log(f"Connecting to network device: {self.device_id}")
result = subprocess.run(
["adb", "connect", self.device_id],
capture_output=True,
text=True,
timeout=15
)
if "connected" in result.stdout.lower() or "already connected" in result.stdout.lower():
log(f"Successfully connected to {self.device_id}")
return True
else:
log(f"Failed to connect: {result.stdout.strip()}", "ERROR")
return False
except subprocess.TimeoutExpired:
log(f"Connection timeout for {self.device_id}", "ERROR")
return False
except Exception as e:
log(f"Error connecting to device: {e}", "ERROR")
return False
def disconnect_network_device(self, logger=None) -> bool:
"""Disconnect network device (emulator)"""
if self.device_type != "network":
return True
def log(msg: str, level: str = "INFO"):
if logger:
getattr(logger, level.lower())(msg)
else:
print(f"{level} | {msg}")
try:
log(f"Disconnecting network device: {self.device_id}")
result = subprocess.run(
["adb", "disconnect", self.device_id],
capture_output=True,
text=True,
timeout=10
)
log(f"Disconnect result: {result.stdout.strip()}")
return True
except Exception as e:
log(f"Error disconnecting device: {e}", "WARNING")
return False
@staticmethod
def list_connected_devices() -> list[tuple[str, DeviceType]]:
"""
List all connected devices with their types
Returns list of (device_id, device_type) tuples
"""
try:
result = subprocess.run(
["adb", "devices"],
capture_output=True,
text=True,
timeout=10
)
devices = []
for line in result.stdout.split("\n")[1:]: # Skip header
if "\tdevice" in line:
device_id = line.split("\t")[0].strip()
device_type = DeviceManager.detect_device_type(device_id)
devices.append((device_id, device_type))
return devices
except Exception:
return []
@staticmethod
def check_adb_available() -> bool:
"""Check if ADB is installed and accessible"""
try:
result = subprocess.run(
["adb", "version"],
capture_output=True,
timeout=5
)
return result.returncode == 0
except Exception:
return False
def load_device_from_env(account_suffix: str = "") -> Optional[str]:
"""
Load device ID from environment variables
Args:
account_suffix: Optional suffix for multi-account (e.g., "_A", "_B")
Returns:
Device ID or None if not found
Priority:
1. DEVICE_{suffix} (e.g., DEVICE_A)
2. DEVICE_ID_{suffix} (legacy)
3. DEVICE (default)
"""
from dotenv import load_dotenv
load_dotenv()
if account_suffix:
# Try new format first
device = os.getenv(f"DEVICE{account_suffix}")
if device:
return device
# Try legacy format
device = os.getenv(f"DEVICE_ID{account_suffix}")
if device:
return device
# Fallback to default DEVICE
return os.getenv("DEVICE")
if __name__ == "__main__":
"""Test device manager functionality"""
print("=== Device Manager Test ===\n")
# Check ADB
if not DeviceManager.check_adb_available():
print("ERROR: ADB is not installed or not in PATH")
sys.exit(1)
print("[OK] ADB is available\n")
# List connected devices
devices = DeviceManager.list_connected_devices()
print(f"Connected devices: {len(devices)}")
for device_id, device_type in devices:
print(f" - {device_id} ({device_type})")
print()
# Test device from .env
device_id = load_device_from_env()
if device_id:
print(f"Device from .env: {device_id}")
dm = DeviceManager(device_id)
print(f" Type: {dm.device_type}")
print(f" Connected: {dm.is_device_connected()}")
if not dm.is_device_connected():
print(f" Attempting connection...")
success = dm.ensure_connected()
print(f" Result: {'[OK] Success' if success else '[FAILED]'}")
else:
print("No DEVICE found in .env")