iotsploit-drivers 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.
@@ -0,0 +1 @@
1
+ """Official IoTSploit device driver package."""
File without changes
@@ -0,0 +1,508 @@
1
+ import logging
2
+ from typing import Optional, Dict, List
3
+ from iotsploit_core.domain.device import Device, DeviceType, SerialDevice
4
+ from iotsploit_core.core.base_plugin import BaseDeviceDriver
5
+ from .scpi_client import ScpiClient, ScpiSerialTransport
6
+ from iotsploit_core.core.tool_service import get_firmware_service
7
+ import time
8
+ import serial.tools.list_ports
9
+ from pathlib import Path
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class ESP32Driver(BaseDeviceDriver):
14
+ def __init__(self):
15
+ super().__init__()
16
+ self.transport = None
17
+ self.client = None
18
+ # Initialize firmware tool service
19
+ self.firmware_service = get_firmware_service()
20
+ # Define supported commands
21
+ self.supported_commands = {
22
+ "scan_wifi": "Scan for available WiFi networks",
23
+ "get_version": "Get device version",
24
+ "get_status": "Get device status",
25
+ "reset": "Reset the ESP32 device",
26
+ "start_wifi_monitor": "Start continuous WiFi monitoring",
27
+ "stop_wifi_monitor": "Stop continuous WiFi monitoring",
28
+ "flash_firmware": "Flash firmware to ESP32-S3 device",
29
+ "erase_flash": "Erase ESP32-S3 flash memory",
30
+ "get_chip_info": "Get ESP32-S3 chip information"
31
+ }
32
+
33
+ def get_auth_mode_str(self, auth_mode):
34
+ """Convert auth mode number to string description."""
35
+ auth_modes = {
36
+ 0: "OPEN",
37
+ 1: "WEP",
38
+ 2: "WPA_PSK",
39
+ 3: "WPA2_PSK",
40
+ 4: "WPA_WPA2_PSK",
41
+ 5: "WPA2_ENTERPRISE",
42
+ 6: "WPA3_PSK",
43
+ 7: "WPA2_WPA3_PSK"
44
+ }
45
+ return auth_modes.get(int(auth_mode), f"UNKNOWN({auth_mode})")
46
+
47
+ def _scan_wifi_networks(self) -> List[Dict]:
48
+ """Scan for WiFi networks and return formatted results."""
49
+ ap_list = self.client.query("WIFi:AP:LIST?", timeout=10.0)
50
+ if not ap_list or ap_list == "NO_AP_FOUND" or ap_list.startswith("ERROR"):
51
+ logger.info("No WiFi networks found or error response received from client")
52
+ return []
53
+
54
+ result = []
55
+ ap_entries = [ap for ap in ap_list.strip().split(';') if ap]
56
+ for ap in ap_entries:
57
+ try:
58
+ ssid, rssi, channel, auth = ap.split(',')
59
+ security = self.get_auth_mode_str(auth)
60
+ logger.info("Found WiFi Network: SSID: %s, RSSI: %s dBm, Channel: %s, Security: %s",
61
+ ssid, rssi, channel, security)
62
+ result.append({
63
+ "ssid": ssid,
64
+ "rssi": f"{rssi} dBm",
65
+ "channel": channel,
66
+ "security": security
67
+ })
68
+ except ValueError as e:
69
+ logger.error("Error parsing AP entry: %s - %s", ap, str(e))
70
+ return result
71
+
72
+ def _scan_impl(self) -> List[Device]:
73
+ """
74
+ Scan for available ESP32-S3 devices by checking all CP210x devices.
75
+ Returns the device with correct version number.
76
+ """
77
+ devices = []
78
+ # Find all CP210x devices
79
+ for port in serial.tools.list_ports.comports():
80
+ if "CP210" in port.description:
81
+ logger.info(f"Found CP210x device at {port.device}")
82
+ try:
83
+ # Try to connect and check version
84
+ temp_transport = ScpiSerialTransport(
85
+ port=port.device,
86
+ baudrate=115200,
87
+ timeout=1.0
88
+ )
89
+ temp_client = ScpiClient(temp_transport)
90
+ temp_client.connect()
91
+
92
+ try:
93
+ version = temp_client.get_version()
94
+ if version.strip() == "1.0.0":
95
+ logger.info(f"Found ESP32-S3 device at {port.device} with correct version")
96
+ devices.append(SerialDevice(
97
+ device_id="esp32s3_001",
98
+ name="ESP32-S3",
99
+ port=port.device,
100
+ baud_rate=115200,
101
+ attributes={
102
+ 'description': 'ESP32-S3 Development Board',
103
+ 'serial_number': port.serial_number,
104
+ 'chip': 'esp32s3'
105
+ }
106
+ ))
107
+ except Exception as e:
108
+ logger.debug(f"Not an ESP32-S3 device at {port.device}: {e}")
109
+
110
+ temp_client.close()
111
+ except Exception as e:
112
+ logger.debug(f"Failed to check device at {port.device}: {e}")
113
+ continue
114
+
115
+ if not devices:
116
+ logger.warning("No ESP32-S3 devices found")
117
+ return devices
118
+
119
+ def _initialize_impl(self, device: SerialDevice) -> bool:
120
+ """
121
+ Initialize the ESP32-S3 device using SCPI over serial.
122
+ """
123
+ if device.device_type != DeviceType.Serial:
124
+ raise ValueError("This plugin only supports serial devices")
125
+
126
+ logger.info(f"Initializing ESP32-S3 device on port {device.port}")
127
+ try:
128
+ self.transport = ScpiSerialTransport(
129
+ port=device.port,
130
+ baudrate=device.baud_rate,
131
+ timeout=1.0
132
+ )
133
+ self.client = ScpiClient(self.transport)
134
+ logger.info("ESP32-S3 device initialized successfully")
135
+ return True
136
+ except Exception as e:
137
+ logger.error(f"Failed to initialize ESP32-S3 device: {e}")
138
+ raise
139
+
140
+ def _connect_impl(self, device: SerialDevice) -> bool:
141
+ """
142
+ Connect to the ESP32-S3 device using SCPI client.
143
+ """
144
+ if not self.client:
145
+ logger.error("Device not initialized. Please initialize first.")
146
+ raise RuntimeError("Device not initialized")
147
+
148
+ try:
149
+ self.client.connect()
150
+ version = self.client.get_version()
151
+ status = self.client.get_status()
152
+ logger.info(f"ESP32-S3 device connected successfully. Version: {version}, Status: {status}")
153
+ return True
154
+ except Exception as e:
155
+ logger.error(f"Failed to connect to ESP32-S3 device: {e}")
156
+ raise
157
+
158
+ def _acquisition_loop(self):
159
+ """Continuous WiFi scanning loop."""
160
+ while self.is_acquiring.is_set():
161
+ try:
162
+ wifi_list = self._scan_wifi_networks()
163
+ # Send data through stream manager
164
+ if wifi_list:
165
+ for device_id in self._devices:
166
+ self.stream_wrapper.broadcast_data(device_id, {
167
+ "type": "wifi_scan",
168
+ "timestamp": time.time(),
169
+ "data": wifi_list
170
+ })
171
+ except Exception as e:
172
+ logger.error(f"Error in WiFi scanning loop: {e}")
173
+ time.sleep(5) # Scan every 5 seconds
174
+
175
+ # --- Optimized command dispatch below ---
176
+
177
+ def _handle_scan_wifi(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
178
+ wifi_list = self._scan_wifi_networks()
179
+ return {
180
+ "networks": wifi_list
181
+ }
182
+
183
+ def _handle_start_wifi_monitor(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
184
+ if not self.is_acquiring.is_set():
185
+ self.start_streaming(device)
186
+ return "WiFi monitoring started"
187
+
188
+ def _handle_stop_wifi_monitor(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
189
+ if self.is_acquiring.is_set():
190
+ self.stop_streaming(device)
191
+ return "WiFi monitoring stopped"
192
+
193
+ def _handle_get_version(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
194
+ return self.client.get_version()
195
+
196
+ def _handle_get_status(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
197
+ return self.client.get_status()
198
+
199
+ def _handle_reset(self, device: SerialDevice, args: Optional[Dict] = None) -> str:
200
+ self.client.send_command("*RST")
201
+ return "Device reset successfully"
202
+
203
+ def _handle_flash_firmware(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
204
+ """
205
+ Flash firmware to ESP32-S3 device using ESP32Programmer
206
+ """
207
+ try:
208
+ # Check if esptool is available
209
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
210
+ error_msg = "esptool is not available. Please install it: pip install esptool"
211
+ logger.error(error_msg)
212
+ return {"status": "error", "message": error_msg}
213
+
214
+ # Get firmware name from args or use default
215
+ firmware_name = args.get('firmware_name', 'esp32s3_wifi_penetration_tool') if args else 'esp32s3_wifi_penetration_tool'
216
+
217
+ # Try to get firmware from the centralized manifest
218
+ firmware_info = self.firmware_service.get_firmware_info(firmware_name)
219
+
220
+ if not firmware_info:
221
+ error_msg = f"Firmware '{firmware_name}' not found in manifest"
222
+ logger.error(error_msg)
223
+ return {"status": "error", "message": error_msg}
224
+
225
+ # Get flash options from firmware config
226
+ flash_options = firmware_info.get('flash_options', {})
227
+
228
+ # Get port, chip, and baud from args or flash options or defaults
229
+ port = args.get('port') if args else None
230
+ port = port or flash_options.get('port', '/dev/ttyACM2')
231
+
232
+ chip = args.get('chip') if args else None
233
+ chip = chip or flash_options.get('chip', 'esp32s3')
234
+
235
+ baud = args.get('baud') if args else None
236
+ baud = baud or flash_options.get('baud', '460800')
237
+
238
+ # Check if this firmware has a files array for multi-file flashing
239
+ if 'files' in flash_options:
240
+ # Use the files from the firmware configuration
241
+ files = flash_options['files']
242
+ logger.info(f"Using multi-file configuration from manifest: {len(files)} files")
243
+
244
+ # Verify all files exist
245
+ for file_entry in files:
246
+ file_path = file_entry['path']
247
+ if not Path(file_path).exists():
248
+ error_msg = f"Firmware file not found: {file_path}"
249
+ logger.error(error_msg)
250
+ return {"status": "error", "message": error_msg}
251
+
252
+ logger.info(f"Flashing ESP32-S3 firmware '{firmware_name}' to {port}...")
253
+ logger.info(f"Files to flash: {len(files)} files")
254
+
255
+ # Flash all files in one operation using the ESP32 programmer
256
+ result = self.firmware_service.esp32.flash_multi(
257
+ port=port,
258
+ files=files,
259
+ chip=chip,
260
+ baud=baud,
261
+ flash_mode=flash_options.get('flash_mode', 'dio'),
262
+ flash_freq=flash_options.get('flash_freq', '80m'),
263
+ flash_size=flash_options.get('flash_size', '2MB')
264
+ )
265
+ else:
266
+ # Single file flashing
267
+ firmware_path = firmware_info['path']
268
+ if not Path(firmware_path).exists():
269
+ error_msg = f"Firmware file not found: {firmware_path}"
270
+ logger.error(error_msg)
271
+ return {"status": "error", "message": error_msg}
272
+
273
+ logger.info(f"Flashing ESP32-S3 single firmware '{firmware_name}' to {port}...")
274
+
275
+ result = self.firmware_service.esp32.flash_single(
276
+ port=port,
277
+ firmware_path=firmware_path,
278
+ address=flash_options.get('address', '0x10000'),
279
+ chip=chip,
280
+ baud=baud
281
+ )
282
+
283
+ if result.success:
284
+ success_msg = f"ESP32-S3 firmware '{firmware_name}' flashed successfully in {result.execution_time:.2f}s"
285
+ logger.info(success_msg)
286
+ return {
287
+ "status": "success",
288
+ "message": success_msg,
289
+ "execution_time": result.execution_time,
290
+ "firmware_name": firmware_name
291
+ }
292
+ else:
293
+ error_msg = f"Failed to flash firmware '{firmware_name}': {result.stderr or 'Unknown error'}"
294
+ logger.error(error_msg)
295
+ return {
296
+ "status": "error",
297
+ "message": error_msg,
298
+ "return_code": result.return_code,
299
+ "stderr": result.stderr
300
+ }
301
+
302
+ except Exception as e:
303
+ error_msg = f"Error flashing ESP32-S3 firmware: {str(e)}"
304
+ logger.error(error_msg)
305
+ return {"status": "error", "message": error_msg}
306
+
307
+ def _handle_erase_flash(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
308
+ """
309
+ Erase ESP32-S3 flash memory using ESP32Programmer
310
+ """
311
+ try:
312
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
313
+ error_msg = "esptool is not available. Please install it: pip install esptool"
314
+ logger.error(error_msg)
315
+ return {"status": "error", "message": error_msg}
316
+
317
+ # Get port from args or use default
318
+ port = args.get('port', '/dev/ttyACM2') if args else '/dev/ttyACM2'
319
+ chip = args.get('chip', 'esp32s3') if args else 'esp32s3'
320
+ baud = args.get('baud', '460800') if args else '460800'
321
+
322
+ logger.info(f"Erasing ESP32-S3 flash on {port}...")
323
+
324
+ result = self.firmware_service.esp32.erase_flash(
325
+ port=port,
326
+ chip=chip,
327
+ baud=baud
328
+ )
329
+
330
+ if result.success:
331
+ success_msg = f"ESP32-S3 flash erased successfully in {result.execution_time:.2f}s"
332
+ logger.info(success_msg)
333
+ return {
334
+ "status": "success",
335
+ "message": success_msg,
336
+ "execution_time": result.execution_time
337
+ }
338
+ else:
339
+ error_msg = f"Failed to erase flash: {result.stderr or 'Unknown error'}"
340
+ logger.error(error_msg)
341
+ return {
342
+ "status": "error",
343
+ "message": error_msg,
344
+ "return_code": result.return_code,
345
+ "stderr": result.stderr
346
+ }
347
+
348
+ except Exception as e:
349
+ error_msg = f"Error erasing ESP32-S3 flash: {str(e)}"
350
+ logger.error(error_msg)
351
+ return {"status": "error", "message": error_msg}
352
+
353
+ def _handle_get_chip_info(self, device: SerialDevice, args: Optional[Dict] = None) -> Dict:
354
+ """
355
+ Get ESP32-S3 chip information using ESP32Programmer
356
+ """
357
+ try:
358
+ if not self.firmware_service.esp32.is_tool_available('esptool'):
359
+ error_msg = "esptool is not available. Please install it: pip install esptool"
360
+ logger.error(error_msg)
361
+ return {"status": "error", "message": error_msg}
362
+
363
+ # Get port from args or use default
364
+ port = args.get('port', '/dev/ttyACM2') if args else '/dev/ttyACM2'
365
+ baud = args.get('baud', '460800') if args else '460800'
366
+
367
+ logger.info(f"Getting ESP32-S3 chip info from {port}...")
368
+
369
+ result = self.firmware_service.esp32.get_chip_info(
370
+ port=port,
371
+ baud=baud
372
+ )
373
+
374
+ if result.success:
375
+ success_msg = f"ESP32-S3 chip info retrieved successfully"
376
+ logger.info(success_msg)
377
+ return {
378
+ "status": "success",
379
+ "message": success_msg,
380
+ "chip_info": result.stdout,
381
+ "execution_time": result.execution_time
382
+ }
383
+ else:
384
+ error_msg = f"Failed to get chip info: {result.stderr or 'Unknown error'}"
385
+ logger.error(error_msg)
386
+ return {
387
+ "status": "error",
388
+ "message": error_msg,
389
+ "return_code": result.return_code,
390
+ "stderr": result.stderr
391
+ }
392
+
393
+ except Exception as e:
394
+ error_msg = f"Error getting ESP32-S3 chip info: {str(e)}"
395
+ logger.error(error_msg)
396
+ return {"status": "error", "message": error_msg}
397
+
398
+ def _command_impl(self, device: SerialDevice, command: str, args: Optional[Dict] = None) -> Optional[str]:
399
+ """
400
+ Execute commands on the ESP32-S3 device using SCPI.
401
+ Uses a dictionary dispatch for cleaner code.
402
+ """
403
+ if not self.client and command != "flash_firmware":
404
+ logger.error("Cannot send command: ESP32-S3 device not connected")
405
+ raise RuntimeError("Device not connected")
406
+
407
+ command_map = {
408
+ "scan_wifi": self._handle_scan_wifi,
409
+ "start_wifi_monitor": self._handle_start_wifi_monitor,
410
+ "stop_wifi_monitor": self._handle_stop_wifi_monitor,
411
+ "get_version": self._handle_get_version,
412
+ "get_status": self._handle_get_status,
413
+ "reset": self._handle_reset,
414
+ "flash_firmware": self._handle_flash_firmware,
415
+ "erase_flash": self._handle_erase_flash,
416
+ "get_chip_info": self._handle_get_chip_info
417
+ }
418
+
419
+ try:
420
+ handler = command_map.get(command)
421
+ if handler is None:
422
+ logger.error(f"Unknown command: {command}")
423
+ return f"Unknown command: {command}"
424
+ return handler(device, args)
425
+ except Exception as e:
426
+ logger.error(f"Error executing command {command}: {e}")
427
+ raise
428
+
429
+ def _reset_impl(self, device: SerialDevice) -> bool:
430
+ """
431
+ Reset the ESP32-S3 device using SCPI *RST command.
432
+ """
433
+ try:
434
+ if self.client:
435
+ self.client.send_command("*RST")
436
+ logger.info("ESP32-S3 device reset successfully")
437
+ return True
438
+ return False
439
+ except Exception as e:
440
+ logger.error(f"Failed to reset ESP32-S3 device: {e}")
441
+ raise
442
+
443
+ def _close_impl(self, device: SerialDevice) -> bool:
444
+ """
445
+ Close the connection to the ESP32-S3 device.
446
+ """
447
+ try:
448
+ if self.is_acquiring.is_set():
449
+ self.stop_streaming(device)
450
+ if self.client:
451
+ self.client.close()
452
+ self.transport = None
453
+ self.client = None
454
+ logger.info("ESP32-S3 device closed successfully")
455
+ return True
456
+ except Exception as e:
457
+ logger.error(f"Failed to close ESP32-S3 device: {e}")
458
+ raise
459
+
460
+ def _setup_acquisition(self, device: Device):
461
+ """Setup for WiFi monitoring."""
462
+ logger.info(f"Setting up WiFi monitoring for device {device.device_id}")
463
+
464
+ def _cleanup_acquisition(self, device: Device):
465
+ """Cleanup after WiFi monitoring."""
466
+ logger.info(f"Cleaning up WiFi monitoring for device {device.device_id}")
467
+
468
+
469
+ if __name__ == "__main__":
470
+ logging.basicConfig(level=logging.INFO)
471
+
472
+ driver = ESP32Driver()
473
+ devices = driver.scan()
474
+
475
+ if devices:
476
+ test_device = devices[0]
477
+ print(f"ESP32-S3 Device Found: {test_device}")
478
+
479
+ try:
480
+ if driver.initialize(test_device):
481
+ if driver.connect(test_device):
482
+ print("Device connected successfully")
483
+
484
+ # Test flash firmware command
485
+ result = driver.command(test_device, "flash_firmware")
486
+ print(f"Flash firmware result: {result}")
487
+
488
+ # Start WiFi monitoring
489
+ result = driver.command(test_device, "start_wifi_monitor")
490
+ print(result)
491
+
492
+ # Let it run for 30 seconds
493
+ time.sleep(30)
494
+
495
+ # Stop WiFi monitoring
496
+ result = driver.command(test_device, "stop_wifi_monitor")
497
+ print(result)
498
+
499
+ if driver.close(test_device):
500
+ print("Device closed successfully")
501
+ else:
502
+ print("Failed to close device")
503
+ else:
504
+ print("Failed to connect to device")
505
+ except Exception as ex:
506
+ print(f"Error during device operation: {ex}")
507
+ else:
508
+ print("No ESP32-S3 devices found")
@@ -0,0 +1,140 @@
1
+ import abc
2
+ import socket
3
+ import time
4
+
5
+ try:
6
+ import serial
7
+ except ImportError: # pragma: no cover - exercised only when pyserial is absent
8
+ serial = None
9
+
10
+
11
+ class ScpiTransport(abc.ABC):
12
+ @abc.abstractmethod
13
+ def connect(self):
14
+ pass
15
+
16
+ @abc.abstractmethod
17
+ def write(self, data: bytes) -> int:
18
+ pass
19
+
20
+ @abc.abstractmethod
21
+ def read(self, bufsize: int = 1024) -> bytes:
22
+ pass
23
+
24
+ @abc.abstractmethod
25
+ def flush(self):
26
+ pass
27
+
28
+ @abc.abstractmethod
29
+ def close(self):
30
+ pass
31
+
32
+
33
+ class ScpiTcpTransport(ScpiTransport):
34
+ def __init__(self, ip: str, port: int, timeout: float = 5.0):
35
+ self.ip = ip
36
+ self.port = port
37
+ self.timeout = timeout
38
+ self.sock = None
39
+
40
+ def connect(self):
41
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
42
+ self.sock.settimeout(self.timeout)
43
+ self.sock.connect((self.ip, self.port))
44
+
45
+ def write(self, data: bytes) -> int:
46
+ if not self.sock:
47
+ raise ConnectionError("TCP socket is not connected")
48
+ return self.sock.send(data)
49
+
50
+ def read(self, bufsize: int = 1024) -> bytes:
51
+ if not self.sock:
52
+ raise ConnectionError("TCP socket is not connected")
53
+ return self.sock.recv(bufsize)
54
+
55
+ def flush(self):
56
+ pass
57
+
58
+ def close(self):
59
+ if self.sock:
60
+ self.sock.close()
61
+ self.sock = None
62
+
63
+
64
+ class ScpiSerialTransport(ScpiTransport):
65
+ def __init__(self, port: str, baudrate: int = 115200, timeout: float = 1.0):
66
+ self.port = port
67
+ self.baudrate = baudrate
68
+ self.timeout = timeout
69
+ self.ser = None
70
+
71
+ def connect(self):
72
+ if serial is None:
73
+ raise ImportError("pyserial is required to use ScpiSerialTransport")
74
+ self.ser = serial.Serial(
75
+ port=self.port,
76
+ baudrate=self.baudrate,
77
+ timeout=self.timeout,
78
+ )
79
+
80
+ def write(self, data: bytes) -> int:
81
+ if not self.ser:
82
+ raise ConnectionError("Serial port is not connected")
83
+ return self.ser.write(data)
84
+
85
+ def read(self, bufsize: int = 1024) -> bytes:
86
+ if not self.ser:
87
+ raise ConnectionError("Serial port is not connected")
88
+ return self.ser.read(bufsize)
89
+
90
+ def flush(self):
91
+ if self.ser:
92
+ self.ser.flush()
93
+
94
+ def close(self):
95
+ if self.ser:
96
+ self.ser.close()
97
+ self.ser = None
98
+
99
+
100
+ class ScpiClient:
101
+ def __init__(self, transport):
102
+ """
103
+ transport must be an instance of ScpiTransport (or subclass)
104
+ """
105
+ self.transport = transport
106
+
107
+ def connect(self):
108
+ self.transport.connect()
109
+
110
+ def send_command(self, command: str, terminator: str = "\n") -> None:
111
+ full_command = command.strip() + terminator
112
+ self.transport.write(full_command.encode())
113
+ self.transport.flush()
114
+
115
+ def query(self, command: str, terminator: str = "\n", timeout: float = 2.0) -> str:
116
+ """
117
+ Send a SCPI query and wait for a response.
118
+ """
119
+ self.send_command(command, terminator)
120
+ start_time = time.time()
121
+ received_data = b""
122
+ while time.time() - start_time < timeout:
123
+ data = self.transport.read(1024)
124
+ if data:
125
+ received_data += data
126
+ if received_data.endswith(terminator.encode()):
127
+ break
128
+ return received_data.decode().strip()
129
+
130
+ def reset(self) -> None:
131
+ self.send_command("*RST")
132
+
133
+ def get_status(self) -> str:
134
+ return self.query("SYSTem:STATus?")
135
+
136
+ def get_version(self) -> str:
137
+ return self.query("SYSTem:VERSion?")
138
+
139
+ def close(self):
140
+ self.transport.close()
File without changes