Skip to content

Instantly share code, notes, and snippets.

@CortesAguilar
Last active November 25, 2025 00:05
Show Gist options
  • Select an option

  • Save CortesAguilar/0929a62f2813e8413f2809eb370562db to your computer and use it in GitHub Desktop.

Select an option

Save CortesAguilar/0929a62f2813e8413f2809eb370562db to your computer and use it in GitHub Desktop.
Webserver que sirve archivos estáticos (HTML/CSS/JS) desde filesystem.
<!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 &lt; 100 KB.</p>
</footer>
</div>
</div>
</div>
</div>
</body></html>
# ♡(。- ω -) 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)
@CortesAguilar
Copy link
Author

dashboard console

@IoTeacher
Copy link

100

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment