from machine import Pin, SPI from time import sleep_ms, ticks_ms, ticks_diff import network import socket try: import tls as ssl # newer MicroPython: native module is called "tls" except ImportError: import ssl # older builds / builds that freeze the ssl wrapper from ili9341 import Display, color565 # ---------------- Settings ---------------- HOST = "gab.wallawalla.edu" PATH = "/~ralph.stirling/index.html" STRIP_HTML = True # False = show the raw HTML source instead of plain text MAX_BYTES = 16 * 1024 # stop reading after this many bytes ETH_CS_PIN = 17 # not in your list: GPIO17 is the usual SPI0 CS for a W5500 # ---------------- LCD setup (same as the button demo) ---------------- spi_lcd = SPI(1, baudrate=40000000, sck=Pin(10), mosi=Pin(11), miso=Pin(12)) display = Display(spi_lcd, dc=Pin(3), cs=Pin(15), rst=Pin(9), width=320, height=240, rotation=270) display.write_cmd(0x21) # panel inversion; remove if your colors look wrong BLACK = color565(0, 0, 0) WHITE = color565(255, 255, 255) GREEN = color565(0, 255, 0) YELLOW = color565(255, 255, 0) RED = color565(255, 0, 0) COLS = 40 # 320 px / 8 px per character LINE_H = 10 # 8 px font + 2 px spacing ROWS = 240 // LINE_H class Console: """Very small text console for the 8x8 font.""" def __init__(self): self.row = 0 def clear(self): display.clear(BLACK) self.row = 0 def put(self, text, color=WHITE): """Print one line (no wrapping). Returns False if the screen is full.""" if self.row >= ROWS: return False if text: # drawing an empty string raises ValueError in the library display.draw_text8x8(0, self.row * LINE_H, text[:COLS], color, BLACK) self.row += 1 return True con = Console() # ---------------- Text helpers ---------------- def html_to_text(html): """Crude HTML -> plain text: drops tags/scripts/styles/comments.""" low = html.lower() out = [] i, n = 0, len(html) block = ("br", "p", "/p", "div", "/div", "li", "tr", "/tr", "h1", "h2", "h3", "h4", "h5", "h6", "/h1", "/h2", "/h3", "/h4", "/h5", "/h6", "title", "/title", "hr", "table", "/table") while i < n: c = html[i] if c != "<": out.append(c) i += 1 continue if low.startswith("", i) i = n if end < 0 else end + 3 continue if low.startswith("" end = low.find(closing, i) i = n if end < 0 else end + len(closing) continue j = html.find(">", i) if j < 0: break tag = low[i + 1:j] parts = tag.lstrip("/").split() name = parts[0].rstrip("/") if parts else "" if tag.startswith("/"): name = "/" + name if name in block: out.append("\n") i = j + 1 text = "".join(out) for a, b in ((" ", " "), ("<", "<"), (">", ">"), (""", '"'), ("'", "'"), ("&", "&")): text = text.replace(a, b) return text def wrap(text, width=COLS): """Collapse whitespace per line and word-wrap to the screen width.""" lines = [] blank = True for raw in text.split("\n"): words = raw.split() if not words: if not blank: lines.append("") blank = True continue blank = False cur = "" for w in words: while len(w) > width: # break very long words if cur: lines.append(cur) cur = "" lines.append(w[:width]) w = w[width:] if not cur: cur = w elif len(cur) + 1 + len(w) <= width: cur += " " + w else: lines.append(cur) cur = w if cur: lines.append(cur) return lines # ---------------- Networking ---------------- def start_ethernet(): if not hasattr(network, "WIZNET5K"): raise RuntimeError("No WIZNET5K in firmware") spi_eth = SPI(0, 2_000_000, sck=Pin(18), mosi=Pin(19), miso=Pin(16)) nic = network.WIZNET5K(spi_eth, Pin(ETH_CS_PIN), Pin(20)) # CS, RST nic.active(True) nic.ifconfig("dhcp") start = ticks_ms() while ticks_diff(ticks_ms(), start) < 20000: if nic.isconnected() and nic.ifconfig()[0] != "0.0.0.0": return nic sleep_ms(200) raise RuntimeError("DHCP timed out") def https_get(host, path, max_bytes=MAX_BYTES): """Return (status_line, body_bytes) for a simple HTTPS GET.""" addr = socket.getaddrinfo(host, 443)[0][-1] s = socket.socket() s.settimeout(15) s.connect(addr) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx.verify_mode = ssl.CERT_NONE # no certificate check (demo only) s = ctx.wrap_socket(s, server_hostname=host) # HTTP/1.0 so the server doesn't use chunked encoding s.write("GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: pico2\r\n" "Connection: close\r\n\r\n" % (path, host)) data = b"" try: while len(data) < max_bytes: chunk = s.read(1024) if not chunk: break data += chunk except OSError: pass # many servers close without TLS close_notify finally: s.close() head, _, body = data.partition(b"\r\n\r\n") status = head.split(b"\r\n")[0].decode() return status, body def to_ascii(raw): return bytes(b if (32 <= b < 127 or b in (9, 10, 13)) else 63 for b in raw).decode() # ---------------- Main ---------------- def main(): con.clear() con.put("W5500 demo", YELLOW) con.put("Starting Ethernet...") nic = start_ethernet() ip = nic.ifconfig()[0] con.put("IP: " + ip, GREEN) print("ifconfig:", nic.ifconfig()) con.put("GET " + HOST) status, body = https_get(HOST, PATH) print(status) text = to_ascii(body) print(text) if STRIP_HTML: text = html_to_text(text) lines = wrap(text) # Show result: header lines, then as much of the page as fits con.clear() con.put("IP: " + ip, GREEN) con.put(status, YELLOW) for line in lines: if not con.put(line): break print("Full page printed to REPL; %d lines after wrapping" % len(lines)) try: main() except Exception as e: print("Error:", repr(e)) con.put("Error:", RED) msg = str(e) while msg: con.put(msg[:COLS], RED) msg = msg[COLS:]