import machine
import time
import dht
import network
import socket
import _thread
import random
# ===== CONFIGURACIÓN =====
STUDENT_NAME = "Alejandra Gonzalez" # ¡OBLIGATORIO CAMBIAR!
WIFI_SSID = "Wokwi-GUEST" # WiFi simulado (no cambiar)
WIFI_PASSWORD = "" # Sin contraseña
# Pines virtuales (configuración para Wokwi)
DHT_PIN = 15
TRIG_PIN = 14
ECHO_PIN = 13
RGB_RED_PIN = 10
RGB_GREEN_PIN = 11
RGB_BLUE_PIN = 12
TANK_LED_PIN = 9
PUMP_LED_PIN = 8
# ===== INICIALIZACIÓN =====
# Sensores
dht_sensor = dht.DHT22(machine.Pin(DHT_PIN))
ultrasonic_trig = machine.Pin(TRIG_PIN, machine.Pin.OUT)
ultrasonic_echo = machine.Pin(ECHO_PIN, machine.Pin.IN)
# LEDs
rgb_red = machine.Pin(RGB_RED_PIN, machine.Pin.OUT)
rgb_green = machine.Pin(RGB_GREEN_PIN, machine.Pin.OUT)
rgb_blue = machine.Pin(RGB_BLUE_PIN, machine.Pin.OUT)
tank_led = machine.Pin(TANK_LED_PIN, machine.Pin.OUT)
pump_led = machine.Pin(PUMP_LED_PIN, machine.Pin.OUT)
# Variables globales
temperature = 25.0
humidity = 50.0
distance = 30.0
pump_state = False
simulation_time = 0
# ===== FUNCIONES PRINCIPALES =====
def connect_wifi():
"""Simulación de conexión WiFi para Wokwi"""
print(f"Conectando a {WIFI_SSID}...")
time.sleep(2)
print("¡Conectado! (Simulación)")
print("IP: 192.168.0.1")
return True
def read_dht():
"""Simula lectura del sensor DHT22 con variaciones aleatorias"""
global temperature, humidity
# Generar variaciones naturales
temp_change = random.uniform(-0.8, 0.8)
hum_change = random.uniform(-2, 2)
# Aplicar cambios manteniendo dentro de rangos
temperature = max(10, min(40, temperature + temp_change))
humidity = max(30, min(85, humidity + hum_change))
return temperature, humidity
def read_distance():
"""Simula lectura del sensor ultrasónico HC-SR04"""
global distance
# Generar cambio aleatorio
dist_change = random.uniform(-5, 5)
# Mantener dentro de rango válido
new_distance = max(2, min(100, distance + dist_change))
# Añadir comportamiento especial cuando está bajo
if new_distance < 10:
# Oscilar entre 5-15 cuando está bajo
new_distance = random.uniform(5, 15)
distance = new_distance
return distance
def update_leds():
"""Actualiza los LEDs según las condiciones actuales"""
# LED RGB basado en temperatura
if temperature < 18:
rgb_red.off(); rgb_green.off(); rgb_blue.on() # Azul (frío)
elif 18 <= temperature <= 28:
rgb_red.off(); rgb_green.on(); rgb_blue.off() # Verde (ideal)
else:
rgb_red.on(); rgb_green.off(); rgb_blue.off() # Rojo (caliente)
# LED de tanque vacío
tank_led.value(1 if distance < 10 else 0)
def web_server():
"""Servidor web para monitoreo y control"""
s = socket.socket()
s.bind(('0.0.0.0', 80))
s.listen(5)
print("Servidor web iniciado en http://192.168.0.1")
while True:
try:
client, addr = s.accept()
request = client.recv(1024).decode('utf-8')
# Manejar solicitud de activación de bomba
global pump_state
if 'GET /toggle' in request:
pump_state = not pump_state
pump_led.value(1 if pump_state else 0)
# Construir respuesta HTML
html = f"""HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: close
<!DOCTYPE html>
<html>
<head>
<title>Proyecto IoT - {STUDENT_NAME}</title>
<meta http-equiv="refresh" content="5">
<style>
body {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
color: white;
text-align: center;
padding: 20px;
margin: 0;
}}
.container {{
max-width: 800px;
margin: 20px auto;
background: rgba(0, 0, 0, 0.7);
border-radius: 15px;
padding: 20px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
}}
h1 {{
color: #4fc3f7;
text-shadow: 0 0 10px rgba(79, 195, 247, 0.7);
}}
.student-info {{
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 10px;
margin-bottom: 20px;
}}
.sensors {{
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
margin: 20px 0;
}}
.sensor-card {{
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 15px;
width: 200px;
transition: transform 0.3s;
}}
.sensor-card:hover {{
transform: scale(1.05);
background: rgba(255, 255, 255, 0.15);
}}
.sensor-value {{
font-size: 2.5em;
font-weight: bold;
margin: 10px 0;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}}
.status {{
font-size: 1.2em;
padding: 5px;
border-radius: 5px;
display: inline-block;
margin-top: 5px;
}}
.cold {{ color: #29b6f6; }}
.normal {{ color: #66bb6a; }}
.hot {{ color: #ef5350; }}
.low {{
background-color: #d32f2f;
animation: pulse 1.5s infinite;
}}
@keyframes pulse {{
0% {{ opacity: 1; }}
50% {{ opacity: 0.6; }}
100% {{ opacity: 1; }}
}}
.pump-control {{
margin: 30px 0;
padding: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}}
.pump-btn {{
background-color: {'#4CAF50' if pump_state else '#f44336'};
color: white;
border: none;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 1.2em;
margin: 10px 2px;
cursor: pointer;
border-radius: 8px;
transition: all 0.3s;
}}
.pump-btn:hover {{
transform: scale(1.1);
box-shadow: 0 0 15px {'rgba(76, 175, 80, 0.7)' if pump_state else 'rgba(244, 67, 54, 0.7)'};
}}
.footer {{
margin-top: 30px;
color: #bbbbbb;
font-size: 0.9em;
}}
</style>
</head>
<body>
<div class="container">
<div class="student-info">
<h1>Proyecto IoT - Monitoreo de Tanque</h1>
<h2>Estudiante: {STUDENT_NAME}</h2>
<p>Simulación en Wokwi | Tiempo: {simulation_time} segundos</p>
</div>
<div class="sensors">
<div class="sensor-card">
<h3>Temperatura</h3>
<div class="sensor-value">{temperature:.1f}°C</div>
<div class="status {'cold' if temperature < 18 else 'hot' if temperature > 28 else 'normal'}">
{'Frío' if temperature < 18 else 'Caliente' if temperature > 28 else 'Normal'}
</div>
<p>LED:
<span style="color:#FF0000">●</span> Caliente |
<span style="color:#00FF00">●</span> Normal |
<span style="color:#0000FF">●</span> Frío
</p>
</div>
<div class="sensor-card">
<h3>Humedad</h3>
<div class="sensor-value">{humidity:.1f}%</div>
<div class="status {'normal'}">Aceptable</div>
<p>Rango ideal: 40-70%</p>
</div>
<div class="sensor-card">
<h3>Nivel del Tanque</h3>
<div class="sensor-value">{distance:.1f} cm</div>
<div class="status {'low' if distance < 10 else 'normal'}">
{'¡TANQUE VACÍO!' if distance < 10 else 'Nivel Normal'}
</div>
<p>LED: <span style="color:#FF0000">●</span> {distance < 10 and 'ENCENDIDO' or 'APAGADO'}</p>
</div>
</div>
<div class="pump-control">
<h2>Control de Bomba</h2>
<p>Estado actual:
<strong style="color: {'#4CAF50' if pump_state else '#F44336'}">
{'ACTIVADA' if pump_state else 'DESACTIVADA'}
</strong>
</p>
<a href="/toggle">
<button class="pump-btn">
{'DESACTIVAR BOMBA' if pump_state else 'ACTIVAR BOMBA'}
</button>
</a>
<p>LED: <span style="color:#00FF00">●</span> {pump_state and 'ENCENDIDO' or 'APAGADO'}</p>
</div>
<div class="footer">
<p>Sistema simulado en Wokwi | Los valores se generan automáticamente</p>
<p>Actualizado cada 5 segundos</p>
</div>
</div>
</body>
</html>"""
client.send(html)
client.close()
except Exception as e:
print("Error en servidor web:", e)
time.sleep(1)
def led_test():
"""Prueba inicial de todos los LEDs"""
print("Iniciando prueba de LEDs...")
for led in [rgb_red, rgb_green, rgb_blue, tank_led, pump_led]:
led.on()
time.sleep(0.3)
time.sleep(1)
for led in [rgb_red, rgb_green, rgb_blue, tank_led, pump_led]:
led.off()
time.sleep(0.2)
print("Prueba de LEDs completada")
def main():
"""Función principal del programa"""
global simulation_time
# Prueba inicial de LEDs
led_test()
# Conectar a WiFi (simulado)
if not connect_wifi():
print("Error: No se pudo conectar a WiFi")
return
# Iniciar servidor web en segundo plano
_thread.start_new_thread(web_server, ())
print("Sistema iniciado. Presiona Ctrl+C para detener.")
# Bucle principal
start_time = time.ticks_ms()
while True:
try:
# Actualizar tiempo de simulación
simulation_time = (time.ticks_ms() - start_time) // 1000
# Leer sensores
temperature, humidity = read_dht()
distance = read_distance()
# Actualizar LEDs
update_leds()
# Mostrar valores en consola
print("\n" + "="*40)
print(f"Tiempo: {simulation_time}s")
print(f"Temperatura: {temperature:.1f}°C")
print(f"Humedad: {humidity:.1f}%")
print(f"Distancia: {distance:.1f} cm")
print(f"Bomba: {'ACTIVA' if pump_state else 'INACTIVA'}")
print("="*40)
# Esperar 5 segundos
time.sleep(5)
except Exception as e:
print("Error en bucle principal:", e)
time.sleep(10)
# Iniciar programa
if __name__ == "__main__":
main()