Este circuito pone en servicio un detector de temperatura y humedad con un DHT11, recoge la señal un tarjeta ESP32 y envia esa informacion a otra ESP32 para guardar la informacion en un archivo monitoreado por un LLM.
El circuito esta alimentado por dos paneles solares de 6 watios, una tarjeta MHCD42 para administrar la carga de una bateria de litio Li-ion de 1300 mAh.
El circuito entra en bajo consumo consumiendo 35 nanoamperios durante 1 hora a traves de una tarjeta TPL5110, la alimentacion de la TPL5110 se hace a traves de dos supercondensadores de 1 faradio. La TPL5110 pone en marcha un rele optoacoplador que a su vez activa el paso de corriente a traves de un transistor Mosfet -P, en concreto el Mosfet 27P06. Este Mosfet sera el encargado de alimentar la ESP32 y activarla.
Han sido necesarias dos resistencias a la salida de señal de la ESP32 hacia el TPL5110 en modo divisor de tension, las resistencias son de 10K y 4.7K, tambien he añadido un condensador para eliminar ruido de 100 nanofaradios. Para evitar que la ESP32 reciba tension de los supercondensadores he añadido un diodo zener, de esa manera la ESP32 recibe tension a traves de la placa MHCD42.
Conexionado electrico:
Los dos paneles solares de 6 vatios se conectan a la entrada de la tarjeta MHCD42 encargada de la gestion de carga de bateria, por otra parte la bateria conectada a la tarjeta MHCD42 es una bateria de litio Li-ion de 1300 mAh. El positivo de la salida de la MHCD42 esta conectado a un borne de los contactos abiertos de un rele optoacoplador y tambien esta conectado al anodo de un diodo Schottky. El catodo del diodo Schottky esta conectado al positivo de dos supercondensadores H73S, tambien esta conectado al positivo de la entrada del TPL5110. El negativo de entrada de la TPL5110 esta conectado en paralelo al pin Gate de un Mosfet canal P, el mosfet FQP27P06, por otro lado el negativo de la TPL5110 tambien esta conectado al negativo de los dos condensadores H73S. Tambien tenemos conectado el negativo al negativo de una tarjeta ESP32 Nodemcu, tambien al negativo de un condensador electrolitico de 100 nanofaradios y a un resistencia de 10 Kilo ohmios. Por otra parte el transirtor mosfet FQP27P06 tiene el pin Source conectado al otro borne del contacto abierto del rele optoacoplador anteriormente mencionado y el pin Drain esta conectado al positivo de alimentacion de la tarjeta ESP32 Nodemcu.
La salida de tension de la tarjeta TPL5110 estoy alimentando el accionamiento del rele optoacoplador estando conectado el negativo de la TPL5110 al negativo del rele y el positivo de la TPL5110 al positivo del rele y al pin de señal de activacion del rele al mismo tiempo.
El pin numero 25 de la ESP32 Nodemcu esta conectado al positivo del condensador de electrolitio de 100 nanofaradios y a una resistencia de 4.7 Kilo ohmios en paralelo. El otro terminal de la resistencia de 4.7 Kilo ohmios hay conectado en paralelo otra resistencia de 10 Kilo ohmios, nombrada anteriormente, y tambien esta conectado al pin Done de la TPL5110 para poner la TPL5110 en estado reposo cuando el pin se active.
Por otra parte hay conectado un detector de temperatura y humedad DHT11 a la ESP32 Nodemcu, desde el pin de 3.3 voltios de la ESP32 alimento el positivo del DHT11, y desde el GND de la ESP32 alimento el negativo del DHT11, el pin de señal del DHT11 esta conectado al pin numero 33 de la ESP32 Nodemcu.
Enlaces a componentes utilizados:
Panel solar de 2x6W, 5V, IP67.
Tarjeta para la gestion de baterias de litio, MHCD42.
Tarjeta para entrar en modo ultrabajoconsumo TPL5110.
Tarjeta ESP32 nodemcu de espressif.
Detector DHT11, sensor de temperatura y humedad.
Supercondensador de 1 faradio.
Resistencias de 10K ohmios y 4.7K ohmios.
Condensador electrolitico de 0,1 microfaradios.
Tarjeta electrónica (Olimex ESP32 EVB) externa a este circuito que recibe los datos y almacena en un MicroSD.
Codigo funcionando en la tarjeta ESP32 que hace la lectura de temperatura y humedad:
#include <esp_now.h>
#include <WiFi.h>
#include "DHT.h"
// Configuración del sensor DHT
#define DHTPIN 33
#define DHTTYPE DHT11
#define TPL 25
DHT dht(DHTPIN, DHTTYPE);
// Dirección MAC de la ESP32 receptora
uint8_t receiverAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Declaración del tipo de mensaje
enum MessageType {
SENSOR_DATA
};
// Estructura para el mensaje con identificador
typedef struct {
MessageType type;
float temperature;
float humidity;
} SensorMessage;
SensorMessage dataToSend;
// Callback para notificar estado de envío
void onSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("Estado del envío: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Éxito" : "Fallido");
}
void setup() {
Serial.begin(9600);
pinMode(TPL, OUTPUT);
digitalWrite(TPL, LOW);
// Inicializar el sensor DHT
dht.begin();
Serial.println("Sensor DHT inicializado.");
// Inicializar Wi-Fi en modo estación
WiFi.mode(WIFI_STA);
// Inicializar ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error al inicializar ESP-NOW");
return;
}
esp_now_register_send_cb(onSent);
// Añadir el receptor
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, receiverAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Error al añadir el receptor.");
return;
}
Serial.println("ESP-NOW inicializado y receptor añadido.");
}
void loop() {
// Leer datos del sensor DHT
float temp = dht.readTemperature();
float hum = dht.readHumidity();
// Comprobar si la lectura es válida
if (isnan(temp) || isnan(hum)) {
Serial.println("Error al leer el sensor DHT");
delay(2000);
return;
}
// Preparar datos para enviar
dataToSend.type = SENSOR_DATA;
dataToSend.temperature = temp;
dataToSend.humidity = hum;
delay(1000);
// Enviar datos
esp_now_send(receiverAddress, (uint8_t *)&dataToSend, sizeof(dataToSend));
// Retardo antes de enviar nuevamente
delay(2000);
digitalWrite(TPL, HIGH);
}
Codigo de la tarjeta Olimex ESP32 EVB recibiendo la informacion de dos ESP32:
#include <esp_now.h>
#include <WiFi.h>
#include <SD_MMC.h>
// Declaración de tipos de mensajes
enum MessageType {
SENSOR_DATA, // Para temperatura y humedad
NUMBER_DATA // Para otros números
};
// Estructuras de datos específicas para cada tipo
typedef struct {
float temperature;
float humidity;
} SensorData;
typedef struct {
int number;
} NumberData;
// Estructura genérica para recibir datos
typedef struct {
MessageType type; // Identificador del tipo de mensaje
union {
SensorData sensorData;
NumberData numberData;
} payload; // Datos específicos según el tipo
} GenericMessage;
GenericMessage receivedMessage;
// Variable para el tiempo de inicio
unsigned long startTime;
void onReceive(const uint8_t *mac, const uint8_t *incomingData, int len) {
// Copiar datos en la estructura
memcpy(&receivedMessage, incomingData, len);
// Calcular tiempo transcurrido
unsigned long elapsedMillis = millis() - startTime;
unsigned long elapsedSeconds = elapsedMillis / 1000;
unsigned int hours = elapsedSeconds / 3600;
unsigned int minutes = (elapsedSeconds % 3600) / 60;
unsigned int seconds = elapsedSeconds % 60;
// Formatear tiempo transcurrido
char elapsedTimeStr[20];
snprintf(elapsedTimeStr, sizeof(elapsedTimeStr), "%02u:%02u:%02u", hours, minutes, seconds);
// Abrir archivo para guardar los datos
File dataFile = SD_MMC.open("/data.txt", FILE_APPEND);
if (!dataFile) {
Serial.println("Error al abrir el archivo en la tarjeta SD.");
return;
}
// Procesar y guardar los datos según el tipo de mensaje
switch (receivedMessage.type) {
case SENSOR_DATA:
Serial.println("Datos de sensor recibidos:");
Serial.print("Temperatura: ");
Serial.print(receivedMessage.payload.sensorData.temperature);
Serial.println(" °C");
Serial.print("Humedad: ");
Serial.print(receivedMessage.payload.sensorData.humidity);
Serial.println(" %");
// Guardar en la microSD
dataFile.printf("[%s] sensor exterior, Temperatura: %.2f °C, Humedad: %.2f %%\n",
elapsedTimeStr,
receivedMessage.payload.sensorData.temperature,
receivedMessage.payload.sensorData.humidity);
break;
case NUMBER_DATA:
// Siempre imprimir "Detectado presencia en la entrada"
Serial.println("Detectado presencia en la entrada");
dataFile.printf("[%s] Detectado presencia en la entrada\n", elapsedTimeStr);
break;
default:
Serial.println("Tipo de mensaje desconocido.");
dataFile.printf("[%s] Tipo de mensaje desconocido\n", elapsedTimeStr);
break;
}
// Cerrar el archivo
dataFile.close();
Serial.println("Datos guardados en la tarjeta SD.");
}
void setup() {
Serial.begin(9600);
// Inicializar Wi-Fi en modo estación
WiFi.mode(WIFI_STA);
Serial.println("Wi-Fi inicializado en modo estación");
// Inicializar ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error al inicializar ESP-NOW");
return;
}
// Registrar callback para recibir datos
esp_now_register_recv_cb(onReceive);
// Inicializar la tarjeta microSD
if (!SD_MMC.begin()) {
Serial.println("Error al inicializar la tarjeta SD.");
return;
}
Serial.println("Tarjeta SD inicializada correctamente.");
// Configurar tiempo inicial
startTime = millis();
const char* startDate = "2024-11-30 09:00:00"; // Fecha de inicio predefinida
// Abrir el archivo (sin importar si existe) y escribir el inicio del registro
File dataFile = SD_MMC.open("/data.txt", FILE_APPEND);
if (dataFile) {
dataFile.printf("Inicio del registro: %s\n", startDate);
dataFile.close();
Serial.println("Inicio del registro guardado en la tarjeta SD.");
} else {
Serial.println("Error al escribir el inicio del registro en la tarjeta SD.");
}
Serial.println("ESP-NOW inicializado y esperando datos...");
}
void loop() {
// No hay lógica adicional, los datos se manejan en el callback
}