Last active
November 25, 2025 00:05
-
-
Save CortesAguilar/0929a62f2813e8413f2809eb370562db to your computer and use it in GitHub Desktop.
Webserver que sirve archivos estáticos (HTML/CSS/JS) desde filesystem.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html class="dark" lang="en"><head> | |
| <meta charset="utf-8"/> | |
| <meta content="width=device-width, initial-scale=1.0" name="viewport"/> | |
| <title>Monitoreo — Demo</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet"/> | |
| <script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script> | |
| <style> | |
| .material-symbols-outlined { | |
| font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; | |
| } | |
| </style> | |
| <script id="tailwind-config"> | |
| tailwind.config = { | |
| darkMode: "class", | |
| theme: { | |
| extend: { | |
| colors: { | |
| "primary": "#5048e5", | |
| "background-light": "#f6f6f8", | |
| "background-dark": "#121117", | |
| }, | |
| fontFamily: { | |
| "display": ["Inter", "Noto Sans", "sans-serif"] | |
| }, | |
| borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"}, | |
| }, | |
| }, | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-background-light dark:bg-background-dark font-display"> | |
| <div class="relative flex h-auto min-h-screen w-full flex-col bg-background-light dark:bg-background-dark group/design-root overflow-x-hidden" style='font-family: Inter, "Noto Sans", sans-serif;'> | |
| <div class="layout-container flex h-full grow flex-col"> | |
| <div class="px-4 sm:px-10 md:px-20 lg:px-40 flex flex-1 justify-center py-5"> | |
| <div class="layout-content-container flex flex-col max-w-[960px] flex-1"> | |
| <!-- PageHeading --> | |
| <div class="flex flex-wrap justify-between gap-3 p-4"> | |
| <h1 class="text-slate-900 dark:text-white text-4xl font-black leading-tight tracking-[-0.033em] min-w-72">Monitoreo — Demo</h1> | |
| </div> | |
| <!-- Stats --> | |
| <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 p-4"> | |
| <div class="flex min-w-[158px] flex-1 flex-col gap-2 rounded-lg p-6 border bg-white dark:bg-background-dark border-slate-200 dark:border-[#3e3d52]"> | |
| <p class="text-slate-600 dark:text-slate-300 text-base font-medium leading-normal">🌡️ Temperatura (°C)</p> | |
| <p class="text-slate-900 dark:text-white tracking-light text-2xl font-bold leading-tight">23.5</p> | |
| </div> | |
| <div class="flex min-w-[158px] flex-1 flex-col gap-2 rounded-lg p-6 border bg-white dark:bg-background-dark border-slate-200 dark:border-[#3e3d52]"> | |
| <p class="text-slate-600 dark:text-slate-300 text-base font-medium leading-normal">💧 Humedad (%)</p> | |
| <p class="text-slate-900 dark:text-white tracking-light text-2xl font-bold leading-tight">45</p> | |
| </div> | |
| <div class="flex min-w-[158px] flex-1 flex-col gap-2 rounded-lg p-6 border bg-white dark:bg-background-dark border-slate-200 dark:border-[#3e3d52]"> | |
| <p class="text-slate-600 dark:text-slate-300 text-base font-medium leading-normal">📶 Estado de Red</p> | |
| <p class="text-slate-900 dark:text-white tracking-light text-2xl font-bold leading-tight">Conectado</p> | |
| </div> | |
| </div> | |
| <!-- Action Button --> | |
| <div class="flex px-4 py-3 justify-start"> | |
| <button class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-primary text-white text-sm font-bold leading-normal tracking-[0.015em] hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"> | |
| <span class="truncate">Simulate Data</span> | |
| </button> | |
| </div> | |
| <!-- SectionHeader --> | |
| <h2 class="text-slate-900 dark:text-white text-[22px] font-bold leading-tight tracking-[-0.015em] px-4 pb-3 pt-5">Recent Events</h2> | |
| <!-- Table --> | |
| <div class="px-4 py-3 @container"> | |
| <div class="flex overflow-hidden rounded-lg border border-slate-200 dark:border-[#3e3d52] bg-white dark:bg-background-dark"> | |
| <table class="flex-1"> | |
| <thead> | |
| <tr class="bg-slate-50 dark:bg-[#1d1c26]"> | |
| <th class="px-4 py-3 text-left text-slate-600 dark:text-slate-300 text-sm font-medium leading-normal">Date/Time</th> | |
| <th class="px-4 py-3 text-left text-slate-600 dark:text-slate-300 text-sm font-medium leading-normal">Sensor</th> | |
| <th class="px-4 py-3 text-left text-slate-600 dark:text-slate-300 text-sm font-medium leading-normal">Value</th> | |
| <th class="px-4 py-3 text-left text-slate-600 dark:text-slate-300 text-sm font-medium leading-normal">Status</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr class="border-t border-t-slate-200 dark:border-t-[#3e3d52]"> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">2023-10-27 10:00:00</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Temperatura</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">23.5 °C</td> | |
| <td class="h-[72px] px-4 py-2 text-sm font-normal leading-normal"> | |
| <span class="inline-flex items-center justify-center rounded-md h-8 px-4 bg-slate-100 dark:bg-[#2a2938] text-slate-700 dark:text-white text-sm font-medium">Normal</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t border-t-slate-200 dark:border-t-[#3e3d52]"> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">2023-10-27 10:00:00</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Humedad</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">45 %</td> | |
| <td class="h-[72px] px-4 py-2 text-sm font-normal leading-normal"> | |
| <span class="inline-flex items-center justify-center rounded-md h-8 px-4 bg-slate-100 dark:bg-[#2a2938] text-slate-700 dark:text-white text-sm font-medium">Normal</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t border-t-slate-200 dark:border-t-[#3e3d52]"> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">2023-10-27 09:55:00</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Temperatura</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">23.4 °C</td> | |
| <td class="h-[72px] px-4 py-2 text-sm font-normal leading-normal"> | |
| <span class="inline-flex items-center justify-center rounded-md h-8 px-4 bg-slate-100 dark:bg-[#2a2938] text-slate-700 dark:text-white text-sm font-medium">Normal</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t border-t-slate-200 dark:border-t-[#3e3d52]"> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">2023-10-27 09:55:00</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Humedad</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">46 %</td> | |
| <td class="h-[72px] px-4 py-2 text-sm font-normal leading-normal"> | |
| <span class="inline-flex items-center justify-center rounded-md h-8 px-4 bg-slate-100 dark:bg-[#2a2938] text-slate-700 dark:text-white text-sm font-medium">Normal</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t border-t-slate-200 dark:border-t-[#3e3d52]"> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">2023-10-27 09:50:00</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Red</td> | |
| <td class="h-[72px] px-4 py-2 text-slate-500 dark:text-[#9f9eb7] text-sm font-normal leading-normal">Conectado</td> | |
| <td class="h-[72px] px-4 py-2 text-sm font-normal leading-normal"> | |
| <span class="inline-flex items-center justify-center rounded-md h-8 px-4 bg-slate-100 dark:bg-[#2a2938] text-slate-700 dark:text-white text-sm font-medium">Ok</span> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Help Section --> | |
| <div class="p-4"> | |
| <details class="rounded-lg border border-slate-200 dark:border-[#3e3d52] bg-white dark:bg-[#1d1c26] p-4 text-slate-600 dark:text-slate-300"> | |
| <summary class="font-bold cursor-pointer text-slate-800 dark:text-white">Ayuda</summary> | |
| <div class="mt-4 space-y-2 text-sm"> | |
| <p>Este dashboard muestra datos de un microcontrolador.</p> | |
| <p><strong>KPIs:</strong> Muestran la última lectura de Temperatura, Humedad y el estado de la conexión de red.</p> | |
| <p><strong>Simulate Data:</strong> Este botón genera nuevos datos aleatorios para actualizar los KPIs y añade una nueva fila a la tabla de "Eventos Recientes".</p> | |
| <p><strong>Lectura de datos:</strong> En una implementación real, estos datos se leerían a través de una petición HTTP al microcontrolador.</p> | |
| </div> | |
| </details> | |
| </div> | |
| <!-- Footer --> | |
| <footer class="p-4 mt-8 text-center text-xs text-slate-500 dark:text-slate-400"> | |
| <p>Dashboard demo para fines educativos. Tamaño total del archivo optimizado para ser < 100 KB.</p> | |
| </footer> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </body></html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ♡(。- ω -) Webserver estático Pico W — kawaii header | |
| # Autor: Javier Ulises Cortes Aguilar | |
| # No. de control: 22211541 | |
| # Materia: Lenguajes de Interfaz | |
| # Fecha: 2025-11-09 | |
| # Función: Sirve archivos estáticos desde el filesystem. | |
| # Nota: "/" -> "index.html.txt" (sin subcarpetas). Sin dependencias externas en Python. | |
| import network, socket, time, os | |
| SSID = "Wokwi-GUEST" | |
| PASSWORD = "" | |
| def connect_wifi(): | |
| wlan = network.WLAN(network.STA_IF) | |
| wlan.active(True) | |
| wlan.connect(SSID, PASSWORD) | |
| for _ in range(60): | |
| if wlan.isconnected(): | |
| break | |
| time.sleep(0.25) | |
| if not wlan.isconnected(): | |
| raise RuntimeError("Fallo WiFi") | |
| ip = wlan.ifconfig()[0] | |
| print("IP:", ip) | |
| return ip | |
| def guess_type(path): | |
| if path.endswith(".css"): | |
| return "text/css; charset=utf-8" | |
| if path.endswith(".js"): | |
| return "application/javascript; charset=utf-8" | |
| return "text/html; charset=utf-8" | |
| def find_file(path): | |
| if path == "/" or path == "/index.html": | |
| if "index.html.txt" in os.listdir(): | |
| return "index.html.txt" | |
| name = path.lstrip("/") | |
| if name in os.listdir(): | |
| return name | |
| if name.endswith(".html") and (name + ".txt") in os.listdir(): | |
| return name + ".txt" | |
| return None | |
| def serve(ip): | |
| s = socket.socket() | |
| s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
| s.bind(("0.0.0.0", 80)) | |
| s.listen(2) | |
| print("HTTP: http://%s/" % ip) | |
| while True: | |
| client, addr = s.accept() | |
| try: | |
| req = client.recv(1024).decode("utf-8", "ignore") | |
| first = req.split("\r\n")[0] | |
| parts = first.split() | |
| path = parts[1] if len(parts) >= 2 else "/" | |
| fpath = find_file(path) | |
| if fpath: | |
| ct = guess_type(path) | |
| client.sendall(b"HTTP/1.1 200 OK\r\nContent-Type: " + ct.encode() + b"\r\nConnection: close\r\n\r\n") | |
| with open(fpath, "rb") as f: | |
| while True: | |
| chunk = f.read(1024) | |
| if not chunk: | |
| break | |
| client.sendall(chunk) | |
| else: | |
| client.sendall(b"HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n404") | |
| except: | |
| try: | |
| client.sendall(b"HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n500") | |
| except: | |
| pass | |
| finally: | |
| client.close() | |
| ip = connect_wifi() | |
| serve(ip) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment