iotsploit-cli 0.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iotsploit_cli/__init__.py +1 -0
- iotsploit_cli/commands/__init__.py +1 -0
- iotsploit_cli/commands/base_commands.py +5 -0
- iotsploit_cli/commands/device_commands.py +536 -0
- iotsploit_cli/commands/django_commands.py +254 -0
- iotsploit_cli/commands/firmware_commands.py +213 -0
- iotsploit_cli/commands/linux_commands.py +35 -0
- iotsploit_cli/commands/network_commands.py +36 -0
- iotsploit_cli/commands/plugin_commands.py +249 -0
- iotsploit_cli/commands/system_commands.py +77 -0
- iotsploit_cli/commands/target_commands.py +246 -0
- iotsploit_cli/console.py +493 -0
- iotsploit_cli-0.0.6.dist-info/METADATA +67 -0
- iotsploit_cli-0.0.6.dist-info/RECORD +16 -0
- iotsploit_cli-0.0.6.dist-info/WHEEL +4 -0
- iotsploit_cli-0.0.6.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""IoTSploit CLI package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Commands package for SAT Shell
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import cmd2
|
|
4
|
+
from cmd2 import ansi
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from .base_commands import BaseCommands
|
|
7
|
+
from iotsploit_django.tools.monitor_mgr import SystemMonitor
|
|
8
|
+
from iotsploit_django.tools.input_mgr import Input_Mgr
|
|
9
|
+
from iotsploit_django.adapters.django.device_registry_factory import get_device_registry
|
|
10
|
+
from iotsploit_core.utils import iots_logger
|
|
11
|
+
|
|
12
|
+
logger = iots_logger.get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DeviceCommands(BaseCommands):
|
|
16
|
+
"""Device-related commands for the SAT Shell"""
|
|
17
|
+
|
|
18
|
+
@cmd2.with_category('Device Commands')
|
|
19
|
+
def do_device_info(self, arg):
|
|
20
|
+
'Show IoTSploit Host Info'
|
|
21
|
+
logger.info(ansi.style("Host Device Info:", fg=ansi.Fg.CYAN))
|
|
22
|
+
|
|
23
|
+
pi_monitor = SystemMonitor.create_monitor("raspberry_pi")
|
|
24
|
+
device_info = SystemMonitor.monitor_device(pi_monitor)
|
|
25
|
+
|
|
26
|
+
for key, value in device_info.items():
|
|
27
|
+
if isinstance(value, dict):
|
|
28
|
+
logger.info(ansi.style(f" {key}:", fg=ansi.Fg.CYAN))
|
|
29
|
+
for sub_key, sub_value in value.items():
|
|
30
|
+
logger.info(ansi.style(f" {sub_key}: {sub_value}", fg=ansi.Fg.CYAN))
|
|
31
|
+
else:
|
|
32
|
+
logger.info(ansi.style(f" {key}: {value}", fg=ansi.Fg.CYAN))
|
|
33
|
+
|
|
34
|
+
@cmd2.with_category('Device Commands')
|
|
35
|
+
def do_list_device_drivers(self, arg):
|
|
36
|
+
'List all available device plugins'
|
|
37
|
+
available_devices = self.device_driver_manager.list_drivers()
|
|
38
|
+
if available_devices:
|
|
39
|
+
logger.info(ansi.style("Available device plugins:", fg=ansi.Fg.CYAN))
|
|
40
|
+
for device in available_devices:
|
|
41
|
+
logger.info(ansi.style(f" - {device}", fg=ansi.Fg.CYAN))
|
|
42
|
+
else:
|
|
43
|
+
logger.info(ansi.style("No device plugins available.", fg=ansi.Fg.YELLOW))
|
|
44
|
+
|
|
45
|
+
do_lsdrv = do_list_device_drivers
|
|
46
|
+
|
|
47
|
+
@cmd2.with_category('Device Commands')
|
|
48
|
+
def do_list_devices(self, arg):
|
|
49
|
+
'List all devices stored in the database'
|
|
50
|
+
try:
|
|
51
|
+
devices = self.device_manager.get_all_devices()
|
|
52
|
+
|
|
53
|
+
if not devices:
|
|
54
|
+
logger.info(ansi.style("No devices found in the database.", fg=ansi.Fg.YELLOW))
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
logger.info(ansi.style("Devices in the database:", fg=ansi.Fg.CYAN))
|
|
58
|
+
for device in devices:
|
|
59
|
+
logger.info(ansi.style(f" - ID: {device['device_id']}", fg=ansi.Fg.GREEN))
|
|
60
|
+
logger.info(f" Name: {device['name']}")
|
|
61
|
+
logger.info(f" Type: {device['device_type']}")
|
|
62
|
+
|
|
63
|
+
if device['device_type'] == 'Serial':
|
|
64
|
+
logger.info(f" Port: {device['attributes'].get('port', 'N/A')}")
|
|
65
|
+
logger.info(f" Baud Rate: {device['attributes'].get('baud_rate', 'N/A')}")
|
|
66
|
+
elif device['device_type'] == 'USB':
|
|
67
|
+
logger.info(f" Vendor ID: {device['attributes'].get('vendor_id', 'N/A')}")
|
|
68
|
+
logger.info(f" Product ID: {device['attributes'].get('product_id', 'N/A')}")
|
|
69
|
+
|
|
70
|
+
logger.info(f" Attributes: {device['attributes']}")
|
|
71
|
+
logger.info(" ---")
|
|
72
|
+
|
|
73
|
+
except Exception as e:
|
|
74
|
+
logger.error(ansi.style(f"Error listing devices: {str(e)}", fg=ansi.Fg.RED))
|
|
75
|
+
|
|
76
|
+
# Alias for list_devices
|
|
77
|
+
do_lsdev = do_list_devices
|
|
78
|
+
|
|
79
|
+
@cmd2.with_category('Device Commands')
|
|
80
|
+
def do_execute_device_command(self, arg):
|
|
81
|
+
'Send a command to a device. Usage: device_command [command_string]'
|
|
82
|
+
try:
|
|
83
|
+
# Check if we need to select a device first
|
|
84
|
+
if not hasattr(self, '_current_device') or not hasattr(self, '_current_driver'):
|
|
85
|
+
logger.info(ansi.style("No device selected. Please select a device first.", fg=ansi.Fg.YELLOW))
|
|
86
|
+
if not self._select_device():
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
# Now we can be sure we have a device selected
|
|
90
|
+
if not arg:
|
|
91
|
+
# If no command provided, list available commands and let user select one
|
|
92
|
+
commands = self.device_driver_manager.get_plugin_commands(self._current_plugin)
|
|
93
|
+
if commands:
|
|
94
|
+
logger.info(ansi.style(f"\nAvailable commands for {self._current_plugin}:", fg=ansi.Fg.CYAN))
|
|
95
|
+
|
|
96
|
+
# Create list of command choices with descriptions
|
|
97
|
+
cmd_choices = [f"{cmd:<10} - {desc}" for cmd, desc in commands.items()]
|
|
98
|
+
|
|
99
|
+
# Let user select a command
|
|
100
|
+
selected = Input_Mgr.Instance().single_choice(
|
|
101
|
+
"Select command to execute",
|
|
102
|
+
cmd_choices
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Extract just the command name from the selection
|
|
106
|
+
selected_cmd = selected.split()[0].strip()
|
|
107
|
+
|
|
108
|
+
# Execute the selected command
|
|
109
|
+
self._current_driver.command(self._current_device, selected_cmd)
|
|
110
|
+
else:
|
|
111
|
+
logger.warning(ansi.style(f"No commands available for driver: {self._current_plugin}", fg=ansi.Fg.YELLOW))
|
|
112
|
+
else:
|
|
113
|
+
# Send the command to the device
|
|
114
|
+
self._current_driver.command(self._current_device, arg)
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(ansi.style(f"Error sending command: {str(e)}", fg=ansi.Fg.RED))
|
|
118
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
119
|
+
|
|
120
|
+
def _select_device(self):
|
|
121
|
+
"""Helper method to handle device selection process"""
|
|
122
|
+
try:
|
|
123
|
+
# Get available device plugins with connected devices
|
|
124
|
+
available_plugins = [
|
|
125
|
+
driver_name for driver_name, device
|
|
126
|
+
in self.connected_devices.items()
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
if not available_plugins:
|
|
130
|
+
logger.error(ansi.style("No initialized devices available", fg=ansi.Fg.RED))
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
# Let user select a plugin
|
|
134
|
+
selected_plugin = Input_Mgr.Instance().single_choice(
|
|
135
|
+
"Select device plugin",
|
|
136
|
+
available_plugins
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Get the already connected device
|
|
140
|
+
device = self.connected_devices.get(selected_plugin)
|
|
141
|
+
if not device:
|
|
142
|
+
logger.error(ansi.style(f"Device not found for {selected_plugin}", fg=ansi.Fg.RED))
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
# Store the current device and driver information
|
|
146
|
+
self._current_device = device
|
|
147
|
+
self._current_driver = self.device_driver_manager.get_driver_instance(selected_plugin)
|
|
148
|
+
self._current_plugin = selected_plugin
|
|
149
|
+
|
|
150
|
+
logger.info(ansi.style(f"Selected device: {device.name}", fg=ansi.Fg.GREEN))
|
|
151
|
+
return True
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
logger.error(ansi.style(f"Error during device selection: {str(e)}", fg=ansi.Fg.RED))
|
|
155
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
@cmd2.with_category('Device Commands')
|
|
159
|
+
def do_select_device(self, arg):
|
|
160
|
+
'Select a device for subsequent commands'
|
|
161
|
+
if self._select_device():
|
|
162
|
+
logger.info(ansi.style("Device selected successfully. Use 'execute_device_command' to send commands.", fg=ansi.Fg.GREEN))
|
|
163
|
+
else:
|
|
164
|
+
logger.error(ansi.style("Device selection failed.", fg=ansi.Fg.RED))
|
|
165
|
+
|
|
166
|
+
# Add alias for select_device
|
|
167
|
+
do_sd = do_select_device
|
|
168
|
+
|
|
169
|
+
@cmd2.with_category('Device Commands')
|
|
170
|
+
def do_switch_device(self, arg):
|
|
171
|
+
'Switch to a different device'
|
|
172
|
+
if hasattr(self, '_current_device'):
|
|
173
|
+
# Try to disconnect current device if possible
|
|
174
|
+
try:
|
|
175
|
+
if hasattr(self._current_driver, 'disconnect'):
|
|
176
|
+
self._current_driver.disconnect(self._current_device)
|
|
177
|
+
except Exception as e:
|
|
178
|
+
logger.debug(f"Error disconnecting device: {str(e)}")
|
|
179
|
+
|
|
180
|
+
delattr(self, '_current_device')
|
|
181
|
+
delattr(self, '_current_driver')
|
|
182
|
+
delattr(self, '_current_plugin')
|
|
183
|
+
|
|
184
|
+
# Immediately prompt for new device selection
|
|
185
|
+
if self._select_device():
|
|
186
|
+
logger.info(ansi.style("Successfully switched to new device.", fg=ansi.Fg.GREEN))
|
|
187
|
+
else:
|
|
188
|
+
logger.error(ansi.style("Failed to switch device.", fg=ansi.Fg.RED))
|
|
189
|
+
|
|
190
|
+
@cmd2.with_category('Device Commands')
|
|
191
|
+
def do_list_device_commands(self, arg):
|
|
192
|
+
'List available commands for a device driver'
|
|
193
|
+
try:
|
|
194
|
+
# Get available device plugins
|
|
195
|
+
available_plugins = self.device_driver_manager.list_drivers()
|
|
196
|
+
if not available_plugins:
|
|
197
|
+
logger.error(ansi.style("No device plugins available", fg=ansi.Fg.RED))
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
# Let user select a plugin
|
|
201
|
+
selected_plugin = Input_Mgr.Instance().single_choice(
|
|
202
|
+
"Select device plugin",
|
|
203
|
+
available_plugins
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Get commands for the selected plugin
|
|
207
|
+
commands = self.device_driver_manager.get_plugin_commands(selected_plugin)
|
|
208
|
+
|
|
209
|
+
if not commands:
|
|
210
|
+
logger.warning(ansi.style(f"No commands available for plugin: {selected_plugin}", fg=ansi.Fg.YELLOW))
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
# Display commands and their descriptions
|
|
214
|
+
logger.info(ansi.style(f"\nAvailable commands for {selected_plugin}:", fg=ansi.Fg.CYAN))
|
|
215
|
+
for cmd, description in commands.items():
|
|
216
|
+
logger.info(ansi.style(f" {cmd:<10}", fg=ansi.Fg.GREEN) +
|
|
217
|
+
ansi.style(f"- {description}", fg=ansi.Fg.WHITE))
|
|
218
|
+
|
|
219
|
+
except Exception as e:
|
|
220
|
+
logger.error(ansi.style(f"Error listing commands: {str(e)}", fg=ansi.Fg.RED))
|
|
221
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
222
|
+
|
|
223
|
+
# Add an alias for list_device_commands
|
|
224
|
+
do_lscmd = do_list_device_commands
|
|
225
|
+
|
|
226
|
+
@cmd2.with_category('Device Commands')
|
|
227
|
+
def do_scan_devices(self, arg):
|
|
228
|
+
'Scan for devices and show detailed information'
|
|
229
|
+
try:
|
|
230
|
+
# 获取设备注册表实例
|
|
231
|
+
device_registry = get_device_registry()
|
|
232
|
+
device_registry.initialize() # 确保已初始化
|
|
233
|
+
|
|
234
|
+
# 执行设备扫描
|
|
235
|
+
logger.info(ansi.style("Scanning for devices...", fg=ansi.Fg.CYAN))
|
|
236
|
+
discovered_devices = device_registry.scan_devices()
|
|
237
|
+
|
|
238
|
+
# 获取所有设备(包括已存储的和新发现的)
|
|
239
|
+
all_devices = device_registry.device_store.devices
|
|
240
|
+
device_sources = device_registry.device_store.device_sources # 直接获取设备来源字典
|
|
241
|
+
|
|
242
|
+
# 分类显示设备
|
|
243
|
+
static_devices = {
|
|
244
|
+
device_id: device
|
|
245
|
+
for device_id, device in all_devices.items()
|
|
246
|
+
if device_sources.get(device_id) == "static"
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
dynamic_devices = {
|
|
250
|
+
device_id: device
|
|
251
|
+
for device_id, device in all_devices.items()
|
|
252
|
+
if device_sources.get(device_id) == "dynamic"
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if static_devices:
|
|
256
|
+
logger.info(ansi.style("\nConfigured Devices:", fg=ansi.Fg.BLUE))
|
|
257
|
+
self._display_devices(static_devices, device_sources)
|
|
258
|
+
|
|
259
|
+
if dynamic_devices:
|
|
260
|
+
logger.info(ansi.style("\nDynamically Discovered Devices:", fg=ansi.Fg.GREEN))
|
|
261
|
+
self._display_devices(dynamic_devices, device_sources)
|
|
262
|
+
|
|
263
|
+
if not static_devices and not dynamic_devices:
|
|
264
|
+
logger.info(ansi.style("No devices found.", fg=ansi.Fg.YELLOW))
|
|
265
|
+
|
|
266
|
+
except Exception as e:
|
|
267
|
+
logger.error(ansi.style(f"Error scanning devices: {str(e)}", fg=ansi.Fg.RED))
|
|
268
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
269
|
+
|
|
270
|
+
def _display_devices(self, devices: Dict, sources: Dict):
|
|
271
|
+
"""Helper method to display device information"""
|
|
272
|
+
for device_id, device in devices.items():
|
|
273
|
+
source = sources.get(device_id, "unknown")
|
|
274
|
+
source_color = ansi.Fg.GREEN if source == "dynamic" else ansi.Fg.BLUE
|
|
275
|
+
|
|
276
|
+
# Only display ID, Name, and Source
|
|
277
|
+
logger.info(ansi.style(f"\n Device ID: {device_id}", fg=ansi.Fg.CYAN))
|
|
278
|
+
logger.info(ansi.style(f" Source: {source}", fg=source_color))
|
|
279
|
+
logger.info(f" Name: {device.name}")
|
|
280
|
+
logger.info(" " + "-" * 40) # Separator line
|
|
281
|
+
|
|
282
|
+
# 添加命令别名
|
|
283
|
+
do_scan = do_scan_devices
|
|
284
|
+
|
|
285
|
+
# Add alias for execute_device_command
|
|
286
|
+
do_dc = do_execute_device_command
|
|
287
|
+
|
|
288
|
+
@cmd2.with_category('Device Commands')
|
|
289
|
+
def do_initialize_devices(self, arg):
|
|
290
|
+
'Auto-initialize all available devices'
|
|
291
|
+
logger.info("Starting device initialization...")
|
|
292
|
+
self._auto_initialize_devices()
|
|
293
|
+
|
|
294
|
+
# Add alias for initialize_devices
|
|
295
|
+
do_initdev = do_initialize_devices
|
|
296
|
+
|
|
297
|
+
@cmd2.with_category('Device Commands')
|
|
298
|
+
def do_get_driver_states(self, arg):
|
|
299
|
+
'Show enabled/disabled state of all device drivers'
|
|
300
|
+
try:
|
|
301
|
+
driver_states = self.device_driver_manager.get_driver_states()
|
|
302
|
+
|
|
303
|
+
if not driver_states:
|
|
304
|
+
logger.info(ansi.style("No device drivers found.", fg=ansi.Fg.YELLOW))
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
logger.info(ansi.style("\nDevice Driver States:", fg=ansi.Fg.CYAN))
|
|
308
|
+
|
|
309
|
+
# Calculate column widths for alignment
|
|
310
|
+
max_name_len = max(len(name) for name in driver_states.keys())
|
|
311
|
+
|
|
312
|
+
# Display stats
|
|
313
|
+
enabled_count = sum(1 for state in driver_states.values() if state.get("enabled", True))
|
|
314
|
+
disabled_count = len(driver_states) - enabled_count
|
|
315
|
+
|
|
316
|
+
logger.info(ansi.style(f"Total: {len(driver_states)} | Enabled: {enabled_count} | Disabled: {disabled_count}\n", fg=ansi.Fg.BLUE))
|
|
317
|
+
|
|
318
|
+
# Display detailed info for each driver
|
|
319
|
+
for driver_name, state in driver_states.items():
|
|
320
|
+
enabled = state.get("enabled", True)
|
|
321
|
+
status_color = ansi.Fg.GREEN if enabled else ansi.Fg.RED
|
|
322
|
+
status_text = "Enabled" if enabled else "Disabled"
|
|
323
|
+
|
|
324
|
+
logger.info(ansi.style(f"{driver_name:<{max_name_len}} : ", fg=ansi.Fg.CYAN) +
|
|
325
|
+
ansi.style(f"{status_text}", fg=status_color))
|
|
326
|
+
|
|
327
|
+
# Show description if available
|
|
328
|
+
description = state.get("description")
|
|
329
|
+
if description:
|
|
330
|
+
logger.info(f" Description: {description}")
|
|
331
|
+
|
|
332
|
+
# Show last update time if available
|
|
333
|
+
last_updated = state.get("last_updated")
|
|
334
|
+
if last_updated:
|
|
335
|
+
logger.info(f" Last updated: {last_updated}")
|
|
336
|
+
|
|
337
|
+
logger.info("") # Empty line between drivers
|
|
338
|
+
|
|
339
|
+
except Exception as e:
|
|
340
|
+
logger.error(ansi.style(f"Error getting driver states: {str(e)}", fg=ansi.Fg.RED))
|
|
341
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
342
|
+
|
|
343
|
+
# Add alias for get_driver_states
|
|
344
|
+
do_gds = do_get_driver_states
|
|
345
|
+
|
|
346
|
+
@cmd2.with_category('Device Commands')
|
|
347
|
+
def do_enable_driver(self, arg):
|
|
348
|
+
'Enable a device driver. Usage: enable_driver [driver_name]'
|
|
349
|
+
try:
|
|
350
|
+
# Get list of all drivers
|
|
351
|
+
all_drivers = self.device_driver_manager.list_drivers()
|
|
352
|
+
|
|
353
|
+
if not all_drivers:
|
|
354
|
+
logger.warning(ansi.style("No device drivers available.", fg=ansi.Fg.YELLOW))
|
|
355
|
+
return
|
|
356
|
+
|
|
357
|
+
# If driver name is provided as an argument, use it
|
|
358
|
+
# Otherwise, let user select from available drivers
|
|
359
|
+
driver_name = arg.strip() if arg else None
|
|
360
|
+
|
|
361
|
+
if not driver_name:
|
|
362
|
+
# Get current states to show which are disabled
|
|
363
|
+
states = self.device_driver_manager.get_driver_states()
|
|
364
|
+
|
|
365
|
+
# Create list with status indicators
|
|
366
|
+
driver_choices = []
|
|
367
|
+
for drv in all_drivers:
|
|
368
|
+
status = states.get(drv, {}).get("enabled", True)
|
|
369
|
+
status_text = "Enabled" if status else "Disabled"
|
|
370
|
+
driver_choices.append(f"{drv} [{status_text}]")
|
|
371
|
+
|
|
372
|
+
# Let user select a driver
|
|
373
|
+
selected = Input_Mgr.Instance().single_choice(
|
|
374
|
+
"Select driver to enable",
|
|
375
|
+
driver_choices
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Extract driver name from selection
|
|
379
|
+
driver_name = selected.split()[0]
|
|
380
|
+
|
|
381
|
+
# Ask for optional description
|
|
382
|
+
description = Input_Mgr.Instance().string_input(
|
|
383
|
+
"Enter reason for enabling (optional)"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
# Enable the driver - only pass description if it's not empty
|
|
387
|
+
if description.strip():
|
|
388
|
+
result = self.device_driver_manager.enable_driver(driver_name, description)
|
|
389
|
+
else:
|
|
390
|
+
result = self.device_driver_manager.enable_driver(driver_name)
|
|
391
|
+
|
|
392
|
+
if result.get("status") == "success":
|
|
393
|
+
logger.info(ansi.style(f"Successfully enabled driver: {driver_name}", fg=ansi.Fg.GREEN))
|
|
394
|
+
else:
|
|
395
|
+
logger.error(ansi.style(f"Failed to enable driver: {result.get('message', 'Unknown error')}", fg=ansi.Fg.RED))
|
|
396
|
+
|
|
397
|
+
except Exception as e:
|
|
398
|
+
logger.error(ansi.style(f"Error enabling driver: {str(e)}", fg=ansi.Fg.RED))
|
|
399
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
400
|
+
|
|
401
|
+
# Add alias for enable_driver
|
|
402
|
+
do_ed = do_enable_driver
|
|
403
|
+
|
|
404
|
+
@cmd2.with_category('Device Commands')
|
|
405
|
+
def do_disable_driver(self, arg):
|
|
406
|
+
'Disable a device driver. Usage: disable_driver [driver_name]'
|
|
407
|
+
try:
|
|
408
|
+
# Get list of all drivers
|
|
409
|
+
all_drivers = self.device_driver_manager.list_drivers()
|
|
410
|
+
|
|
411
|
+
if not all_drivers:
|
|
412
|
+
logger.warning(ansi.style("No device drivers available.", fg=ansi.Fg.YELLOW))
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
# If driver name is provided as an argument, use it
|
|
416
|
+
# Otherwise, let user select from available drivers
|
|
417
|
+
driver_name = arg.strip() if arg else None
|
|
418
|
+
|
|
419
|
+
if not driver_name:
|
|
420
|
+
# Get current states to show which are enabled
|
|
421
|
+
states = self.device_driver_manager.get_driver_states()
|
|
422
|
+
|
|
423
|
+
# Create list with status indicators
|
|
424
|
+
driver_choices = []
|
|
425
|
+
for drv in all_drivers:
|
|
426
|
+
status = states.get(drv, {}).get("enabled", True)
|
|
427
|
+
status_text = "Enabled" if status else "Disabled"
|
|
428
|
+
driver_choices.append(f"{drv} [{status_text}]")
|
|
429
|
+
|
|
430
|
+
# Let user select a driver
|
|
431
|
+
selected = Input_Mgr.Instance().single_choice(
|
|
432
|
+
"Select driver to disable",
|
|
433
|
+
driver_choices
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Extract driver name from selection
|
|
437
|
+
driver_name = selected.split()[0]
|
|
438
|
+
|
|
439
|
+
# Warning and confirmation before disabling
|
|
440
|
+
logger.warning(ansi.style("Warning: Disabling a driver will close all connected devices for that driver!", fg=ansi.Fg.YELLOW))
|
|
441
|
+
|
|
442
|
+
confirm = Input_Mgr.Instance().yes_no_input(
|
|
443
|
+
f"Are you sure you want to disable driver '{driver_name}'?",
|
|
444
|
+
default=False
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
if not confirm:
|
|
448
|
+
logger.info("Operation cancelled.")
|
|
449
|
+
return
|
|
450
|
+
|
|
451
|
+
# Ask for optional description
|
|
452
|
+
description = Input_Mgr.Instance().string_input("Enter reason for disabling (optional)")
|
|
453
|
+
|
|
454
|
+
# Disable the driver
|
|
455
|
+
result = self.device_driver_manager.disable_driver(driver_name, description or None)
|
|
456
|
+
|
|
457
|
+
if result.get("status") == "success":
|
|
458
|
+
logger.info(ansi.style(f"Successfully disabled driver: {driver_name}", fg=ansi.Fg.GREEN))
|
|
459
|
+
|
|
460
|
+
# Report on closed devices
|
|
461
|
+
closed_devices = result.get("closed_devices", [])
|
|
462
|
+
if closed_devices:
|
|
463
|
+
logger.info(f"Closed {len(closed_devices)} device(s): {', '.join(closed_devices)}")
|
|
464
|
+
|
|
465
|
+
# Remove from connected_devices if needed
|
|
466
|
+
if driver_name in self.connected_devices:
|
|
467
|
+
del self.connected_devices[driver_name]
|
|
468
|
+
else:
|
|
469
|
+
logger.error(ansi.style(f"Failed to disable driver: {result.get('message', 'Unknown error')}", fg=ansi.Fg.RED))
|
|
470
|
+
|
|
471
|
+
except Exception as e:
|
|
472
|
+
logger.error(ansi.style(f"Error disabling driver: {str(e)}", fg=ansi.Fg.RED))
|
|
473
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
474
|
+
|
|
475
|
+
# Add alias for disable_driver
|
|
476
|
+
do_dd = do_disable_driver
|
|
477
|
+
|
|
478
|
+
@cmd2.with_category('Device Commands')
|
|
479
|
+
def do_device_import(self, arg):
|
|
480
|
+
'''Import devices from a JSON file into the database.
|
|
481
|
+
|
|
482
|
+
Usage: device_import <json_file_path>
|
|
483
|
+
|
|
484
|
+
Example: device_import conf/devices.json
|
|
485
|
+
|
|
486
|
+
JSON file format:
|
|
487
|
+
{
|
|
488
|
+
"devices": [
|
|
489
|
+
{
|
|
490
|
+
"device_id": "serial_001",
|
|
491
|
+
"name": "Serial Device",
|
|
492
|
+
"device_type": "Serial",
|
|
493
|
+
"port": "/dev/ttyUSB0",
|
|
494
|
+
"baud_rate": 115200
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
"device_id": "usb_001",
|
|
498
|
+
"name": "USB Device",
|
|
499
|
+
"device_type": "USB",
|
|
500
|
+
"vendor_id": "1234",
|
|
501
|
+
"product_id": "5678"
|
|
502
|
+
}
|
|
503
|
+
]
|
|
504
|
+
}
|
|
505
|
+
'''
|
|
506
|
+
import os
|
|
507
|
+
import warnings
|
|
508
|
+
|
|
509
|
+
if not arg:
|
|
510
|
+
logger.error(ansi.style("Usage: device_import <json_file_path>", fg=ansi.Fg.RED))
|
|
511
|
+
logger.info(ansi.style("Example: device_import conf/devices.json", fg=ansi.Fg.CYAN))
|
|
512
|
+
return
|
|
513
|
+
|
|
514
|
+
json_file_path = arg.strip()
|
|
515
|
+
|
|
516
|
+
if not os.path.exists(json_file_path):
|
|
517
|
+
logger.error(ansi.style(f"File not found: {json_file_path}", fg=ansi.Fg.RED))
|
|
518
|
+
return
|
|
519
|
+
|
|
520
|
+
try:
|
|
521
|
+
logger.info(ansi.style(f"Importing devices from: {json_file_path}", fg=ansi.Fg.CYAN))
|
|
522
|
+
|
|
523
|
+
# Suppress deprecation warning since we're intentionally using this for import
|
|
524
|
+
with warnings.catch_warnings():
|
|
525
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
526
|
+
self.device_manager.parse_and_set_device_from_json(json_file_path)
|
|
527
|
+
|
|
528
|
+
logger.info(ansi.style("Device import completed successfully!", fg=ansi.Fg.GREEN))
|
|
529
|
+
logger.info(ansi.style("Use 'list_devices' or 'lsdev' to view imported devices.", fg=ansi.Fg.CYAN))
|
|
530
|
+
|
|
531
|
+
except Exception as e:
|
|
532
|
+
logger.error(ansi.style(f"Error importing devices: {str(e)}", fg=ansi.Fg.RED))
|
|
533
|
+
logger.debug("Detailed error:", exc_info=True)
|
|
534
|
+
|
|
535
|
+
# Add alias for device_import
|
|
536
|
+
do_dimport = do_device_import
|