├── LICENSE ├── README.md ├── boot.py ├── config.txt ├── docs └── help.txt ├── main.py ├── pico-shell.png ├── telnet └── utelnetserver.py └── utils.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Patrick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PicoShell 2 | 3 | **PicoShell** is a lightweight, real-time command-line interface (CLI) for the Raspberry Pi Pico W 2 (RP2350 dual-core), built entirely in MicroPython. It brings a minimal UNIX-style shell to embedded hardware with support for Wi-Fi networking, filesystem interaction, script execution, telnet access, and more. 4 | 5 | --- 6 | ![PicoShell Screenshot](pico-shell.png) 7 | 8 | 9 | ## Features 10 | 11 | - Basic shell command interface over USB or Telnet 12 | - Wi-Fi networking with persistent config 13 | - Telnet daemon that autostarts on successful network connection 14 | - Filesystem tools: create, read, delete, navigate 15 | - Script runner and file downloader 16 | - System utilities: memory, clock speed, device info, and overclocking 17 | - Built for expansion and real task threading with RP2350 18 | 19 | --- 20 | 21 | ## Commands 22 | 23 | ### General 24 | 25 | | Command | Description | 26 | |--------------|--------------------------------------| 27 | | `help`, `h` | Show this help message | 28 | | `about` | Show shell version & system info | 29 | | `clear` | Clear the terminal display | 30 | | `exit` | Exits back to MicroPython | 31 | 32 | ### Filesystem 33 | 34 | | Command | Description | 35 | |----------------|--------------------------------------| 36 | | `pwd` | Print current working directory | 37 | | `ls` | List files and directories | 38 | | `cd ` | Change directory | 39 | | `mkdir ` | Create a directory | 40 | | `rmdir ` | Remove a directory | 41 | | `rm ` | Delete a file | 42 | | `read ` | Print contents of a file | 43 | 44 | ### Networking 45 | 46 | | Command | Description | 47 | |----------------------|----------------------------------------| 48 | | `wifi` | Connect to Wi-Fi using config file | 49 | | `ifconfig` | Show IP and network info | 50 | | `ping ` | Ping a host by IP or domain | 51 | | `curl ` | Fetch and display content from URL | 52 | | `clone [name]` | Download file from GitHub/raw URL | 53 | | `scan` | Scan nearby Wi-Fi networks | 54 | | `pmap ` | Nmap-style port scanner | 55 | 56 | ### Telnet 57 | 58 | | Command | Description | 59 | |------------------|----------------------------------------| 60 | | `telnet launch` | Start the telnet server | 61 | | `telnet stop` | Stop the telnet server | 62 | 63 | ### Scripts 64 | 65 | | Command | Description | 66 | |------------------|----------------------------------------| 67 | | `run ` | Execute a Python script from storage | 68 | 69 | ### System 70 | 71 | | Command | Description | 72 | |-------------------|----------------------------------------| 73 | | `setclock ` | Set CPU frequency (40–260 MHz) | 74 | | `clock` | Show current CPU clock speed | 75 | | `dspace` | Show available storage | 76 | | `ram` | Show current RAM usage | 77 | | `sysinfo` | Show detailed system/platform info | 78 | 79 | --- 80 | 81 | ## Project Structure 82 | 83 | ``` 84 | boot.py # Wi-Fi and Telnet auto-connect on boot 85 | Main.py # Main CLI loop 86 | utils.py # Core shell commands 87 | utelnetserver.py # Lightweight Telnet server 88 | help.txt # CLI help text 89 | config.txt # Wi-Fi credentials (SSID=..., PASSWORD=...) 90 | ``` 91 | 92 | --- 93 | 94 | ## Getting Started 95 | 96 | ### 1. Flash MicroPython to Your Pico W 2 97 | 98 | - Download the latest **MicroPython UF2 firmware** for the **Pico W 2 (RP2350)** from the [official MicroPython downloads page](https://micropython.org/download/rp2-pico-w/). 99 | - Hold the **BOOTSEL** button while plugging in your Pico to your computer. It will appear as a USB drive. 100 | - Drag and drop the downloaded `.uf2` file onto that drive. 101 | - The Pico will reboot into MicroPython mode. 102 | 103 | ### 2. Upload PicoShell Files 104 | 105 | - Upload the following to the root of the Pico filesystem: 106 | 107 | - `boot.py` 108 | - `Main.py` 109 | - `utils.py` 110 | - `telnet` 111 | - `docs` 112 | - `config.txt` 113 | 114 | You can use any of the following tools: 115 | 116 | #### Thonny IDE (GUI) 117 | 118 | - Open [Thonny](https://thonny.org) 119 | - Select "MicroPython (Raspberry Pi Pico)" 120 | - Use the file browser to upload each file listed above 121 | 122 | #### mpremote (CLI) 123 | 124 | ```bash 125 | mpremote connect ttyUSB0 fs cp boot.py : 126 | mpremote connect ttyUSB0 fs cp Main.py : 127 | mpremote connect ttyUSB0 fs cp utils.py : 128 | mpremote connect ttyUSB0 fs cp utelnetserver.py : 129 | mpremote connect ttyUSB0 fs cp help.txt : 130 | mpremote connect ttyUSB0 fs cp config.txt : 131 | ``` 132 | 133 | > Replace `ttyUSB0` with your actual serial port (e.g., `COM3` on Windows). 134 | 135 | #### rshell / ampy 136 | 137 | - Use `rshell` or `ampy` to push files to `/` on the board. 138 | 139 | ### 3. Configure Wi-Fi 140 | 141 | Create a file called `config.txt` on the Pico containing: 142 | 143 | ``` 144 | SSID=YourNetwork 145 | PASSWORD=YourPassword 146 | ``` 147 | 148 | - No spaces around the `=` 149 | - No quotes 150 | - Must be exact format 151 | 152 | ### 4. Run PicoShell 153 | 154 | - Reset or power on the Pico W 155 | - It will: 156 | - Connect to Wi-Fi using `config.txt` 157 | - Auto-start the telnet server 158 | - Drop into CLI via USB serial or Telnet if online 159 | 160 | --- 161 | 162 | ## License 163 | 164 | MIT License — use it, modify it, ship it, just don’t pretend you made it. 165 | 166 | --- 167 | -------------------------------------------------------------------------------- /boot.py: -------------------------------------------------------------------------------- 1 | import utils 2 | import network 3 | import time 4 | from telnet import utelnetserver 5 | 6 | wlan = network.WLAN(network.STA_IF) 7 | time.sleep(3) 8 | try: 9 | with open('config.txt') as f: 10 | ssid, password = utils.read_wifi_config('config.txt') 11 | utils.auto_connect(ssid, password) 12 | print('Initializing...') 13 | 14 | time.sleep(10) 15 | 16 | if wlan.isconnected(): 17 | print("Connected! Starting telnet...") 18 | utelnetserver.start() 19 | 20 | else: 21 | print("Still trying to connect") 22 | except OSError: 23 | print("config.txt not found. Skipping Wi-Fi connection.") 24 | 25 | try: 26 | print("Starting PicoShell...") 27 | time.sleep(2) 28 | import main 29 | except Exception as e: 30 | print("Error:",e) 31 | -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | SSID= 2 | PASSWORD= -------------------------------------------------------------------------------- /docs/help.txt: -------------------------------------------------------------------------------- 1 | Available Commands: 2 | 3 | help, h Show this help message 4 | wifi Manually scan and connect to a Wi-Fi network 5 | ifconfig Show network interface configuration (IP address, etc.) 6 | sysinfo Display system info 7 | dspace Shows the available disk space on the device 8 | ram Shows the current RAM usage 9 | 10 | Filesystem Commands: 11 | pwd Print the current working directory 12 | ls List files and directories 13 | cd Change current directory 14 | mkdir Create a new directory 15 | rmdir Remove a directory 16 | rm Delete a file 17 | read Prints the contents of a file 18 | 19 | 20 | Script & Networking: 21 | run Execute a Python script from storage 22 | clone [name] Download a .py or .txt file from the internet (GitHub raw supported) 23 | curl Fetch and display content from a URL 24 | ping Ping a host by domain or IP 25 | scan Scan for local networks 26 | pmap Nmap-style port scanner that will check for open ports on a designated network 27 | 28 | Telnet: 29 | telnet launch Start a telnet server. 30 | telnet stop Stop the telnet server. 31 | Note: Telnet is started by default if the device is able to successfully connect to Wifi. 32 | 33 | System: 34 | clear Clear the screen 35 | about Show system version and shell info 36 | setclock Set the CPU clock speed (allowed range: 40–260 MHz) 37 | clock Show the current CPU clock speed 38 | temp Returns the CPU temperature 39 | freemem Force Garbage collection to free as much memory as possible. 40 | 41 | Notes: 42 | - Use raw GitHub URLs when cloning (https://raw.githubusercontent.com/...) 43 | - Clone automatically saves using the file's name unless you specify one 44 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import utils 3 | import network 4 | import platform 5 | import machine 6 | import gc 7 | from machine import Pin 8 | import time 9 | ### 10 | bold = "\033[1m" 11 | green = "\033[32m" 12 | blue = "\033[34m" 13 | reset = "\033[0m" 14 | its = 0 15 | led = Pin("LED", Pin.OUT) 16 | blink = 0 17 | blinked = False 18 | sys_info = os.uname() 19 | 20 | while True: 21 | try: 22 | if not blinked: 23 | while blink < 4: 24 | led.on() 25 | time.sleep(0.2) 26 | led.off() 27 | time.sleep(0.2) 28 | blink += 1 29 | blinked = True 30 | command = input(f"{bold}{green}Pico@{sys_info.sysname}{reset}:{blue}{os.getcwd()}{reset}$ ") 31 | 32 | if command == 'wifi': 33 | utils.getWifi() 34 | 35 | elif command == 'help' or command == 'h': 36 | try: 37 | with open("/docs/help.txt") as f: 38 | print(f.read()) 39 | except Exception as e: 40 | print("Help file does not exist.", e) 41 | 42 | elif command == 'ls': 43 | utils.ls() 44 | 45 | elif command == 'exit': 46 | break 47 | 48 | elif command.startswith("run "): 49 | script_name = command[4:].strip() 50 | utils.run(script_name) 51 | 52 | elif command.startswith("cd "): 53 | dir = command[3:].strip() 54 | utils.cd(dir) 55 | 56 | elif command == 'ifconfig': 57 | utils.if_config() 58 | 59 | elif command.startswith("ping "): 60 | host = command[5:].strip() 61 | utils.ping(host) 62 | 63 | elif command.startswith("curl "): 64 | url = command[5:].strip() 65 | utils.curl(url) 66 | 67 | elif command.startswith('telnet '): 68 | tel = command[7:].strip() 69 | utils.telnet_launch(tel) 70 | 71 | elif command.startswith('mkdir '): 72 | dir = command[6:].strip() 73 | utils.mkdir(dir) 74 | 75 | elif command.startswith('rmdir '): 76 | dir = command[6:].strip() 77 | utils.rmdir(dir) 78 | 79 | elif command.startswith('rm '): 80 | file = command[3:].strip() 81 | utils.rm(file) 82 | 83 | elif command == 'sysinfo': 84 | utils.sysinfo() 85 | 86 | elif command == 'dspace': 87 | utils.get_storage() 88 | 89 | elif command == 'about': 90 | print(platform.platform()) 91 | 92 | elif command == 'clock': 93 | print("CPU Clock:", machine.freq() // 1_000_000, "MHz") 94 | 95 | elif command.startswith('setclock '): 96 | clock = int(command[9:].strip()) 97 | utils.overclock(clock) 98 | 99 | elif command == 'scan': 100 | utils.scan() 101 | 102 | elif command.startswith('clone '): 103 | try: 104 | args = command[6:].strip().split() 105 | url = args[0] 106 | filename = args[1] if len(args) > 1 else url.rsplit('/', 1)[-1] 107 | utils.download_file(url, filename) 108 | print(f"Downloading {filename} from {url}") 109 | except Exception as e: 110 | print("Download failed:", e) 111 | 112 | elif command.startswith("pmap "): 113 | parts = command.split() 114 | ip = parts[1] 115 | start = int(parts[2]) if len(parts) > 2 else 1 116 | end = int(parts[3]) if len(parts) > 3 else 1024 117 | utils.scan_ports(ip, start, end) 118 | 119 | 120 | elif command == 'clear': 121 | print('\033c', end='') 122 | 123 | elif command.startswith('blink'): 124 | utils.blink() 125 | 126 | elif command == 'reboot': 127 | print("Rebooting.") 128 | machine.reset() 129 | 130 | elif command == 'reset': 131 | print("Reseting") 132 | machine.soft_reset() 133 | 134 | elif command.startswith('read '): 135 | fName = command[4:].strip() 136 | utils.read(fName) 137 | 138 | elif command == 'ram': 139 | utils.get_mem() 140 | 141 | elif command == 'pwd': 142 | print(os.getcwd()) 143 | 144 | elif command == 'temp': 145 | print(f"CPU Temp: {utils.read_temp():.2f} °C") 146 | 147 | elif command == 'freemem': 148 | utils.get_mem() 149 | gc.collect() 150 | print("After Garbage Collection: ") 151 | utils.get_mem() 152 | 153 | 154 | its += 1 155 | 156 | if its % 5 == 0 and its != 0: 157 | gc.collect() 158 | 159 | #else: 160 | #print("Unknown Command") 161 | except Exception as e: 162 | print("CLI ERROR: ",e) 163 | 164 | except KeyboardInterrupt: 165 | print() 166 | continue 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /pico-shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patrickp02/PicoShell/dbf0e2c9bf92171050e5493af02615bf497a191c/pico-shell.png -------------------------------------------------------------------------------- /telnet/utelnetserver.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import network 3 | import uos 4 | import errno 5 | import gc 6 | from uio import IOBase 7 | 8 | last_client_socket = None 9 | server_socket = None 10 | 11 | class TelnetWrapper(IOBase): 12 | def __init__(self, socket): 13 | self.socket = socket 14 | self.discard_count = 0 15 | self._input_buffer = b"" 16 | 17 | def readinto(self, b): 18 | readbytes = 0 19 | for i in range(len(b)): 20 | byte = 0 21 | 22 | while byte == 0: 23 | if not self._input_buffer: 24 | try: 25 | self._input_buffer = self.socket.recv(64) 26 | except OSError as e: 27 | if e.args and e.args[0] == errno.EAGAIN: 28 | return readbytes if readbytes else None 29 | raise 30 | 31 | if not self._input_buffer: 32 | return readbytes if readbytes else None 33 | 34 | byte = self._input_buffer[0] 35 | self._input_buffer = self._input_buffer[1:] 36 | 37 | if byte == 0xFF: 38 | self.discard_count = 2 39 | byte = 0 40 | elif self.discard_count > 0: 41 | self.discard_count -= 1 42 | byte = 0 43 | elif byte == 0: 44 | byte = 0 # null byte, discard 45 | 46 | b[i] = byte 47 | readbytes += 1 48 | 49 | return readbytes 50 | 51 | def write(self, data): 52 | mv = memoryview(data) 53 | while len(mv): 54 | try: 55 | sent = self.socket.write(mv) 56 | mv = mv[sent:] 57 | except OSError as e: 58 | if e.args and e.args[0] == errno.EAGAIN: 59 | continue 60 | raise 61 | 62 | def close(self): 63 | try: 64 | self.socket.close() 65 | except: 66 | pass 67 | self._input_buffer = b"" 68 | 69 | def accept_telnet_connect(telnet_server): 70 | global last_client_socket 71 | 72 | uos.dupterm(None) 73 | if last_client_socket: 74 | try: 75 | last_client_socket.close() 76 | except: 77 | pass 78 | last_client_socket = None 79 | 80 | gc.collect() 81 | 82 | try: 83 | last_client_socket, remote_addr = telnet_server.accept() 84 | print("Telnet connection from:", remote_addr) 85 | last_client_socket.setblocking(False) 86 | uos.dupterm(TelnetWrapper(last_client_socket)) 87 | print("[INFO] Telnet client accepted") 88 | print("[MEM] Free:", gc.mem_free(), "Used:", gc.mem_alloc()) 89 | except Exception as e: 90 | print("[ERROR] Accept failed:", e) 91 | 92 | def stop(): 93 | global server_socket, last_client_socket 94 | uos.dupterm(None) 95 | 96 | if server_socket: 97 | try: 98 | server_socket.close() 99 | except: 100 | pass 101 | server_socket = None 102 | 103 | if last_client_socket: 104 | try: 105 | last_client_socket.close() 106 | except: 107 | pass 108 | last_client_socket = None 109 | 110 | gc.collect() 111 | print("[INFO] Telnet server stopped") 112 | print("[MEM] Free:", gc.mem_free(), "Used:", gc.mem_alloc()) 113 | 114 | def start(port=23): 115 | stop() 116 | global server_socket 117 | 118 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 119 | server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 120 | 121 | ai = socket.getaddrinfo("0.0.0.0", port) 122 | addr = ai[0][4] 123 | 124 | server_socket.bind(addr) 125 | server_socket.listen(1) 126 | server_socket.setsockopt(socket.SOL_SOCKET, 20, accept_telnet_connect) 127 | 128 | for i in (network.AP_IF, network.STA_IF): 129 | wlan = network.WLAN(i) 130 | if wlan.active(): 131 | print("Telnet server started on {}:{}".format(wlan.ifconfig()[0], port)) 132 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import network 2 | import time 3 | import os 4 | import socket 5 | import urequests 6 | import gc 7 | from telnet import utelnetserver 8 | import ssl 9 | import machine 10 | from machine import Pin 11 | 12 | 13 | adc = machine.ADC(29) 14 | conversion_factor = 3.3 / 4095 15 | wlan = network.WLAN(network.STA_IF) 16 | led = Pin("LED", Pin.OUT) 17 | def auto_connect(ssid,password): 18 | wlan.active(True) 19 | wlan.connect(ssid,password) 20 | 21 | def read_wifi_config(filename): 22 | config = {} 23 | with open(filename, 'r') as file: 24 | for line in file: 25 | if '=' in line: 26 | key, value = line.strip().split('=', 1) 27 | config[key.strip()] = value.strip() 28 | return config['SSID'], config['PASSWORD'] 29 | def overclock(clock): 30 | decide = input("WARNING! Overclocking can cause instability. Would you like to proceed?[Y/N]: ") 31 | if decide.lower() == 'y': 32 | if clock > 40 and clock < 260: 33 | machine.freq(clock * 1_000_000) 34 | print("Clock speed set to " + str(clock)) 35 | else: 36 | if clock < 40: 37 | print("Clock speed is set too low!") 38 | else: 39 | print("Clock speed is set too high!") 40 | 41 | def get_storage(): 42 | stats = os.statvfs("/") 43 | block_size = stats[0] 44 | total_blocks = stats[2] 45 | free_blocks = stats[3] 46 | 47 | total = (block_size * total_blocks) // 1024 48 | free = (block_size * free_blocks) // 1024 49 | used = total - free 50 | 51 | print("Storage:") 52 | print(f" Total: {total} KB") 53 | print(f" Used: {used} KB") 54 | print(f" Free: {free} KB") 55 | 56 | def getWifi(): 57 | global wlan 58 | wlan.active(True) 59 | 60 | if wlan.isconnected(): 61 | essid = wlan.config('essid') 62 | print("Connected to: ",essid) 63 | state = input(f"Would you like to disconnect from {essid}? [Y/N]: ") 64 | 65 | if state == 'Y' or state == 'y': 66 | wlan.disconnect() 67 | wlan.active(False) # Hard disables the Wi-Fi chip 68 | time.sleep(1) # Give it a sec to settle 69 | wlan.active(True) 70 | time.sleep(1) 71 | print("Disconnected!") 72 | return 73 | 74 | else: 75 | return 76 | 77 | while not wlan.isconnected(): 78 | networks = wlan.scan() 79 | print("Available Networks:") 80 | for network in networks: 81 | print(f"SSID: {network[0]} Signal Strength: {network[3]}") 82 | 83 | essid = input("Enter the network name you would like to use: ") 84 | password = input("Enter the password for the network: ") 85 | 86 | if isinstance(password, str): 87 | wlan.active(True) 88 | wlan.connect(essid, password) # Attempt to connect 89 | else: 90 | print("Password must be a string!") 91 | 92 | # Wait until the device is connected 93 | start_time = time.ticks_ms() # Get the current time 94 | while not wlan.isconnected(): 95 | print("Connecting...", end="") # Print without a new line 96 | time.sleep(1) # Wait for 1 second 97 | print(".", end="") # Add a dot every second 98 | timed = time.ticks_diff(time.ticks_ms(), start_time) # Check elapsed time 99 | if timed > 100000: # Timeout after 100 seconds 100 | print("Network error!") 101 | break 102 | 103 | # Once connected 104 | if wlan.isconnected(): 105 | print("You're all connected!") 106 | print(wlan.ifconfig()) # Print the network configuration 107 | 108 | def cd(dir): 109 | try: 110 | os.chdir(dir) 111 | except OSError: 112 | print("Path does not exist!") 113 | print("Error: " + str(OSError)) 114 | 115 | def ls(): 116 | 117 | print(" ".join(os.listdir())) 118 | def run(script_name): 119 | try: 120 | # Check if the file exists 121 | if script_name in os.listdir(): 122 | with open(script_name, "r") as file: 123 | script_content = file.read() 124 | code_obj = compile(script_content, script_name,'exec') 125 | exec(code_obj, { 126 | "__name__": "__main__", 127 | "input": input, 128 | "print": print, 129 | }) 130 | del code_obj 131 | 132 | else: 133 | print(f"Error: {script_name} not found.") 134 | except Exception as e: 135 | print(f"Error running {script_name}: {e}") 136 | 137 | def if_config(): 138 | print(" ".join(wlan.ifconfig())) 139 | if wlan.isconnected(): 140 | print("Connected:", wlan.ifconfig()) 141 | else: 142 | print("Not connected (IP config stale)") 143 | 144 | def read(fName): 145 | try: 146 | with open (fName) as f: 147 | print(f.read()) 148 | 149 | except Exception as e: 150 | print("Error: ",e) 151 | 152 | 153 | def ping(host, count=4, timeout=1): 154 | try: 155 | # Resolve host to get address info 156 | addr_info = socket.getaddrinfo(host, 80) 157 | addr = addr_info[0][-1][0] # Extract the IP address from the tuple 158 | print(f"Pinging {host} ({addr}) with {count} packets:") 159 | 160 | for i in range(count): 161 | start_time = time.ticks_ms() 162 | 163 | 164 | s = socket.socket() 165 | s.settimeout(timeout) 166 | 167 | try: 168 | s.connect((addr, 80)) 169 | end_time = time.ticks_ms() 170 | elapsed_time = time.ticks_diff(end_time, start_time) 171 | print(f"Reply from {addr}: time={elapsed_time}ms") 172 | except OSError: 173 | print(f"Request timed out for {host}") 174 | 175 | s.close() 176 | time.sleep(1) 177 | 178 | except Exception as e: 179 | print(f"Error: {e}") 180 | 181 | def curl(url): 182 | try: 183 | response = urequests.get(url) 184 | print(response.text) 185 | response.close() 186 | except Exception as e: 187 | print("Error: " , e) 188 | finally: 189 | gc.collect() 190 | 191 | def telnet_launch(tel): 192 | if tel == 'launch': 193 | utelnetserver.start() 194 | if tel == 'stop': 195 | utelnetserver.stop() 196 | gc.collect() 197 | 198 | def download_file(url, filename): 199 | _, _, host, path = url.split('/', 3) 200 | addr = socket.getaddrinfo(host, 443)[0][-1] 201 | 202 | s = socket.socket() 203 | s.connect(addr) 204 | s = ssl.wrap_socket(s, server_hostname=host) 205 | 206 | req = f"GET /{path} HTTP/1.0\r\nHost: {host}\r\n\r\n" 207 | s.write(req.encode()) 208 | 209 | header_passed = False 210 | with open(filename, 'w') as f: 211 | while True: 212 | data = s.read(1024) 213 | if data: 214 | content = data.decode() 215 | if not header_passed: 216 | if "\r\n\r\n" in content: 217 | content = content.split("\r\n\r\n", 1)[1] 218 | header_passed = True 219 | else: 220 | continue 221 | f.write(content) 222 | else: 223 | break 224 | s.close() 225 | 226 | def scan(): 227 | try: 228 | networks = wlan.scan() 229 | print("Available Networks:") 230 | for network in networks: 231 | print(f"SSID: {network[0]} Signal Strength: {network[3]}") 232 | except Exception as e: 233 | print("Error: ", e) 234 | 235 | def scan_ports(ip, start=1, end=1024): 236 | print(f"Scanning {ip} from port {start} to {end}...") 237 | found = False 238 | for port in range(start, end + 1): 239 | try: 240 | s = socket.socket() 241 | s.settimeout(0.2) 242 | s.connect((ip, port)) 243 | print(f"Port {port}: OPEN") 244 | found = True 245 | s.close() 246 | except: 247 | pass 248 | if not found: 249 | print("No open ports detected.") 250 | 251 | def blink(times=3, delay=0.2): 252 | for _ in range(times): 253 | led.toggle() 254 | time.sleep(delay) 255 | led.toggle() 256 | time.sleep(delay) 257 | 258 | def read_temp(): 259 | try: 260 | raw = adc.read_u16() * conversion_factor 261 | temp = (27 - (raw - 0.706) / 0.001721) / 10 262 | return temp 263 | except Exception as e: 264 | print("ERROR:",e) 265 | def get_mem(): 266 | print("Free:", gc.mem_free()/1024, "kilobytes") 267 | print("Used:", gc.mem_alloc()/1024, "kilobytes") 268 | print("Total:", (gc.mem_alloc() + gc.mem_free())/1024, "kilobytes") 269 | 270 | def mkdir(dir):os.mkdir(dir) 271 | 272 | def rmdir(dir):os.rmdir(dir) 273 | 274 | def rm(file):os.remove(file) 275 | 276 | def sysinfo():print(" ".join(os.uname())) 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | --------------------------------------------------------------------------------