import network
import socket
import time
from machine import Pin
# Configuración de los 4 LEDs
leds = [Pin(2, Pin.OUT), Pin(3, Pin.OUT), Pin(4, Pin.OUT), Pin(5, Pin.OUT)]
# --- PEGA AQUÍ TODO EL CONTENIDO DE TU ARCHIVO code.html ---
# Nota: Usa triple comilla para que acepte varias líneas
html_design = """
<!DOCTYPE html>
<html class="dark" lang="en"><head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>Pico W Virtual Switch Panel</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Space+Grotesk:wght@600;700&family=Material+Symbols+Outlined:wght,[email protected],0..1&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,[email protected],0..1&display=swap" rel="stylesheet"/>
<style>
.material-symbols-outlined {
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
.glass-panel {
backdrop-filter: blur(12px);
background-color: rgba(14, 20, 22, 0.7);
border: 1px solid rgba(255, 255, 255, 0.1);
border-top: 1px solid rgba(255, 255, 255, 0.2);
border-left: 1px solid rgba(255, 255, 255, 0.2);
}
.glow-cyan {
box-shadow: 0px 0px 15px rgba(6, 182, 212, 0.4);
}
body {
background-color: #0f172a;
color: #dee3e6;
}
</style>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
theme: {
extend: {
"colors": {
"primary-fixed-dim": "#4cd7f6",
"on-secondary-fixed": "#131b2e",
"on-secondary-fixed-variant": "#3f465c",
"on-primary": "#003640",
"secondary-container": "#3f465c",
"outline-variant": "#3d494c",
"on-surface-variant": "#bcc9cd",
"surface-bright": "#343a3c",
"tertiary-fixed-dim": "#ffb873",
"error-container": "#93000a",
"background": "#0e1416",
"on-surface": "#dee3e6",
"on-background": "#dee3e6",
"primary-container": "#06b6d4",
"error": "#ffb4ab",
"inverse-surface": "#dee3e6",
"on-secondary-container": "#adb4ce",
"tertiary-fixed": "#ffdcbf",
"surface-container": "#1b2122",
"primary-fixed": "#acedff",
"on-primary-fixed-variant": "#004e5c",
"on-secondary": "#283044",
"outline": "#869397",
"on-tertiary-fixed": "#2d1600",
"inverse-primary": "#00687a",
"on-primary-container": "#00424f",
"on-tertiary": "#4b2800",
"on-error": "#690005",
"surface-container-high": "#252b2d",
"surface-container-low": "#171d1e",
"on-primary-fixed": "#001f26",
"primary": "#4cd7f6",
"on-error-container": "#ffdad6",
"on-tertiary-fixed-variant": "#6a3b00",
"inverse-on-surface": "#2b3133",
"surface-dim": "#0e1416",
"secondary": "#bec6e0",
"on-tertiary-container": "#5b3200",
"tertiary-container": "#e89337",
"surface-container-lowest": "#090f11",
"surface-tint": "#4cd7f6",
"surface-variant": "#303638",
"surface": "#0e1416",
"tertiary": "#ffb873",
"secondary-fixed-dim": "#bec6e0",
"secondary-fixed": "#dae2fd",
"surface-container-highest": "#303638"
},
"borderRadius": {
"DEFAULT": "0.25rem",
"lg": "0.5rem",
"xl": "0.75rem",
"full": "9999px"
},
"spacing": {
"xs": "4px",
"md": "16px",
"container-padding": "32px",
"unit": "4px",
"sm": "8px",
"lg": "24px",
"xl": "48px",
"gutter": "20px"
},
"fontFamily": {
"h2": ["Space Grotesk"],
"data-display": ["JetBrains Mono"],
"body-lg": ["JetBrains Mono"],
"body-md": ["JetBrains Mono"],
"h1": ["Space Grotesk"],
"label-caps": ["JetBrains Mono"]
},
"fontSize": {
"h2": ["24px", {"lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600"}],
"data-display": ["20px", {"lineHeight": "1.2", "letterSpacing": "0.05em", "fontWeight": "700"}],
"body-lg": ["16px", {"lineHeight": "1.6", "letterSpacing": "0em", "fontWeight": "400"}],
"body-md": ["14px", {"lineHeight": "1.5", "letterSpacing": "0em", "fontWeight": "400"}],
"h1": ["36px", {"lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700"}],
"label-caps": ["11px", {"lineHeight": "1", "letterSpacing": "0.1em", "fontWeight": "600"}]
}
},
},
}
</script>
<style>
body {
min-height: max(884px, 100dvh);
}
</style>
</head>
<body class="flex flex-col min-h-screen items-center overflow-x-hidden">
<!-- Top AppBar -->
<header class="fixed top-0 w-full z-50 flex flex-col px-md py-sm bg-surface/70 backdrop-blur-md border-b border-white/10 shadow-[0px_0px_15px_rgba(6,182,212,0.2)]">
<div class="flex items-center justify-between">
<div class="flex items-center gap-sm">
<span class="material-symbols-outlined text-primary text-h2" data-icon="memory">memory</span>
<div class="flex flex-col">
<h1 class="font-h2 text-h2 text-primary tracking-tight">PICO W · Virtual Switch Panel</h1>
<span class="font-label-caps text-label-caps text-on-surface-variant flex items-center gap-xs">
GPIO Controller v1.0
<span class="w-2 h-2 rounded-full bg-[#4ade80] shadow-[0_0_8px_rgba(74,222,128,0.6)] animate-pulse"></span>
</span>
</div>
</div>
<span class="material-symbols-outlined text-primary" data-icon="wifi">wifi</span>
</div>
</header>
<!-- Main Canvas -->
<main class="w-full max-w-[400px] mt-[80px] mb-[100px] px-md py-lg flex flex-col gap-lg">
<!-- SW1 Card (Active State Example) -->
<div class="glass-panel rounded-xl p-md flex flex-col gap-md glow-cyan border-primary/30">
<div class="flex justify-between items-start">
<div class="flex flex-col">
<span class="font-label-caps text-label-caps text-on-surface-variant">GPIO 2</span>
<h2 class="font-data-display text-data-display text-primary">SW1</h2>
</div>
<div class="bg-[#4ade80] text-[#003640] font-label-caps text-label-caps px-sm py-xs rounded-full shadow-[0_0_10px_rgba(74,222,128,0.4)]">
ON
</div>
</div>
<button class="w-full bg-primary-container text-on-primary-container py-md rounded-full font-body-lg font-bold transition-all active:scale-95 duration-200">
DEACTIVATE
</button>
<div class="flex justify-between items-center border-t border-white/5 pt-sm">
<span class="font-label-caps text-label-caps text-on-surface-variant">LAST CHANGED</span>
<span class="font-label-caps text-label-caps text-primary">12:45:02 PM</span>
</div>
</div>
<!-- SW2 Card -->
<div class="glass-panel rounded-xl p-md flex flex-col gap-md">
<div class="flex justify-between items-start">
<div class="flex flex-col">
<span class="font-label-caps text-label-caps text-on-surface-variant">GPIO 3</span>
<h2 class="font-data-display text-data-display text-on-surface">SW2</h2>
</div>
<div class="border border-error/40 text-error/60 font-label-caps text-label-caps px-sm py-xs rounded-full">
OFF
</div>
</div>
<button class="w-full glass-panel text-primary py-md rounded-full font-body-lg font-bold border-white/10 hover:bg-primary/10 transition-all active:scale-95 duration-200">
ACTIVATE
</button>
<div class="flex justify-between items-center border-t border-white/5 pt-sm">
<span class="font-label-caps text-label-caps text-on-surface-variant">LAST CHANGED</span>
<span class="font-label-caps text-label-caps text-on-surface-variant">09:12:44 AM</span>
</div>
</div>
<!-- SW3 Card -->
<div class="glass-panel rounded-xl p-md flex flex-col gap-md">
<div class="flex justify-between items-start">
<div class="flex flex-col">
<span class="font-label-caps text-label-caps text-on-surface-variant">GPIO 4</span>
<h2 class="font-data-display text-data-display text-on-surface">SW3</h2>
</div>
<div class="border border-error/40 text-error/60 font-label-caps text-label-caps px-sm py-xs rounded-full">
OFF
</div>
</div>
<button class="w-full glass-panel text-primary py-md rounded-full font-body-lg font-bold border-white/10 hover:bg-primary/10 transition-all active:scale-95 duration-200">
ACTIVATE
</button>
<div class="flex justify-between items-center border-t border-white/5 pt-sm">
<span class="font-label-caps text-label-caps text-on-surface-variant">LAST CHANGED</span>
<span class="font-label-caps text-label-caps text-on-surface-variant">08:05:11 AM</span>
</div>
</div>
<!-- SW4 Card -->
<div class="glass-panel rounded-xl p-md flex flex-col gap-md">
<div class="flex justify-between items-start">
<div class="flex flex-col">
<span class="font-label-caps text-label-caps text-on-surface-variant">GPIO 5</span>
<h2 class="font-data-display text-data-display text-on-surface">SW4</h2>
</div>
<div class="border border-error/40 text-error/60 font-label-caps text-label-caps px-sm py-xs rounded-full">
OFF
</div>
</div>
<button class="w-full glass-panel text-primary py-md rounded-full font-body-lg font-bold border-white/10 hover:bg-primary/10 transition-all active:scale-95 duration-200">
ACTIVATE
</button>
<div class="flex justify-between items-center border-t border-white/5 pt-sm">
<span class="font-label-caps text-label-caps text-on-surface-variant">LAST CHANGED</span>
<span class="font-label-caps text-label-caps text-on-surface-variant">YESTERDAY</span>
</div>
</div>
</main>
<!-- Bottom Status Bar & Shell -->
<nav class="fixed bottom-0 w-full z-50 flex flex-col bg-surface-container/80 backdrop-blur-lg border-t border-white/20 shadow-[0px_-4px_12px_rgba(0,0,0,0.5)] max-w-[400px]">
<!-- Quick Actions -->
<div class="flex justify-around items-center px-md py-sm border-b border-white/10">
<button class="flex items-center gap-xs text-primary font-label-caps text-label-caps hover:bg-primary/10 p-sm rounded-lg transition-colors active:scale-90 duration-200">
<span class="material-symbols-outlined" data-icon="power_settings_new">power_settings_new</span>
ALL ON
</button>
<button class="flex items-center gap-xs text-on-surface-variant font-label-caps text-label-caps hover:bg-white/5 p-sm rounded-lg transition-colors active:scale-90 duration-200">
<span class="material-symbols-outlined" data-icon="power_off">power_off</span>
ALL OFF
</button>
</div>
<!-- Bottom Nav Shell Logic -->
<div class="flex justify-around items-center px-container-padding py-md">
<div class="flex items-center justify-center bg-primary-container text-on-primary-container rounded-full p-2 shadow-[0_0_15px_rgba(6,182,212,0.4)]">
<span class="material-symbols-outlined" data-icon="dashboard">dashboard</span>
</div>
<div class="flex items-center justify-center text-on-surface-variant p-2 hover:text-primary transition-all">
<span class="material-symbols-outlined" data-icon="settings">settings</span>
</div>
</div>
<!-- System Footer -->
<div class="flex justify-center items-center py-xs bg-surface-container-lowest">
<span class="font-label-caps text-[9px] tracking-widest text-on-surface-variant/50">PICO W @ 192.168.1.42</span>
</div>
</nav>
</body></html>
"""
# ---------------------------------------------------------
# Función para conectar a la red de Wokwi
def conectar_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("Wokwi-GUEST", "")
print("Conectando al WiFi de Wokwi...")
while not wlan.isconnected():
print(".", end="")
time.sleep(0.5)
print("\nConectado! IP:", wlan.ifconfig()[0])
return wlan.ifconfig()[0]
ip = conectar_wifi()
# Servidor Web
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
try:
conn, addr = s.accept()
request = conn.recv(1024).decode()
# Lógica para los botones (debe coincidir con los enlaces/fetch de Stitch)
# Si Stitch usa /toggle?id=0, esto lo activará:
if "/toggle?id=" in request:
try:
# Sacamos el número después del =
id_str = request.split("id=")[1][0]
led_index = int(id_str)
leds[led_index].toggle()
print(f"LED {led_index} cambiado")
except:
pass
# Respuesta al navegador
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(html_design)
conn.close()
except Exception as e:
print("Error:", e)