# #############################################################################
# ** Proyecto : 301 - Concurrencia
# ** Plataforma : ESP32 / WROOM
# ** Herramienta : https://www.wokwi.com
# ** : Thonny aplicacion de escritorio descargar en www.thonny.org
# ** Compilador : wokwi Simulador online
# ** Version : 1.0
# ** Fecha/Hora : 08-05-2025, 2:00 pm,
# **
# ** Simulacion de departamento de gestion escolar
# **
# ** Versión : 1
# ** Revisión : A
# ** Release : 0
# ** Bugs & Fixes :
# ** Date : 08-05-2025
# **
# ** By : Jorge Anzaldo
# ** contact : [email protected]
# ** twitter x : @janzaldob
# #############################################################################
import _thread
import time
import random
from machine import Pin
# Nombres de las ventanillas
VENTANILLAS = [
"Inscripción", "Becas", "Pagos", "Kárdex", "Credencial", "Constancias",
"Tutorías", "CENEVAL", "Servicio social", "Prácticas", "Biblioteca",
"Trámites externos", "Egresos", "Titulación"
]
# Pines de los LEDs conectados a la ESP32
LED_PINS = [4, 16, 17, 5, 18, 19, 21, 13, 12, 14, 27, 26, 25, 33]
# Clase semáforo personalizada para permitir solo 3 atenciones simultáneas
class Semaphore:
def __init__(self, count):
self.count = count
self.lock = _thread.allocate_lock()
def acquire(self):
while True:
with self.lock:
if self.count > 0:
self.count -= 1
return
time.sleep(0.01)
def release(self):
with self.lock:
self.count += 1
# Clase principal del sistema
class GestionEscolar:
def __init__(self):
self.num_ventanillas = min(len(LED_PINS), len(VENTANILLAS))
self.leds = [Pin(pin, Pin.OUT) for pin in LED_PINS[:self.num_ventanillas]]
self.sem = Semaphore(3)
self.queue_lock = _thread.allocate_lock()
self.file_lock = _thread.allocate_lock()
self.cola = [] # Cola de alumnos con ventanilla asignada
self.alumno_id = 0
# Crear archivo CSV con encabezado
with open("registro_atencion.csv", "w") as f:
f.write("Alumno_ID,Ventanilla,LED_ID,Inicio,Duración,Fin\n")
# Generador de alumnos: se asignan a una ventanilla aleatoria
def generar_alumnos(self, total):
for _ in range(total):
ventanilla_id = random.randint(0, self.num_ventanillas - 1)
with self.queue_lock:
self.cola.append((self.alumno_id, ventanilla_id))
print(f" Alumno-{self.alumno_id} llegó a la ventanilla {VENTANILLAS[ventanilla_id]}")
self.alumno_id += 1
time.sleep(random.uniform(0.3, 0.8))
# Atención a los alumnos desde cualquier ventanilla
def proceso_atencion(self):
while True:
with self.queue_lock:
if not self.cola:
break
alumno_id, ventanilla_id = self.cola.pop(0)
self.sem.acquire()
try:
led = self.leds[ventanilla_id]
nombre = VENTANILLAS[ventanilla_id]
inicio = time.time()
duracion = random.uniform(1, 3)
print(f" [{nombre}] Atendiendo Alumno-{alumno_id} (LED {ventanilla_id})")
led.on()
time.sleep(duracion)
led.off()
fin = time.time()
with self.file_lock:
with open("registro_atencion.csv", "a") as f:
f.write(f"{alumno_id},{nombre},{ventanilla_id},{inicio:.2f},{duracion:.2f},{fin:.2f}\n")
print(f" [{nombre}] Finalizó atención a Alumno-{alumno_id} ({duracion:.2f} s)")
finally:
self.sem.release()
# ---------------- Funcion Principal ----------------
if __name__ == "__main__":
gestion = GestionEscolar()
# Generar alumnos en segundo plano
_thread.start_new_thread(gestion.generar_alumnos, (30,)) # Cambia a la cantidad deseada
# Lanzar varios hilos para proceso de atención
for _ in range(6): # Múltiples hilos procesan alumnos aleatorios
_thread.start_new_thread(gestion.proceso_atencion, ())
# Esperar suficiente tiempo para completar el proceso
time.sleep(60)
print("\n SIMULACIÓN COMPLETA")