Fase 0: Preparacion y Aprendizaje¶
CORRECCIONES APLICADAS (2026-05-23): T0.8.2 usa el protocolo unificado de
docs/replanificacion/02-protocolo-unificado.md. Se agrega T0.8.3 (test manual del protocolo). Ver detalles endocs/replanificacion/03-fases-corregidas.md.
Resumen¶
- Objetivo: Validar hardware, establecer entorno de desarrollo y familiarizarse con ESP-IDF. Al finalizar esta fase, el desarrollador debe ser capaz de compilar, flashear y depurar proyectos basicos en ESP32-S3 y ESP32-C3, leer sensores, comunicar dispositivos via ESP-NOW y configurar WiFi en modo simultaneo AP+STA.
- Duracion estimada: 3 semanas
- Prerequisitos: Ninguno (es la primera fase del proyecto)
- Hardware necesario:
- 1x ESP32-S3-DevKitC (gateway)
- 1-3x ESP32-C3-DevKitM (nodos sensores)
- 1x Sensor de temperatura (DS18B20 o BMP280)
- 1x Potenciometro (10K recomendado)
- Cables jumper macho-macho y macho-hembra
- 1-2x Breadboard
- 1x Multimetro digital (para medir corriente en mA y uA)
- Cables USB-C (para programacion y alimentacion)
Dependencias externas¶
| Dependencia | Version | Enlace |
|---|---|---|
| ESP-IDF | v5.x (recomendado v5.4) | https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/ |
| VS Code | Ultima estable | https://code.visualstudio.com/ |
| ESP-IDF Extension para VS Code | Ultima estable | https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension |
| Git | >= 2.x | https://git-scm.com/ |
| Python | >= 3.8 (requerido por ESP-IDF) | https://www.python.org/ |
| Node.js | >= 18.x (para herramientas Preact/Vite en Fase 4) | https://nodejs.org/ |
| Vite | >= 5.x (bundler para el dashboard embebido Preact) | https://vitejs.dev/ |
Sub-tarea 0.1: Entorno de desarrollo¶
Objetivo: Tener un entorno funcional capaz de compilar y flashear codigo en ambos chips (ESP32-S3 y ESP32-C3).
Tarea T0.1.1: Instalar ESP-IDF v5.x¶
- Dificultad: Basico
- Descripcion: Descargar e instalar el framework ESP-IDF version 5.x en tu maquina de desarrollo. Pasos:
- Abrir una terminal.
- Clonar el repositorio oficial:
git clone -b v5.4 --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf - Ejecutar el script de instalacion:
cd ~/esp/esp-idf && ./install.sh esp32s3,esp32c3 - Cargar las variables de entorno:
source ~/esp/esp-idf/export.sh - Verificar la instalacion:
idf.py --version - El comando debe imprimir algo como
ESP-IDF v5.4. - Archivos a crear/modificar: Ninguno (instalacion del sistema)
- Criterio de aceptacion:
idf.py --versiondevuelve una version 5.xxtensa-esp32s3-elf-gcc --versionfunciona (toolchain Xtensa para S3)riscv32-esp-elf-gcc --versionfunciona (toolchain RISC-V para C3)- Dependencias: Ninguna
- Pistas: El script
install.shacepta una lista de targets separados por coma. Usarinstall.sh esp32s3,esp32c3instala solo los toolchains necesarios y es mas rapido queinstall.sh all. El scriptexport.shconfigura PATH, IDF_PATH y otras variables. - Errores comunes:
- Olvidar ejecutar
source export.shen cada terminal nueva. Solucion: añadir. ~/esp/esp-idf/export.shal fichero~/.bashrco~/.zshrc. - No usar
--recursiveal clonar, lo que provoca que falten submodulos. Solucion: ejecutargit submodule update --init --recursivedespues de clonar. - Tiempo estimado: 1-2 horas (depende de la velocidad de descarga)
Tarea T0.1.2: Configurar VS Code con extension ESP-IDF¶
- Dificultad: Basico
- Descripcion: Instalar y configurar Visual Studio Code con la extension oficial de Espressif para tener autocompletado, compilacion y flasheo integrados. Pasos:
- Abrir VS Code.
- Ir a Extensions (Ctrl+Shift+X) y buscar "ESP-IDF".
- Instalar la extension "Espressif IDF" (publisher: espressif).
- Al iniciar la extension, seleccionar "Use existing setup" y apuntar al directorio
~/esp/esp-idf. - Verificar que la barra inferior de VS Code muestra los botones de ESP-IDF (build, flash, monitor, target).
- Configurar el target a
esp32s3desde la barra inferior. - Archivos a crear/modificar: Ninguno (configuracion del IDE)
- Criterio de aceptacion:
- La extension muestra los botones de build/flash/monitor en la barra inferior de VS Code
- El autocompletado funciona para funciones de ESP-IDF (probar escribiendo
esp_y ver sugerencias) - Se puede seleccionar el target (esp32s3/esp32c3) desde la barra inferior
- Dependencias: Requiere T0.1.1
- Pistas: La extension busca ESP-IDF en
IDF_PATH. Si no lo encuentra automaticamente, configurar manualmente en Settings > ESP-IDF: Idf Path. Tambien se puede ejecutar el comando "ESP-IDF: Configure ESP-IDF Extension" desde la paleta de comandos (Ctrl+Shift+P). - Errores comunes:
- La extension no encuentra el toolchain si no se configuro el PATH correctamente en T0.1.1. Solucion: verificar que
IDF_PATHapunta al directorio correcto. - Tener multiples versiones de Python instaladas puede confundir a la extension. Solucion: configurar explicitamente la ruta de Python en la configuracion de la extension.
- Tiempo estimado: 30-60 minutos
Tarea T0.1.3: Conectar ESP32-S3 por USB y verificar comunicacion¶
- Dificultad: Basico
- Descripcion: Conectar fisicamente la placa ESP32-S3-DevKitC al ordenador por USB y verificar que el sistema operativo la reconoce. Pasos:
- Conectar la placa ESP32-S3-DevKitC al ordenador usando un cable USB-C (asegurarse de que es un cable de datos, no solo de carga).
- En Linux, ejecutar
ls /dev/ttyUSB*ols /dev/ttyACM*para identificar el puerto. El ESP32-S3 normalmente aparece como/dev/ttyACM0(USB nativo) o/dev/ttyUSB0(si usa chip UART externo). - Verificar con
dmesg | tail -20que el kernel ha detectado el dispositivo. - Si da error de permisos al acceder al puerto, añadir tu usuario al grupo
dialout:sudo usermod -aG dialout $USERy cerrar/abrir sesion. - Probar la comunicacion basica:
python -m serial.tools.miniterm /dev/ttyACM0 115200(Ctrl+] para salir). - Archivos a crear/modificar: Ninguno
- Criterio de aceptacion:
- El comando
ls /dev/ttyACM*ols /dev/ttyUSB*muestra al menos un dispositivo al conectar la placa dmesg | tailmuestra un mensaje de deteccion del dispositivo USB- El miniterm se conecta sin error de permisos
- Dependencias: Ninguna (solo hardware)
- Pistas: El ESP32-S3-DevKitC tiene USB nativo (USB-OTG) ademas del conector UART. El puerto USB nativo suele aparecer como
/dev/ttyACM0. Usadmesg | grep ttypara filtrar solo los mensajes relevantes. - Errores comunes:
- Usar un cable USB de solo carga (sin lineas de datos). Solucion: probar con otro cable si no aparece nada en
dmesg. - No tener permisos de acceso al puerto serie. Solucion:
sudo usermod -aG dialout $USERy reiniciar sesion (cerrar y volver a abrir terminal no es suficiente, hay que cerrar sesion del sistema). - Tiempo estimado: 15-30 minutos
Tarea T0.1.4: Compilar y flashear hello_world en ESP32-S3¶
- Dificultad: Basico
- Descripcion: Compilar el ejemplo basico
hello_worldincluido en ESP-IDF y flashearlo en la placa ESP32-S3. Este es el primer contacto con el ciclo completo de desarrollo. Pasos: - Copiar el ejemplo a una carpeta de trabajo:
cp -r ~/esp/esp-idf/examples/get-started/hello_world ~/esp/hello_world_s3 - Entrar en la carpeta:
cd ~/esp/hello_world_s3 - Cargar variables de entorno:
source ~/esp/esp-idf/export.sh - Configurar el target:
idf.py set-target esp32s3 - Compilar:
idf.py build - Flashear y abrir monitor serie:
idf.py -p /dev/ttyACM0 flash monitor - Observar la salida: debe mostrar "Hello world!" seguido de una cuenta regresiva y reinicio.
- Para salir del monitor: pulsar
Ctrl+]. - Archivos a crear/modificar: Ninguno (se usa el ejemplo tal cual)
- Criterio de aceptacion:
- La compilacion termina sin errores (
Project build complete.) - El flasheo termina exitosamente (
Hard resetting via RTS pin...) - El monitor serie muestra "Hello world!" y la informacion del chip (modelo, cores, revision)
- El dispositivo se reinicia automaticamente tras la cuenta regresiva
- Dependencias: Requiere T0.1.1, T0.1.3
- Pistas:
idf.py set-targetlimpia el build directory y configura el toolchain adecuado.idf.py flash monitorejecuta ambos comandos secuencialmente. El flag-pespecifica el puerto serie. Si el monitor no muestra texto legible, verificar que el baudrate es 115200 (por defecto en ESP-IDF). - Errores comunes:
- No ejecutar
set-targetantes de compilar, lo que causa errores del toolchain. Solucion: siempre ejecutaridf.py set-target esp32s3en un proyecto nuevo. - El flash falla con "Failed to connect": mantener pulsado el boton BOOT de la placa mientras se inicia el flasheo, y soltar al ver "Connecting...".
- Tiempo estimado: 30-60 minutos
Tarea T0.1.5: Compilar y flashear hello_world en ESP32-C3¶
- Dificultad: Basico
- Descripcion: Repetir el proceso de T0.1.4 pero para la placa ESP32-C3-DevKitM. La diferencia principal es que el C3 usa arquitectura RISC-V en lugar de Xtensa. Pasos:
- Copiar el ejemplo:
cp -r ~/esp/esp-idf/examples/get-started/hello_world ~/esp/hello_world_c3 - Entrar en la carpeta:
cd ~/esp/hello_world_c3 - Cargar variables:
source ~/esp/esp-idf/export.sh - Configurar el target:
idf.py set-target esp32c3 - Compilar:
idf.py build - Flashear y monitorizar:
idf.py -p /dev/ttyUSB0 flash monitor(el puerto puede ser diferente al S3) - Verificar que muestra "Hello world!" y que indica un solo core (el C3 es single-core).
- Archivos a crear/modificar: Ninguno
- Criterio de aceptacion:
- La compilacion usa el toolchain RISC-V (
riscv32-esp-elf-gcc) - El monitor muestra "Hello world!" con informacion del chip ESP32-C3
- La informacion del chip indica 1 CPU core (a diferencia del S3 que tiene 2)
- Dependencias: Requiere T0.1.1, T0.1.3
- Pistas: El ESP32-C3 usa toolchain RISC-V (
riscv32-esp-elf-gcc), no Xtensa. El puerto serie del C3 puede ser diferente al del S3 si ambos estan conectados simultaneamente. Usarls /dev/tty*para identificar cada uno. Puedes desconectar uno y ver cual desaparece. - Errores comunes:
- No cambiar el target antes de compilar (si antes compilaste para S3). Solucion:
idf.py set-target esp32c3limpia el build anterior automaticamente. - Confundir los puertos si ambos dispositivos estan conectados. Solucion: conectar solo un dispositivo a la vez al principio, o etiquetar los cables USB.
- Tiempo estimado: 20-40 minutos
Tarea T0.1.6: Crear repositorio Git con estructura del proyecto¶
- Dificultad: Basico
- Descripcion: Inicializar un repositorio Git y crear la estructura de carpetas que usara el proyecto completo. Esto establece la organizacion del codigo desde el principio. Pasos:
- Crear el directorio raiz del proyecto y entrar en el:
mkdir -p ~/Dev/ESP32-fg && cd ~/Dev/ESP32-fg - Inicializar Git:
git init - Crear la estructura de carpetas:
- Crear ficheros placeholder (
README.mdvacio o con titulo) en cada carpeta para que Git las rastree. - Crear un
.gitignorecon las exclusiones tipicas de ESP-IDF:build/,sdkconfig.old,managed_components/,dependencies.lock. - Hacer el primer commit:
git add . && git commit -m "feat: estructura inicial del proyecto" - Archivos a crear/modificar:
.gitignorefirmware/gateway/main/.gitkeepfirmware/node/main/.gitkeepfirmware/common/protocol/.gitkeepserver/.gitkeepdashboard/.gitkeepdocs/.gitkeeptools/.gitkeep- Criterio de aceptacion:
git statusmuestra un repositorio limpio tras el commit- La estructura de carpetas existe y es correcta:
tree -dmuestra firmware/gateway, firmware/node, firmware/common, server, dashboard, docs, tools - El
.gitignoreexcluye correctamente los directorios de build - Dependencias: Ninguna
- Pistas: Los ficheros
.gitkeepson una convencion (Git no rastrea carpetas vacias). El.gitignorede ESP-IDF tipicamente incluye:build/,sdkconfig.old,managed_components/,dependencies.lock,*.pyc,__pycache__/. - Errores comunes:
- Olvidar el
.gitignorey subir accidentalmente la carpetabuild/(que puede pesar cientos de MB). Solucion: crear el.gitignoreantes del primer commit. - No usar
--recursivesi luego se añaden submodulos. Solucion: documentar en el README como clonar el proyecto. - Tiempo estimado: 30-45 minutos
Checkpoint 0.1: En este punto debes poder abrir una terminal, cargar ESP-IDF con
source export.sh, compilar un proyecto para ESP32-S3 o ESP32-C3, flashearlo y ver la salida en el monitor serie. Tambien debes tener un repositorio Git con la estructura del proyecto. Si algo falla, revisa las tareas anteriores antes de continuar.
Sub-tarea 0.2: Blink y GPIO¶
Objetivo: Aprender a controlar pines GPIO de salida. Crear un proyecto propio desde cero (sin copiar el ejemplo).
Tarea T0.2.1: Crear proyecto blink para ESP32-S3 desde cero¶
- Dificultad: Basico
- Descripcion: Crear un proyecto nuevo (no copiar el ejemplo blink) que haga parpadear el LED integrado del ESP32-S3-DevKitC. Esto enseña como se estructura un proyecto ESP-IDF minimo. Pasos:
- Crear el archivo
main.cdentro defirmware/gateway/main/. - Incluir las cabeceras necesarias:
driver/gpio.h,freertos/FreeRTOS.h,freertos/task.h. - En
app_main():- Resetear el pin GPIO:
gpio_reset_pin(GPIO_NUM_48)(el LED del DevKitC-S3 tipicamente esta en GPIO48, verificar con el esquematico de tu placa). - Configurar como salida:
gpio_set_direction(GPIO_NUM_48, GPIO_MODE_OUTPUT). - En un bucle infinito, alternar el nivel del pin con
gpio_set_level()y esperar convTaskDelay(pdMS_TO_TICKS(500)).
- Resetear el pin GPIO:
- Crear
firmware/gateway/main/CMakeLists.txtconidf_component_register(SRCS "main.c" INCLUDE_DIRS "."). - Crear
firmware/gateway/CMakeLists.txtcon el boilerplate de proyecto ESP-IDF. - Compilar, flashear y verificar que el LED parpadea.
- Archivos a crear/modificar:
firmware/gateway/main/main.cfirmware/gateway/main/CMakeLists.txtfirmware/gateway/CMakeLists.txt- Criterio de aceptacion:
- El proyecto compila sin warnings (usar
-Wallsi es posible) - El LED de la placa parpadea a un ritmo constante de 500ms encendido / 500ms apagado
- El codigo usa las funciones
gpio_reset_pin,gpio_set_direction,gpio_set_level(no atajos como escribir directamente en registros) - Dependencias: Requiere T0.1.4, T0.1.6
- Pistas:
gpio_reset_pin()desconecta el pin de cualquier funcion especial y lo prepara para uso general.pdMS_TO_TICKS()convierte milisegundos a ticks de FreeRTOS (necesario paravTaskDelay). La funcionapp_main()es el punto de entrada de ESP-IDF (equivalente amain()en C estandar). ElCMakeLists.txtdel proyecto raiz debe contener: - Errores comunes:
- Usar
delay()en lugar devTaskDelay(). ESP-IDF usa FreeRTOS, ydelay()no existe. Siempre usarvTaskDelay(pdMS_TO_TICKS(ms)). - Numero de GPIO incorrecto para el LED. El GPIO del LED varia segun la version de la placa. Consultar el esquematico o probar con GPIO48 (comun en ESP32-S3-DevKitC-1).
- Tiempo estimado: 1-2 horas
Tarea T0.2.2: Configurar intervalo de blink via menuconfig (Kconfig)¶
- Dificultad: Intermedio
- Descripcion: Crear una opcion de configuracion personalizada en Kconfig para que el intervalo de parpadeo sea configurable sin modificar el codigo fuente. Pasos:
- Crear el archivo
firmware/gateway/main/Kconfig.projbuild. - Definir un menu con una opcion de tipo
int: - En
main.c, reemplazar el valor hardcoded500porCONFIG_BLINK_PERIOD_MS. - Ejecutar
idf.py menuconfig, navegar al menu "Configuracion Blink" y cambiar el valor a 1000. - Recompilar y flashear. Verificar que el LED ahora parpadea mas lento.
- Cambiar de nuevo a 200ms desde menuconfig y verificar que parpadea mas rapido.
- Archivos a crear/modificar:
firmware/gateway/main/Kconfig.projbuild(crear)firmware/gateway/main/main.c(modificar para usarCONFIG_BLINK_PERIOD_MS)- Criterio de aceptacion:
idf.py menuconfigmuestra el menu "Configuracion Blink" con la opcion de periodo- Cambiar el valor en menuconfig y recompilar cambia efectivamente la velocidad de parpadeo
- El rango esta validado: no se puede poner un valor menor a 100 ni mayor a 5000
- El codigo fuente
main.cno contiene ningun valor de intervalo hardcoded - Dependencias: Requiere T0.2.1
- Pistas: Los archivos
Kconfig.projbuilden el directoriomain/se incluyen automaticamente en el menu de configuracion. Las variables definidas en Kconfig se acceden en C comoCONFIG_<NOMBRE>. El archivosdkconfigalmacena la configuracion actual (no editarlo manualmente, usar siempremenuconfig). La directivarangeen Kconfig valida los limites. - Errores comunes:
- Editar
sdkconfigdirectamente en lugar de usarmenuconfig. Los cambios manuales ensdkconfigpueden perderse o causar inconsistencias. - Olvidar recompilar despues de cambiar la configuracion.
idf.py builddetecta cambios ensdkconfigautomaticamente, pero hay que ejecutarlo. - Tiempo estimado: 1-2 horas
Tarea T0.2.3: Crear proyecto blink para ESP32-C3¶
- Dificultad: Basico
- Descripcion: Repetir el ejercicio de blink pero para el ESP32-C3-DevKitM, prestando atencion a las diferencias de hardware. Pasos:
- Crear la misma estructura de proyecto en
firmware/node/. - Copiar el codigo de
firmware/gateway/main/main.ccomo punto de partida. - Cambiar el numero de GPIO del LED. En ESP32-C3-DevKitM, el LED RGB addressable suele estar en GPIO8. Si tu placa no tiene LED integrado, conectar un LED externo con resistencia de 330 ohm a cualquier GPIO disponible.
- Configurar el target:
idf.py set-target esp32c3. - Compilar y flashear en el C3.
- Verificar que el LED parpadea.
- Archivos a crear/modificar:
firmware/node/main/main.cfirmware/node/main/CMakeLists.txtfirmware/node/CMakeLists.txt- Criterio de aceptacion:
- El proyecto compila correctamente para target
esp32c3 - El LED de la placa ESP32-C3 parpadea al intervalo configurado
- El Kconfig del intervalo tambien funciona en este proyecto
- Dependencias: Requiere T0.1.5, T0.2.1
- Pistas: El ESP32-C3-DevKitM usa un LED RGB tipo WS2812 en GPIO8. Para controlarlo como GPIO simple (sin colores),
gpio_set_level(GPIO_NUM_8, 1)enciende el LED en blanco. Si quieres control de colores, necesitaras el driver RMT (que se vera mas adelante). Algunos kits C3 tienen un LED simple en GPIO8 en lugar del WS2812. - Errores comunes:
- Intentar flashear firmware compilado para S3 en un C3 (o viceversa). Siempre verificar el target con
idf.py set-target. - El LED RGB WS2812 no responde a
gpio_set_levelde la misma forma que un LED simple. Si no funciona, probar con un LED externo conectado a otro GPIO. - Tiempo estimado: 30-60 minutos
Checkpoint 0.2: Ahora debes tener dos proyectos funcionales (gateway y node), ambos haciendo parpadear un LED. El intervalo es configurable via menuconfig. Si necesitas mas practica con GPIO, intenta añadir un segundo LED o un boton como entrada (usando
gpio_set_directionconGPIO_MODE_INPUTygpio_get_level).
Sub-tarea 0.3: UART y Logging¶
Objetivo: Dominar el sistema de logging de ESP-IDF para depuracion. El logging es la herramienta principal de diagnostico durante todo el proyecto.
Tarea T0.3.1: Practicar sistema de logging con diferentes niveles y TAGs¶
- Dificultad: Basico
- Descripcion: Aprender a usar las macros de logging de ESP-IDF para imprimir mensajes categorizados por nivel de severidad y modulo. Pasos:
- En el proyecto gateway (
firmware/gateway/main/main.c), añadir al inicio del archivo: - En
app_main(), antes del bucle del blink, añadir mensajes de cada nivel: - Dentro del bucle, añadir un log de info con el estado del LED:
- Incluir la cabecera
esp_log.h. - Compilar, flashear y observar los mensajes coloreados en el monitor serie.
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- El monitor serie muestra mensajes con colores diferentes para cada nivel (rojo para ERROR, amarillo para WARNING, verde para INFO)
- Cada mensaje incluye el TAG entre corchetes, el nivel y el timestamp
- Los mensajes DEBUG y VERBOSE pueden no aparecer (depende de la configuracion por defecto, que suele ser INFO)
- Dependencias: Requiere T0.2.1
- Pistas: La cabecera es
#include "esp_log.h". Las macros son:ESP_LOGE(Error, rojo),ESP_LOGW(Warning, amarillo),ESP_LOGI(Info, verde),ESP_LOGD(Debug, sin color),ESP_LOGV(Verbose, sin color). El TAG es un string que identifica el modulo o componente que genera el mensaje. Convencion: usar el nombre del archivo o modulo. - Errores comunes:
- No incluir
esp_log.h. El compilador dara error de "implicit declaration of function". - Usar
printfen lugar de las macros ESP_LOGx. Elprintffunciona pero no incluye timestamp, TAG ni nivel, y no se puede filtrar. Siempre preferir ESP_LOGx. - Tiempo estimado: 30-60 minutos
Tarea T0.3.2: Controlar niveles de log en compilacion y en runtime¶
- Dificultad: Basico
- Descripcion: Aprender a filtrar los mensajes de log por nivel y por TAG, tanto en la configuracion de compilacion (menuconfig) como en tiempo de ejecucion. Pasos:
- Cambiar nivel por defecto en compilacion:
- Ejecutar
idf.py menuconfig. - Navegar a
Component config > Log output > Default log verbosity. - Cambiar de
InfoaDebug. Recompilar y flashear. - Ahora los mensajes
ESP_LOGDdeben ser visibles.
- Ejecutar
- Cambiar nivel en runtime para un TAG especifico:
- En
app_main(), al inicio, añadir: - Esto hace que el TAG "gateway_main" muestre todos los mensajes (incluido VERBOSE), pero el TAG "wifi" solo muestre WARNING y ERROR.
- En
- Verificar:
- Los mensajes VERBOSE de "gateway_main" aparecen.
- Los mensajes INFO de componentes WiFi (si los hay) no aparecen.
- Experimentar con
esp_log_level_set("*", ESP_LOG_ERROR)para silenciar todo excepto errores. - Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- Al cambiar el nivel en menuconfig a DEBUG, los mensajes
ESP_LOGDse muestran esp_log_level_set()en runtime cambia efectivamente los mensajes visibles para un TAG especifico- Se puede demostrar que un TAG muestra VERBOSE mientras otro solo muestra ERROR
- El wildcard
"*"afecta a todos los TAGs - Dependencias: Requiere T0.3.1
- Pistas:
esp_log_level_set(TAG, nivel)cambia el nivel en runtime. Los niveles son:ESP_LOG_NONE,ESP_LOG_ERROR,ESP_LOG_WARN,ESP_LOG_INFO,ESP_LOG_DEBUG,ESP_LOG_VERBOSE. El nivel de compilacion es el maximo posible: si compilas con nivel INFO,esp_log_level_setno puede activar DEBUG en runtime (el codigo para DEBUG ni siquiera esta compilado). Para maxima flexibilidad, compilar conVERBOSEy filtrar en runtime. - Errores comunes:
- Compilar con nivel INFO e intentar activar DEBUG en runtime. No funciona porque el codigo del
ESP_LOGDfue eliminado por el preprocesador en compilacion. - Confundir el orden de los niveles. De menos a mas detalle: NONE < ERROR < WARN < INFO < DEBUG < VERBOSE.
- Tiempo estimado: 30-60 minutos
Checkpoint 0.3: Ahora puedes usar el sistema de logging para depurar tu codigo de forma efectiva. Debes poder filtrar mensajes por nivel y por modulo. A partir de aqui, usa
ESP_LOGI/ESP_LOGW/ESP_LOGEen todo tu codigo en lugar deprintf.
Sub-tarea 0.4: Lectura de sensor I2C/ADC¶
Objetivo: Leer datos de sensores reales (temperatura y valor analogico) usando los perifericos I2C y ADC del ESP32.
Tarea T0.4.1: Conectar sensor de temperatura al ESP32-S3¶
- Dificultad: Basico
- Descripcion: Realizar la conexion fisica del sensor de temperatura a la placa ESP32-S3. Dependiendo del sensor que tengas, seguir el esquema correspondiente. Pasos:
- Si usas DS18B20 (1-Wire):
- Conectar VDD del sensor a 3.3V del ESP32.
- Conectar GND del sensor a GND del ESP32.
- Conectar DQ (datos) del sensor a un GPIO libre (por ejemplo GPIO4).
- Colocar una resistencia pull-up de 4.7K ohm entre DQ y VDD (3.3V).
- Si usas BMP280 (I2C):
- Conectar VCC a 3.3V, GND a GND.
- Conectar SDA a GPIO1 (o cualquier GPIO que soporte I2C), SCL a GPIO2.
- Colocar resistencias pull-up de 4.7K ohm en SDA y SCL (a 3.3V). Muchos modulos breakout ya las incluyen.
- Verificar con multimetro que:
- El voltaje entre VDD y GND es ~3.3V.
- Las lineas de datos tienen pull-up (voltaje en alto ~3.3V cuando estan en reposo).
- Documentar el esquema de conexion (foto o diagrama) en
docs/conexiones-sensor.md. - Archivos a crear/modificar:
docs/conexiones-sensor.md(crear con esquema de conexion)- Criterio de aceptacion:
- El sensor esta conectado fisicamente al ESP32-S3 segun el esquema
- El multimetro confirma voltaje correcto en VDD (3.3V +/- 0.2V)
- Las lineas de datos tienen pull-up verificado (voltaje alto en reposo)
- Existe documentacion del esquema de conexion
- Dependencias: Ninguna (solo hardware)
- Pistas: Los sensores de temperatura suelen venir en modulos breakout con los pull-ups incluidos. Verificar la documentacion del modulo antes de añadir resistencias externas (pull-up duplicado puede causar problemas). El DS18B20 solo necesita un pin de datos. El BMP280 necesita dos (SDA, SCL). Algunos modulos BMP280 soportan tanto I2C como SPI; asegurarse de que esta configurado en modo I2C (ver jumpers del modulo).
- Errores comunes:
- Olvidar la resistencia pull-up de 4.7K en 1-Wire o I2C. Sin pull-up, la comunicacion falla silenciosamente (no hay error, simplemente no lee datos).
- Conectar el sensor a 5V en lugar de 3.3V. Los pines del ESP32 son de 3.3V y no toleran 5V. Esto puede dañar el chip permanentemente.
- Tiempo estimado: 30-60 minutos
Tarea T0.4.2: Leer temperatura con el driver apropiado¶
- Dificultad: Intermedio
- Descripcion: Escribir codigo para leer la temperatura del sensor conectado en T0.4.1 usando el driver correspondiente de ESP-IDF. Pasos:
- Si usas DS18B20 (1-Wire con driver RMT):
- Añadir la dependencia del componente 1-Wire en
idf_component.yml: - Inicializar el bus 1-Wire con
onewire_bus_rmt: - Buscar dispositivos en el bus y leer temperatura.
- Añadir la dependencia del componente 1-Wire en
- Si usas BMP280 (I2C):
- Configurar el bus I2C master:
- Añadir el dispositivo al bus con
i2c_master_bus_add_device. - Leer los registros del BMP280 para obtener temperatura.
- Imprimir la temperatura leida con
ESP_LOGI. - Repetir la lectura en un bucle cada 2 segundos.
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)firmware/gateway/main/idf_component.yml(crear si se usa componente del registry)- Criterio de aceptacion:
- La temperatura se lee correctamente (valor coherente con la temperatura ambiente, +-2 grados C)
- Las lecturas se repiten periodicamente cada 2 segundos
- No hay errores en el log durante la comunicacion con el sensor
- Si se calienta el sensor (tocandolo con el dedo), el valor sube visiblemente
- Dependencias: Requiere T0.4.1, T0.2.1
- Pistas: El ESP-IDF Component Registry (https://components.espressif.com/) tiene drivers listos para DS18B20 y muchos otros sensores. Buscar "ds18b20" en el registry. Para BMP280, puede que necesites escribir el driver a mano o buscar un componente de terceros. La direccion I2C del BMP280 es tipicamente 0x76 o 0x77 (depende del estado del pin SDO). La nueva API I2C de ESP-IDF v5.x usa
i2c_master_bus_handle_t(no la API legacyi2c_driver_install). - Errores comunes:
- Usar la API I2C legacy (
i2c_driver_install,i2c_cmd_link_create) en lugar de la nueva API master. La API legacy esta deprecada en ESP-IDF v5.x. - Direccion I2C incorrecta del sensor. Solucion: hacer un escaneo I2C (bucle de 0x01 a 0x7F intentando
i2c_master_probe) para descubrir la direccion real. - Tiempo estimado: 2-4 horas
Tarea T0.4.3: Leer valor analogico con ADC (potenciometro)¶
- Dificultad: Intermedio
- Descripcion: Conectar un potenciometro a un pin ADC del ESP32-S3 y leer el valor analogico. Esto simula la lectura de sensores analogicos como sondas de pH o turbidez. Pasos:
- Conectar el potenciometro:
- Terminal izquierdo a GND.
- Terminal derecho a 3.3V.
- Terminal central (wiper) a GPIO3 (u otro pin ADC1, ver documentacion del ESP32-S3).
- Configurar el ADC en el codigo:
adc_oneshot_unit_handle_t adc_handle; adc_oneshot_unit_init_cfg_t init_config = { .unit_id = ADC_UNIT_1, }; adc_oneshot_new_unit(&init_config, &adc_handle); adc_oneshot_chan_cfg_t channel_config = { .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_DEFAULT, }; adc_oneshot_config_channel(adc_handle, ADC_CHANNEL_2, &channel_config); - Leer el valor en un bucle:
- Calibrar el ADC para obtener voltaje real:
adc_cali_handle_t cali_handle; adc_cali_curve_fitting_config_t cali_config = { .unit_id = ADC_UNIT_1, .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_DEFAULT, }; adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle); int voltage_mv; adc_cali_raw_to_voltage(cali_handle, raw_value, &voltage_mv); ESP_LOGI(TAG, "Voltaje: %d mV", voltage_mv); - Girar el potenciometro y verificar que el valor cambia de ~0 a ~3300 mV.
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- El valor raw del ADC cambia al girar el potenciometro (rango ~0 a ~4095 para 12 bits)
- El valor calibrado en mV va de ~0 a ~3300 mV
- Los extremos del potenciometro corresponden a valores cercanos a 0 mV y 3300 mV
- Las lecturas son estables (variacion menor a +-50 mV cuando el potenciometro esta fijo)
- Dependencias: Requiere T0.2.1
- Pistas: Los canales ADC estan mapeados a GPIOs especificos. En ESP32-S3: ADC1_CHANNEL_0 = GPIO1, ADC1_CHANNEL_1 = GPIO2, ADC1_CHANNEL_2 = GPIO3, etc. Consultar la tabla de mapeo en la documentacion.
ADC_ATTEN_DB_12permite leer hasta ~3.3V (atenuacion de 12dB). Sin atenuacion, el rango es solo ~0-1V. La cabecera para la calibracion esesp_adc/adc_cali_scheme.h(para curve fitting) oesp_adc/adc_cali.h(API general). - Errores comunes:
- No configurar la atenuacion del ADC. Sin atenuacion (
ADC_ATTEN_DB_0), el rango es solo 0-1V, y voltajes mayores saturan la lectura. Siempre usarADC_ATTEN_DB_12para señales de 0-3.3V. - Usar un pin ADC2. ADC2 esta compartido con WiFi y no se puede usar cuando WiFi esta activo. Siempre usar ADC1 para lecturas fiables.
- Tiempo estimado: 1-3 horas
Tarea T0.4.4: Imprimir lecturas formateadas con timestamp¶
- Dificultad: Basico
- Descripcion: Formatear la salida de las lecturas del sensor de temperatura y del ADC de forma clara y consistente, incluyendo el timestamp desde el arranque. Pasos:
- Crear una funcion auxiliar que obtenga el timestamp en milisegundos:
- Formatear las lecturas asi:
- Asegurarse de que el formato sea consistente en todas las lecturas.
- Imprimir una lectura de cada sensor cada 2 segundos.
- Usar
ESP_LOGIcon formato string para las impresiones. - Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- Cada linea de lectura incluye timestamp en milisegundos entre corchetes
- La temperatura muestra un decimal (e.g.,
23.5 °C) - El ADC muestra tanto el valor raw como el voltaje calibrado
- El formato es consistente y legible en el monitor serie
- El timestamp incrementa correctamente entre lecturas (~2000ms de diferencia)
- Dependencias: Requiere T0.4.2, T0.4.3
- Pistas:
esp_timer_get_time()devuelve microsegundos desde el arranque comoint64_t. Dividir por 1000 para obtener milisegundos. Para formatear floats, usar%.1fen el string de formato. En ESP-IDF,printfyESP_LOGIsoportan floats por defecto (a diferencia de algunos toolchains embebidos que los desactivan por tamaño). El caracter°se imprime correctamente si el terminal soporta UTF-8. - Errores comunes:
- Overflow de
uint32_tal dividir microsegundos.esp_timer_get_time()devuelveint64_t(microsegundos). Convertir auint32_tmilisegundos permite ~49 dias antes del overflow, lo cual es suficiente para pruebas. - Intentar imprimir floats y obtener "nan" o "0.000000". Esto ocurre si el valor de temperatura es un entero y no se castea a float correctamente. Asegurarse de que la variable de temperatura es
floato hacer cast explicito. - Tiempo estimado: 30-60 minutos
Checkpoint 0.4: Ahora puedes leer datos de sensores reales (temperatura digital y valor analogico) y mostrarlos de forma formateada. El monitor serie debe mostrar lecturas continuas con timestamps. Verifica que la temperatura cambia al calentar el sensor y que el voltaje cambia al girar el potenciometro.
Sub-tarea 0.5: ESP-NOW basico¶
Objetivo: Establecer comunicacion inalambrica entre dos ESP32 usando el protocolo ESP-NOW. Este sera el protocolo principal de comunicacion nodo-gateway en el proyecto.
Tarea T0.5.1: Crear proyecto sender en ESP32-C3¶
- Dificultad: Intermedio
- Descripcion: Crear un proyecto que envie datos simulados via ESP-NOW desde el ESP32-C3 (nodo). ESP-NOW es un protocolo ligero de Espressif que permite comunicacion directa entre dispositivos sin necesidad de router WiFi. Pasos:
- En
firmware/node/main/main.c, crear una estructura para los datos a enviar: - Inicializar NVS (requerido por WiFi):
- Inicializar WiFi en modo STA (necesario para ESP-NOW, aunque no nos conectemos a ningun AP):
- Inicializar ESP-NOW y registrar callback de envio:
- Añadir el peer (gateway) con su MAC address (por ahora usar broadcast
FF:FF:FF:FF:FF:FF): - En un bucle, llenar la estructura con datos simulados y enviar cada 2 segundos:
- Archivos a crear/modificar:
firmware/node/main/main.c(modificar)- Criterio de aceptacion:
- El proyecto compila y flashea correctamente en ESP32-C3
- El callback de envio se ejecuta cada 2 segundos indicando que el paquete fue enviado
- El log muestra los datos que se estan enviando (sensor_id, temperatura, etc.)
- No hay errores de inicializacion de WiFi o ESP-NOW en el log
- Dependencias: Requiere T0.2.3
- Pistas: ESP-NOW requiere que WiFi este inicializado y arrancado, pero no necesita estar conectado a un AP.
esp_now_sendes asincrona: retorna inmediatamente y el resultado se notifica via callback. Las cabeceras necesarias son:esp_now.h,esp_wifi.h,nvs_flash.h,esp_netif.h,esp_event.h. El tamaño maximo de un paquete ESP-NOW es 250 bytes. - Errores comunes:
- No inicializar WiFi antes de ESP-NOW.
esp_now_init()devolveraESP_ERR_ESPNOW_NOT_INITsi WiFi no esta inicializado. Siempre llamar aesp_wifi_init(),esp_wifi_set_mode()yesp_wifi_start()antes. - No inicializar NVS. WiFi requiere NVS para almacenar calibracion del PHY. Sin NVS,
esp_wifi_init()falla. - Tiempo estimado: 2-3 horas
Tarea T0.5.2: Crear proyecto receiver en ESP32-S3¶
- Dificultad: Intermedio
- Descripcion: Crear el receptor ESP-NOW en el ESP32-S3 (gateway) que reciba los datos enviados por el nodo C3. Pasos:
- En
firmware/gateway/main/main.c, añadir la misma definicion desensor_data_tque en el sender. - Inicializar NVS, WiFi (modo STA) y ESP-NOW igual que en el sender.
- Registrar el callback de recepcion:
static void recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) { if (len == sizeof(sensor_data_t)) { sensor_data_t *sensor = (sensor_data_t *)data; ESP_LOGI(TAG, "Recibido de " MACSTR ": sensor=%d, temp=%.1f, adc=%d", MAC2STR(info->src_addr), sensor->sensor_id, sensor->temperatura, sensor->adc_value); } } esp_now_register_recv_cb(recv_cb); - En este caso NO es necesario añadir un peer ni enviar datos (solo recibimos).
- Flashear ambos dispositivos (C3 como sender, S3 como receiver) y verificar comunicacion.
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- El ESP32-S3 recibe los datos enviados por el ESP32-C3
- El log del receiver muestra la MAC del sender y los datos correctos (sensor_id, temperatura, adc_value)
- Los datos recibidos coinciden con los datos enviados
- La recepcion ocurre cada ~2 segundos (coincidiendo con la frecuencia de envio)
- Dependencias: Requiere T0.5.1, T0.2.1
- Pistas: La macro
MACSTRformatea una MAC address como "XX:XX:XX:XX:XX:XX" yMAC2STR()descompone un array de 6 bytes en los argumentos del formato. El callback de recepcion se ejecuta en el contexto de la tarea WiFi, asi que debe ser rapido (no bloquear). En ESP-IDF v5.x, el callback de recepcion usaesp_now_recv_info_tque incluye la MAC de origen y destino ademas de RSSI. - Errores comunes:
- Definir
sensor_data_tde forma diferente en sender y receiver (distinto orden de campos, padding diferente). Solucion: usar__attribute__((packed))en la struct o mejor aun, compartir la definicion en un header comun. - El receiver no recibe nada: verificar que ambos dispositivos estan en el mismo canal WiFi. Por defecto, canal 1.
- Tiempo estimado: 1-2 horas
Tarea T0.5.3: Añadir callbacks de estado al sender¶
- Dificultad: Basico
- Descripcion: Mejorar el sender para verificar si cada envio fue exitoso o fallo, usando el callback de estado de ESP-NOW. Pasos:
- En el sender (
firmware/node/main/main.c), implementar el callback de envio con manejo de estado: - Llevar un contador de envios exitosos y fallidos:
- Imprimir estadisticas cada 10 envios:
- Probar apagando el receiver y verificar que los envios ahora reportan FAIL (en broadcast siempre reporta SUCCESS, asi que para esta prueba necesitaras usar la MAC unicast del receiver en lugar de broadcast).
- Archivos a crear/modificar:
firmware/node/main/main.c(modificar)- Criterio de aceptacion:
- El callback reporta correctamente SUCCESS o FAIL para cada envio
- El contador de estadisticas se incrementa correctamente
- Al usar unicast (MAC especifica del receiver) y apagar el receiver, el sender reporta envios fallidos
- Con broadcast, los envios siempre se reportan como SUCCESS (esto es comportamiento esperado de broadcast)
- Dependencias: Requiere T0.5.1, T0.5.2
- Pistas:
esp_now_send_status_ttiene dos valores:ESP_NOW_SEND_SUCCESSyESP_NOW_SEND_FAIL. En modo broadcast, el envio siempre se reporta como exitoso porque no hay confirmacion (ACK). En modo unicast (MAC especifica), ESP-NOW espera ACK del receptor. Para obtener la MAC real del receiver, imprimirla conesp_read_mac()en el codigo del receiver. Ten cuidado con acceder a variables compartidas entre callbacks y el bucle principal (concurrencia). - Errores comunes:
- Asumir que
SEND_SUCCESSen broadcast significa que el receptor recibio el dato. En broadcast, no hay confirmacion. Solo unicast tiene ACK real. - Acceder a contadores compartidos desde el callback (contexto WiFi) y desde el bucle principal sin proteccion. Para un contador simple,
_Atomicovolatilepuede ser suficiente, pero para datos mas complejos usar un mutex o una cola FreeRTOS. - Tiempo estimado: 1-2 horas
Tarea T0.5.4: Prueba de alcance y medicion de RSSI¶
- Dificultad: Basico
- Descripcion: Realizar pruebas de alcance de ESP-NOW moviendo los dispositivos a diferentes distancias y midiendo la intensidad de señal (RSSI). Pasos:
- Modificar el callback de recepcion en el receiver para imprimir el RSSI:
- Colocar ambos dispositivos juntos (1 metro) y anotar el RSSI.
- Mover el sender a 5 metros y anotar.
- Mover a 10 metros y anotar.
- Mover a 20 metros (o maximo alcance posible) y anotar.
- Probar con obstaculos (pared, puerta) entre los dispositivos.
- Registrar los resultados en una tabla: | Distancia | Obstaculos | RSSI (dBm) | Paquetes perdidos | |---|---|---|---| | 1m | Ninguno | -25 | 0% | | 5m | Ninguno | -45 | 0% | | ... | ... | ... | ... |
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar callback de recepcion)docs/benchmark-alcance.md(crear con tabla de resultados)- Criterio de aceptacion:
- El RSSI se imprime correctamente para cada paquete recibido
- La tabla de resultados tiene al menos 4 distancias diferentes
- Se observa que el RSSI disminuye (se hace mas negativo) con la distancia
- Se documenta el maximo alcance con recepcion fiable (tasa de perdida < 5%)
- Dependencias: Requiere T0.5.2
- Pistas: RSSI (Received Signal Strength Indicator) se mide en dBm. Valores tipicos: -20 a -30 dBm (muy cerca), -50 a -60 dBm (mismo cuarto), -70 a -80 dBm (habitaciones adyacentes), -90 dBm (limite de recepcion). El campo
rx_ctrldelesp_now_recv_info_tcontiene la estructurawifi_pkt_rx_ctrl_tcon el RSSI del paquete recibido. ESP-NOW puede alcanzar hasta ~200 metros en linea de vista sin obstaculos, pero en interior el alcance se reduce significativamente. - Errores comunes:
- Confundir señal WiFi con señal ESP-NOW. Ambos comparten la misma radio 2.4GHz, asi que el RSSI es comparable, pero ESP-NOW no depende de un AP.
- No esperar suficientes paquetes para tener una medicion fiable. Anotar el promedio de al menos 20 paquetes por distancia.
- Tiempo estimado: 1-2 horas
Checkpoint 0.5: Ya tienes comunicacion inalambrica funcionando entre el nodo C3 (sender) y el gateway S3 (receiver). Debes poder ver los datos recibidos en el monitor del S3, con estadisticas de envio en el C3. Ahora es un buen momento para refactorizar: mover
sensor_data_ta un header compartido enfirmware/common/protocol/.
Sub-tarea 0.6: WiFi AP+STA simultaneo¶
Objetivo: Configurar el ESP32-S3 (gateway) para funcionar simultaneamente como Access Point y como estacion WiFi, que es el modo que usara en produccion.
Tarea T0.6.1: Configurar ESP32-S3 en modo APSTA¶
- Dificultad: Intermedio
- Descripcion: Configurar el ESP32-S3 para que funcione simultaneamente como Access Point (AP) y como estacion (STA). El modo AP permitira que dispositivos se conecten directamente al gateway (por ejemplo, un movil para configuracion), mientras que el modo STA permite al gateway conectarse a un router para tener acceso a internet. Pasos:
- Crear un nuevo archivo o modificar
firmware/gateway/main/main.c. - Inicializar NVS y la interfaz de red:
- Inicializar WiFi y configurar modo APSTA:
- Configurar el AP:
- Configurar el STA (conectarse a tu router):
- Registrar event handlers para IP_EVENT y WIFI_EVENT para monitorizar el estado de ambas interfaces.
- Arrancar WiFi:
esp_wifi_start(). - Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)- Criterio de aceptacion:
- El ESP32-S3 crea una red WiFi llamada "IIoT-Gateway" visible desde un movil
- El ESP32-S3 se conecta simultaneamente al router (obtiene IP por DHCP)
- El log muestra ambos eventos: "AP started" y "STA got IP: x.x.x.x"
- No hay errores de inicializacion en el log
- Dependencias: Requiere T0.1.4
- Pistas:
WIFI_MODE_APSTAactiva ambas interfaces simultaneamente. Cada interfaz necesita su propioesp_netif:esp_netif_create_default_wifi_ap()yesp_netif_create_default_wifi_sta(). Los event handlers se registran conesp_event_handler_instance_register(). Eventos importantes:WIFI_EVENT_AP_START,WIFI_EVENT_STA_CONNECTED,IP_EVENT_STA_GOT_IP,WIFI_EVENT_AP_STACONNECTED(un cliente se conecta al AP). - Errores comunes:
- No registrar event handlers para ambas interfaces. Sin el handler de STA, no se inicia el proceso de obtencion de IP (DHCP). Registrar handlers para
WIFI_EVENTeIP_EVENT. - Poner una contraseña de AP menor a 8 caracteres con WPA2. WPA2 requiere minimo 8 caracteres. Solucion: usar contraseña de 8+ caracteres o
WIFI_AUTH_OPENpara pruebas (no recomendado en produccion). - Tiempo estimado: 2-3 horas
Tarea T0.6.2: Verificar ambas interfaces de red¶
- Dificultad: Basico
- Descripcion: Verificar que ambas interfaces (AP y STA) funcionan correctamente de forma simultanea. Pasos:
- Flashear el firmware con la configuracion APSTA.
- Verificar que el log muestra que el AP ha arrancado y que STA ha obtenido IP del router.
- Desde un movil:
- Buscar redes WiFi y conectarse a "IIoT-Gateway" con la contraseña configurada.
- Verificar que el movil obtiene IP (tipicamente 192.168.4.x).
- Verificar en el log del ESP32 que muestra el evento
WIFI_EVENT_AP_STACONNECTEDcon la MAC del movil.
- Verificar la STA:
- El ESP32 debe haber obtenido IP del router (evento
IP_EVENT_STA_GOT_IP). - Desde un ordenador en la misma red que el router, intentar hacer ping a la IP del ESP32.
- El ESP32 debe haber obtenido IP del router (evento
- (Opcional) Imprimir las IP de ambas interfaces con
esp_netif_get_ip_info(). - Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar si es necesario para imprimir IPs)- Criterio de aceptacion:
- Un movil puede conectarse a la red "IIoT-Gateway" y obtiene IP del DHCP del ESP32
- El ESP32 muestra en el log cuando un cliente se conecta al AP
- La interfaz STA obtiene IP del router
pingdesde el movil conectado al AP llega al ESP32 (IP por defecto 192.168.4.1)- Se pueden imprimir las IPs de ambas interfaces: AP (192.168.4.1) y STA (IP asignada por router)
- Dependencias: Requiere T0.6.1
- Pistas: La interfaz AP del ESP32 asigna IPs por DHCP a los clientes (por defecto subnet 192.168.4.x con gateway 192.168.4.1). La interfaz STA obtiene IP del router externo. Para obtener la IP de una interfaz:
esp_netif_get_ip_info(esp_netif_sta, &ip_info)dondeip_info.ipcontiene la direccion.esp_netif_create_default_wifi_ap()yesp_netif_create_default_wifi_sta()devuelven los handlesesp_netif_t*necesarios. - Errores comunes:
- El movil se desconecta porque detecta que no hay internet en la red del AP. Solucion: en Android, desactivar "Smart Network Switch" o "Cambiar a datos moviles automaticamente". En iOS, ignorar el aviso de "Sin conexion a internet".
- La STA no se conecta al router si el canal del AP fija el canal de toda la radio. En APSTA, ambas interfaces comparten la misma radio y por tanto el mismo canal. El canal lo determina el router al que se conecta STA.
- Tiempo estimado: 30-60 minutos
Tarea T0.6.3: Probar coexistencia de WiFi APSTA con ESP-NOW¶
- Dificultad: Avanzado
- Descripcion: Verificar que ESP-NOW sigue funcionando correctamente mientras el gateway esta en modo APSTA. Esta es una validacion critica porque en produccion el gateway debe recibir datos de los nodos via ESP-NOW al mismo tiempo que mantiene WiFi activo. Pasos:
- En el gateway (ESP32-S3), combinar el codigo de APSTA (T0.6.1) con el receptor ESP-NOW (T0.5.2).
- IMPORTANTE: ESP-NOW y WiFi comparten la misma radio y deben operar en el mismo canal. Cuando STA se conecta a un router, el canal lo fija el router. El sender ESP-NOW debe usar el mismo canal.
- En el gateway, despues de conectarse al router, obtener el canal actual:
- En el nodo C3 (sender), fijar el mismo canal: (En pruebas, hardcodear el canal. En produccion, se comunicara dinamicamente.)
- Verificar simultaneamente:
- ESP-NOW recibe datos del nodo C3.
- Un movil esta conectado al AP "IIoT-Gateway".
- STA esta conectado al router.
- Documentar si hay perdida de paquetes ESP-NOW al tener APSTA activo vs solo ESP-NOW.
- Archivos a crear/modificar:
firmware/gateway/main/main.c(modificar)firmware/node/main/main.c(modificar para fijar canal)- Criterio de aceptacion:
- ESP-NOW recibe datos del nodo C3 mientras APSTA esta activo
- No hay aumento significativo de perdida de paquetes ESP-NOW con APSTA activo (< 5% adicional)
- Las tres funciones coexisten: recepcion ESP-NOW, AP activo, STA conectado al router
- El log muestra recepciones ESP-NOW, clientes AP conectados, e IP de STA simultaneamente
- Dependencias: Requiere T0.5.2, T0.6.2
- Pistas: ESP-NOW transmite en el canal WiFi actual del dispositivo. Si sender y receiver estan en canales diferentes, no se comunicaran.
esp_wifi_set_channel()fija el canal en el sender. En modo STA conectado a un AP, el canal lo determina el router y no se puede cambiar.esp_wifi_get_channel()permite consultar el canal actual. La coexistencia funciona porque ESP-NOW y WiFi comparten la capa MAC y se turnan para transmitir. - Errores comunes:
- Sender y receiver en canales diferentes. Si el router del gateway usa canal 6, el sender C3 tambien debe estar en canal 6. Si no coinciden, ESP-NOW no recibira nada.
- Intentar cambiar el canal del gateway cuando STA esta conectado. El canal lo fija el router al que STA esta conectado. Si necesitas un canal especifico, configurar el router para usar ese canal.
- Tiempo estimado: 2-3 horas
Checkpoint 0.6: El gateway ESP32-S3 ahora funciona en modo APSTA (crea red WiFi propia y se conecta al router simultaneamente) y recibe datos via ESP-NOW del nodo C3. Esta es la configuracion de red que usara el sistema en produccion. Si la coexistencia causa problemas, documenta las limitaciones encontradas.
Sub-tarea 0.7: Benchmarks de consumo¶
Objetivo: Medir el consumo energetico real del ESP32-C3 (nodo) en diferentes modos de operacion para estimar la autonomia con bateria.
Tarea T0.7.1: Medir corriente del ESP32-C3 en diferentes modos¶
- Dificultad: Basico
- Descripcion: Medir el consumo de corriente del ESP32-C3 en los principales modos de operacion usando un multimetro. Pasos:
- Configurar el multimetro en modo amperimetro (rango mA para modos activos, uA para sleep).
- Conectar el multimetro EN SERIE con la alimentacion del ESP32-C3:
- Desconectar el USB.
- Alimentar la placa con una fuente externa de 3.3V.
- Insertar el multimetro entre la fuente y el pin 3.3V de la placa (o entre VIN y fuente de 5V si la placa tiene regulador).
- Medir consumo en cada modo:
- Modo activo (WiFi TX): ejecutar el sender ESP-NOW. Anotar corriente.
- Modem sleep: usar
esp_wifi_set_ps(WIFI_PS_MIN_MODEM). Medir cuando no transmite. - Light sleep: configurar con
esp_light_sleep_start(). Medir durante el sleep. - Deep sleep: configurar con
esp_deep_sleep_start(). Medir. Este es el modo de menor consumo.
- Para deep sleep, crear un programa simple:
- Anotar todos los valores medidos.
- Archivos a crear/modificar:
firmware/node/main/main.c(modificar para diferentes modos de sleep)- Criterio de aceptacion:
- Se han medido al menos 4 modos: activo con WiFi, modem sleep, light sleep, deep sleep
- Los valores son coherentes con la documentacion de Espressif (ej: deep sleep del C3 ~5uA, activo ~130mA)
- Los valores estan anotados con precision (al menos en mA para activo, uA para sleep)
- El multimetro esta correctamente configurado (rango adecuado para cada medicion)
- Dependencias: Requiere T0.5.1 (para tener firmware base)
- Pistas: Valores de referencia del ESP32-C3 (aproximados, varian segun condiciones): Activo WiFi TX ~130-150mA, Modem sleep ~15-20mA, Light sleep ~130uA, Deep sleep ~5uA.
esp_deep_sleep(us)acepta microsegundos. En deep sleep, la RAM se pierde (excepto RTC memory). Al despertar, se reiniciaapp_main(). Para guardar datos entre deep sleeps, usarRTC_DATA_ATTR. - Errores comunes:
- Medir la corriente con el multimetro en paralelo (como voltimetro) en lugar de en serie. Esto puede dañar el multimetro o fundir el fusible. Siempre medir corriente EN SERIE.
- No cambiar el rango del multimetro al pasar de mA a uA. Las mediciones de deep sleep estan en el rango de microsAmperios y no se ven en el rango de mA.
- Tiempo estimado: 2-3 horas
Tarea T0.7.2: Calcular autonomia teorica con bateria¶
- Dificultad: Basico
- Descripcion: Usando los valores medidos en T0.7.1, calcular la autonomia teorica del nodo con una bateria de 3400mAh (tipica Li-Ion 18650). Pasos:
- Calcular autonomia en modo continuo para cada modo: Ejemplo: 3400mAh / 130mA = 26.2 horas (solo WiFi activo)
- Calcular autonomia con duty cycle (caso real):
- Escenario: despertar cada 60 segundos, leer sensor (100ms), enviar ESP-NOW (200ms), dormir el resto.
- Tiempo activo: 300ms, tiempo dormido: 59700ms.
- Repetir el calculo para intervalos de 30s, 60s, 120s y 300s.
- Crear una tabla comparativa con los resultados.
- Considerar un factor de eficiencia del 80% (la bateria no entrega el 100% de su capacidad nominal).
- Archivos a crear/modificar:
docs/benchmark-consumo.md(crear, parcial; se completara en T0.7.3)- Criterio de aceptacion:
- Se han calculado las autonomias para al menos 4 escenarios diferentes
- Los calculos incluyen el duty cycle realista (no solo modo continuo)
- Se aplica el factor de eficiencia del 80%
- Los resultados estan en una tabla clara con columnas: Escenario, Intervalo, Consumo medio, Autonomia
- Las unidades son consistentes (mA, mAh, horas/dias)
- Dependencias: Requiere T0.7.1
- Pistas: La formula de duty cycle es:
I_medio = (D * I_activo) + ((1-D) * I_sleep)donde D es el duty cycle (fraccion del tiempo activo). Una bateria 18650 de 3400mAh proporciona ~3.7V nominal. Si usas regulador LDO, la eficiencia es ~90%. Si usas buck converter, ~85-95%. Para ser conservador, usar 80% de la capacidad nominal. No olvidar que la corriente de arranque del WiFi puede ser mayor (~400mA pico) aunque sea breve. - Errores comunes:
- Olvidar convertir unidades (mezclar segundos con horas, mA con uA). Mantener todo en las mismas unidades durante el calculo.
- No considerar el consumo durante el arranque del WiFi (startup). Aunque es breve (~100ms), la corriente pico es alta (~300-400mA). Para calculos conservadores, incluir este pico.
- Tiempo estimado: 1-2 horas
Tarea T0.7.3: Escribir informe de benchmarks de consumo¶
- Dificultad: Basico
- Descripcion: Documentar todos los resultados de las mediciones y calculos de consumo en un informe estructurado. Pasos:
- Crear el archivo
docs/benchmark-consumo.md. - Incluir las siguientes secciones:
- Metodologia: como se midio (equipo, configuracion, condiciones).
- Resultados de medicion: tabla con los valores medidos en T0.7.1.
- Calculos de autonomia: tabla con los calculos de T0.7.2.
- Graficos (opcional): se pueden crear con herramientas externas o en ASCII.
- Conclusiones: modo recomendado para produccion, intervalo optimo, autonomia esperada.
- Limitaciones: factores no considerados (temperatura, envejecimiento de bateria, variabilidad entre chips).
- Incluir la configuracion exacta de firmware para cada medicion (target, config de WiFi, etc.).
- Archivos a crear/modificar:
docs/benchmark-consumo.md(crear o completar)- Criterio de aceptacion:
- El documento contiene todas las secciones listadas (metodologia, resultados, calculos, conclusiones)
- Las tablas son claras y los valores tienen unidades
- Las conclusiones responden a la pregunta: "¿Cuanto durara un nodo con bateria en produccion?"
- Se mencionan las limitaciones del benchmark
- El informe es reproducible: otro desarrollador podria repetir las mediciones con la informacion proporcionada
- Dependencias: Requiere T0.7.1, T0.7.2
- Pistas: Formato de tabla Markdown: Incluir la version de ESP-IDF, la version de la placa y la fecha de las mediciones. Los resultados pueden variar un 10-20% entre chips del mismo modelo.
- Errores comunes:
- No especificar las condiciones de medicion (temperatura ambiente, firmware exacto, etc.). Un benchmark sin contexto no es reproducible.
- Presentar solo el mejor caso. Incluir tambien el peor caso y el caso tipico para dar una vision realista.
- Tiempo estimado: 1-2 horas
Checkpoint 0.7: Ahora tienes datos reales de consumo del ESP32-C3 y una estimacion de cuanto durara cada nodo con bateria. Estos datos seran fundamentales para decidir el intervalo de lectura y el modo de sleep en las fases siguientes. Guarda bien el informe, sera una referencia durante todo el proyecto.
Sub-tarea 0.8: Estructura del proyecto¶
Objetivo: Establecer la estructura de build del proyecto con CMake y crear el componente compartido entre gateway y node.
Tarea T0.8.1: Crear CMakeLists.txt para gateway y node¶
- Dificultad: Basico
- Descripcion: Configurar correctamente los archivos CMakeLists.txt para que tanto el gateway como el node sean proyectos ESP-IDF independientes que se pueden compilar por separado. Pasos:
- Crear
firmware/gateway/CMakeLists.txt: - Crear
firmware/gateway/main/CMakeLists.txt: - Crear
firmware/node/CMakeLists.txt: - Crear
firmware/node/main/CMakeLists.txt: - Verificar que ambos proyectos compilan independientemente:
- Archivos a crear/modificar:
firmware/gateway/CMakeLists.txt(crear o verificar)firmware/gateway/main/CMakeLists.txt(crear o verificar)firmware/node/CMakeLists.txt(crear o verificar)firmware/node/main/CMakeLists.txt(crear o verificar)- Criterio de aceptacion:
idf.py buildenfirmware/gateway/compila exitosamente para esp32s3idf.py buildenfirmware/node/compila exitosamente para esp32c3- Ambos proyectos referencian el componente compartido en
../common - La linea
REQUIRES protocolno causa error (el componente existe tras T0.8.2) - Dependencias: Requiere T0.1.6
- Pistas:
EXTRA_COMPONENT_DIRSdice a ESP-IDF donde buscar componentes adicionales (fuera del directoriocomponents/por defecto). La ruta es relativa alCMakeLists.txtdel proyecto.REQUIRESenidf_component_registerdeclara una dependencia de componente (necesario para que el header se incluya correctamente).cmake_minimum_required(VERSION 3.16)es el minimo requerido por ESP-IDF v5.x. - Errores comunes:
- Usar rutas absolutas en
EXTRA_COMPONENT_DIRS. Siempre usar rutas relativas para que el proyecto sea portable entre maquinas. - Olvidar
REQUIRES protocolen el CMakeLists.txt del main. Sin esta directiva,#include "protocol.h"fallara porque CMake no sabe que debe añadir el include path del componente. - Tiempo estimado: 1-2 horas
Tarea T0.8.2: Crear componente protocol compartido¶
- Dificultad: Intermedio
- Descripcion: Crear un componente ESP-IDF reutilizable que contenga las definiciones de estructuras y constantes compartidas entre gateway y node. Esto evita duplicar codigo y asegura que ambos lados usen las mismas definiciones. Pasos:
- Crear la estructura del componente:
- Crear
firmware/common/protocol/CMakeLists.txt: - Crear
firmware/common/protocol/include/protocol.h:#pragma once #include <stdint.h> #define PROTOCOL_VERSION 1 #define MAX_SENSOR_DATA_SIZE 250 // Limite de ESP-NOW // Tipos de mensaje typedef enum { MSG_TYPE_SENSOR_DATA = 0x01, MSG_TYPE_HEARTBEAT = 0x02, MSG_TYPE_CONFIG = 0x03, MSG_TYPE_ACK = 0x04, } msg_type_t; // Estructura principal de datos de sensor typedef struct __attribute__((packed)) { uint8_t version; // Version del protocolo uint8_t msg_type; // msg_type_t uint16_t node_id; // Identificador del nodo uint32_t timestamp_ms; // Milisegundos desde arranque float temperatura; // Grados Celsius float ph; // pH (placeholder) float oxigeno; // mg/L (placeholder) uint16_t turbidez_raw; // Valor raw ADC int8_t rssi; // RSSI del ultimo envio uint8_t bateria_pct; // Porcentaje bateria (0-100) } sensor_data_t; // Estructura de heartbeat typedef struct __attribute__((packed)) { uint8_t version; uint8_t msg_type; uint16_t node_id; uint32_t uptime_s; // Segundos desde arranque uint8_t bateria_pct; int8_t rssi; } heartbeat_t; - Crear
firmware/common/protocol/protocol.ccon funciones auxiliares placeholder: - En los
main.cde gateway y node, reemplazar las definiciones locales desensor_data_tpor#include "protocol.h". - Compilar ambos proyectos y verificar que no hay errores.
- Archivos a crear/modificar:
firmware/common/protocol/CMakeLists.txt(crear)firmware/common/protocol/include/protocol.h(crear)firmware/common/protocol/protocol.c(crear)firmware/gateway/main/main.c(modificar para usar#include "protocol.h")firmware/node/main/main.c(modificar para usar#include "protocol.h")- Criterio de aceptacion:
- Ambos proyectos (gateway y node) compilan usando
#include "protocol.h"del componente compartido - No hay definiciones duplicadas de
sensor_data_t(solo existe enprotocol.h) sizeof(sensor_data_t)devuelve el mismo valor en S3 y C3 (gracias a__attribute__((packed)))protocol_validate_message()retornatruepara un mensaje valido yfalsepara datos invalidos- Dependencias: Requiere T0.8.1, T0.5.2
- Pistas:
__attribute__((packed))elimina el padding entre campos de la struct, lo que es crucial cuando los datos se envian por red (sin packed, el compilador puede insertar bytes de padding diferentes en arquitecturas diferentes).INCLUDE_DIRS "include"en el CMakeLists.txt hace que#include "protocol.h"funcione directamente (sin necesidad de#include "include/protocol.h").#pragma oncees una directiva de guarda de inclusion (alternativa moderna a#ifndef/#define/#endif). - Errores comunes:
- Olvidar
__attribute__((packed))en las structs compartidas. Sin packed, el ESP32-S3 (Xtensa, 32-bit) y el ESP32-C3 (RISC-V, 32-bit) podrian añadir padding diferente, corrompiendo los datos recibidos. - No incluir el componente en
REQUIRESdel CMakeLists.txt del main. Si no se declara la dependencia, el include path no se configura y#include "protocol.h"falla en compilacion. - Tiempo estimado: 1-2 horas
Checkpoint 0.8: El proyecto tiene ahora una estructura limpia con dos firmwares independientes (gateway para ESP32-S3 y node para ESP32-C3) que comparten un componente comun con las definiciones del protocolo. Esta estructura sera la base para todo el desarrollo futuro. Verifica que ambos proyectos compilan limpiamente.
Preguntas de autoevaluacion¶
Antes de pasar a la Fase 1, asegurate de poder responder estas preguntas:
-
¿Cual es la diferencia entre ESP32-S3 y ESP32-C3 en terminos de arquitectura de CPU? (Pista: uno es Xtensa dual-core y otro es RISC-V single-core)
-
¿Por que es necesario inicializar WiFi antes de usar ESP-NOW, aunque no nos conectemos a ningun Access Point? (Pista: ESP-NOW usa la capa MAC de WiFi)
-
¿Que ocurre si el sender ESP-NOW esta en canal 1 y el receiver esta en canal 6? (Pista: no se comunicaran; deben estar en el mismo canal)
-
¿Por que usamos
__attribute__((packed))en las estructuras del protocolo? (Pista: evitar que el compilador añada padding diferente en arquitecturas diferentes) -
¿Cual es la diferencia entre
ESP_LOGDyESP_LOGIy por que los mensajes DEBUG pueden no aparecer? (Pista: el nivel de compilacion por defecto es INFO, que excluye DEBUG y VERBOSE) -
¿Por que el ADC2 no se debe usar cuando WiFi esta activo en el ESP32? (Pista: ADC2 comparte hardware con el modulo WiFi)
-
¿Que modo de sleep ofrece el menor consumo en el ESP32-C3 y cual es su principal limitacion? (Pista: deep sleep consume ~5uA pero pierde toda la RAM)
-
¿Cual es el tamaño maximo de un paquete ESP-NOW y como afecta esto al diseño del protocolo? (Pista: 250 bytes maximo; las estructuras de datos deben caber en un solo paquete)
Lectura recomendada¶
Guias oficiales de Espressif¶
- ESP-IDF Getting Started Guide - Guia de inicio con ESP-IDF
- ESP-IDF Build System - Sistema de build con CMake
- ESP-NOW Programming Guide - Documentacion oficial de ESP-NOW
Perifericos¶
- GPIO & RTC GPIO - Control de pines GPIO
- ADC Oneshot Mode - Lectura ADC (API nueva)
- I2C Master Driver - Driver I2C (API nueva v5.x)
Bajo consumo¶
- Deep Sleep Wake Stubs - Deep sleep y wake stubs
- Power Management - Gestion de energia
Datasheets¶
- ESP32-S3 Datasheet - Hoja de datos del ESP32-S3
- ESP32-C3 Datasheet - Hoja de datos del ESP32-C3
Component Registry¶
- ESP-IDF Component Registry - Registro de componentes (drivers de sensores, librerias, etc.)
Errores frecuentes de esta fase¶
A continuacion, un resumen consolidado de los errores mas comunes que un desarrollador junior puede encontrar durante la Fase 0:
Entorno y toolchain¶
- Olvidar
source export.sh: Cada terminal nueva necesita cargar las variables de ESP-IDF. Solucion: añadir al.bashrco usar un alias. - No usar
--recursiveal clonar ESP-IDF: Los submodulos no se descargan. Solucion:git submodule update --init --recursive. - No cambiar el target antes de compilar: Compilar firmware de S3 para C3 (o viceversa) produce errores confusos. Siempre ejecutar
idf.py set-targetprimero.
Hardware y conexiones¶
- Cable USB de solo carga: Si
dmesgno detecta nada al conectar la placa, probar con otro cable que tenga lineas de datos. - Permisos de puerto serie: Añadir el usuario al grupo
dialouty reiniciar sesion completa (no solo la terminal). - Olvidar resistencias pull-up: I2C y 1-Wire requieren pull-ups. Sin ellos, la comunicacion falla silenciosamente.
- Conectar sensores a 5V: Los pines del ESP32 son de 3.3V. Conectar 5V puede dañar el chip permanentemente.
Programacion ESP-IDF¶
- Usar
delay()en lugar devTaskDelay(): ESP-IDF usa FreeRTOS;delay()no existe. - Usar
printfen lugar deESP_LOGx: Las macros de log proporcionan timestamp, TAG, nivel y son filtrables. - No inicializar NVS antes de WiFi: WiFi requiere NVS para calibracion del PHY.
- No inicializar WiFi antes de ESP-NOW: ESP-NOW usa la capa MAC de WiFi.
- Usar API I2C legacy: En ESP-IDF v5.x, usar la nueva API con
i2c_master_bus_handle_t.
ADC¶
- No configurar atenuacion del ADC: Sin
ADC_ATTEN_DB_12, el rango es solo 0-1V y voltajes mayores saturan. - Usar ADC2 con WiFi activo: ADC2 comparte hardware con WiFi. Siempre usar ADC1.
ESP-NOW y WiFi¶
- Sender y receiver en canales WiFi diferentes: ESP-NOW solo funciona si ambos dispositivos estan en el mismo canal.
- Asumir que broadcast ESP-NOW confirma recepcion: En broadcast,
SEND_SUCCESSsolo significa que el paquete fue transmitido, no que fue recibido. - Structs sin
packeden el protocolo: Sin__attribute__((packed)), el padding puede diferir entre arquitecturas, corrompiendo los datos.
Mediciones y benchmarks¶
- Medir corriente con multimetro en paralelo: La corriente se mide EN SERIE. Medir en paralelo puede dañar el multimetro.
- No cambiar rango del multimetro: Deep sleep es ~uA, activo es ~mA. Usar el rango adecuado para cada medicion.
Al completar la Fase 0, debes tener: - Entorno de desarrollo funcional para ESP32-S3 y ESP32-C3 - Familiaridad con GPIO, logging, I2C, ADC y ESP-NOW - Comunicacion basica nodo-gateway funcionando - WiFi APSTA configurado en el gateway - Datos de consumo medidos y documentados - Estructura de proyecto con componente compartido
Siguiente fase: Fase 1 - Gateway Nucleo