Placa electrónica con modulo ESP32 integrado, también dispone de 2 reles, tarjeta microSD, sensor infrarrojo, puerto ethernet, etc.
Abajo se muestra la parte de atras de la tarjeta donde podemos ver la distribución de los pines GPIO y tensiones de trabajo.
OLIMEX ESP32-EVB: Una Placa de Desarrollo Versátil y Confiable
La OLIMEX ESP32-EVB es una placa de desarrollo Open Source Hardware diseñada para proyectos que requieren conectividad WiFi, Bluetooth y Ethernet. Con un diseño robusto y múltiples interfaces de hardware, es ideal para aplicaciones IoT, industriales y de automatización.
Características Principales:
- Módulo ESP32-WROOM-32E/UE: Proporciona conectividad WiFi y Bluetooth Low Energy (BLE).
- Conector Ethernet (100 Mbps): Basado en el transceptor LAN8710A para redes rápidas y confiables.
- 2 Relés de alta potencia: Soportan hasta 10A/250VAC o 15A/120VAC, perfectos para control de dispositivos.
- Ranura para tarjeta MicroSD: Compatible en modo 1-bit eMMC, ideal para almacenamiento externo.
- Interfaz CAN: Incluye transceptor SIT1050T con resistencia de terminación opcional.
- Comunicaciones IR: Transmisor y receptor de infrarrojos con un alcance de hasta 5 metros.
- Cargador LiPo integrado: Para operación independiente durante cortes de energía, con indicadores LED de estado.
- Botones de usuario y reset: Para pruebas y reinicios rápidos.
- Puerto Micro-USB: Permite alimentación y programación a través del programador CH340T, compatible con Arduino IDE y ESP-IDF.
- Conector UEXT: Expansión sencilla con módulos adicionales.
- Conector GPIO de 40 pines: Acceso a todos los pines del ESP32 para mayor flexibilidad en proyectos.
- Dimensiones compactas: 75×75 mm (~2.95×2.95 pulgadas), fácil de integrar en proyectos.
Opciones de Configuración:
- Variantes Comerciales e Industriales: Versiones disponibles para rangos de temperatura de 0 a 70°C o -40 a +85°C.
- Antena Integrada o Externa: Según el modelo (EA incluye antena externa).
Ventajas Adicionales:
- Hardware y software Open Source: Diseñado en KiCad bajo licencias OSHW, GPL3 y CC BY-SA 3.0.
- Compatibilidad con herramientas populares: Ejemplos de software disponibles en ESP-IDF y Arduino desde el repositorio oficial de Olimex.
Aplicaciones Comunes:
- Sistemas IoT.
- Automatización industrial.
- Proyectos de domótica.
- Monitoreo remoto y control de dispositivos.
Documentación y Recursos:
Toda la información técnica y los esquemáticos están disponibles en GitHub. Olimex también ofrece ejemplos prácticos para comenzar con tu proyecto.
Codigo NTPtime.cpp del video:
/*
NTP
This routine gets the unixtime from a NTP server and adjusts it to the time zone and the
Middle European summer time if requested
Author: Andreas Spiess V1.0 2016-5-28
Based on work from John Lassen: http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig
*/
#include <Arduino.h>
#include "NTPtimeESP.h"
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
#define SEC_TO_MS 1000
#define RECV_TIMEOUT_DEFAULT 1 // 1 second
#define SEND_INTRVL_DEFAULT 1 // 1 second
#define MAX_SEND_INTERVAL 60 // 60 seconds
#define MAC_RECV_TIMEOUT 60 // 60 seconds
const int NTP_PACKET_SIZE = 48;
byte _packetBuffer[ NTP_PACKET_SIZE];
static const uint8_t _monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
float _timeZone=0.0;
String _NTPserver="";
// NTPserver is the name of the NTPserver
bool NTPtime::setSendInterval(unsigned long _sendInterval_) {
bool retVal = false;
if(_sendInterval_ <= MAX_SEND_INTERVAL) {
_sendInterval = _sendInterval_ * SEC_TO_MS;
retVal = true;
}
return retVal;
}
bool NTPtime::setRecvTimeout(unsigned long _recvTimeout_) {
bool retVal = false;
if(_recvTimeout_ <= MAC_RECV_TIMEOUT) {
_recvTimeout = _recvTimeout_ * SEC_TO_MS;
retVal = true;
}
return retVal;
}
NTPtime::NTPtime(String NTPserver) {
_NTPserver = NTPserver;
_sendPhase = true;
_sentTime = 0;
_sendInterval = SEND_INTRVL_DEFAULT * SEC_TO_MS;
_recvTimeout = RECV_TIMEOUT_DEFAULT * SEC_TO_MS;
}
void NTPtime::printDateTime(strDateTime _dateTime) {
if (_dateTime.valid) {
Serial.print(_dateTime.year);
Serial.print( "-");
Serial.print(_dateTime.month);
Serial.print( "-");
Serial.print(_dateTime.day);
Serial.print( "-");
Serial.print(_dateTime.dayofWeek);
Serial.print( " ");
Serial.print(_dateTime.hour);
Serial.print( "H ");
Serial.print(_dateTime.minute);
Serial.print( "M ");
Serial.print(_dateTime.second);
Serial.print( "S ");
Serial.println();
} else {
#ifdef DEBUG_ON
Serial.println("Invalid time !!!");
Serial.println("");
#endif
}
}
// Converts a unix time stamp to a strDateTime structure
strDateTime NTPtime::ConvertUnixTimestamp( unsigned long _tempTimeStamp) {
strDateTime _tempDateTime;
uint8_t _year, _month, _monthLength;
uint32_t _time;
unsigned long _days;
_tempDateTime.epochTime = _tempTimeStamp;
_time = (uint32_t)_tempTimeStamp;
_tempDateTime.second = _time % 60;
_time /= 60; // now it is minutes
_tempDateTime.minute = _time % 60;
_time /= 60; // now it is hours
_tempDateTime.hour = _time % 24;
_time /= 24; // now it is _days
_tempDateTime.dayofWeek = ((_time + 4) % 7) + 1; // Sunday is day 1
_year = 0;
_days = 0;
while ((unsigned)(_days += (LEAP_YEAR(_year) ? 366 : 365)) <= _time) {
_year++;
}
_tempDateTime.year = _year; // year is offset from 1970
_days -= LEAP_YEAR(_year) ? 366 : 365;
_time -= _days; // now it is days in this year, starting at 0
_days = 0;
_month = 0;
_monthLength = 0;
for (_month = 0; _month < 12; _month++) {
if (_month == 1) { // february
if (LEAP_YEAR(_year)) {
_monthLength = 29;
} else {
_monthLength = 28;
}
} else {
_monthLength = _monthDays[_month];
}
if (_time >= _monthLength) {
_time -= _monthLength;
} else {
break;
}
}
_tempDateTime.month = _month + 1; // jan is month 1
_tempDateTime.day = _time + 1; // day of month
_tempDateTime.year += 1970;
return _tempDateTime;
}
//
// Summertime calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
//
boolean NTPtime::summerTime(unsigned long _timeStamp ) {
strDateTime _tempDateTime;
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
// printTime("Innerhalb ", _tempDateTime);
if (_tempDateTime.month < 3 || _tempDateTime.month > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
if (_tempDateTime.month > 3 && _tempDateTime.month < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
if (_tempDateTime.month == 3 && (_tempDateTime.hour + 24 * _tempDateTime.day) >= (1 + 24 * (31 - (5 * _tempDateTime.year / 4 + 4) % 7)) || _tempDateTime.month == 10 && (_tempDateTime.hour + 24 * _tempDateTime.day) < (1 + 24 * (31 - (5 * _tempDateTime.year / 4 + 1) % 7)))
return true;
else
return false;
}
boolean NTPtime::daylightSavingTime(unsigned long _timeStamp) {
strDateTime _tempDateTime;
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
// here the US code
//return false;
// see http://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date
// since 2007 DST begins on second Sunday of March and ends on first Sunday of November.
// Time change occurs at 2AM locally
if (_tempDateTime.month < 3 || _tempDateTime.month > 11) return false; //January, february, and december are out.
if (_tempDateTime.month > 3 && _tempDateTime.month < 11) return true; //April to October are in
int previousSunday = _tempDateTime.day - (_tempDateTime.dayofWeek - 1); // dow Sunday input was 1,
// need it to be Sunday = 0. If 1st of month = Sunday, previousSunday=1-0=1
//int previousSunday = day - (dow-1);
// -------------------- March ---------------------------------------
//In march, we are DST if our previous Sunday was = to or after the 8th.
if (_tempDateTime.month == 3 ) { // in march, if previous Sunday is after the 8th, is DST
// unless Sunday and hour < 2am
if ( previousSunday >= 8 ) { // Sunday = 1
// return true if day > 14 or (dow == 1 and hour >= 2)
return ((_tempDateTime.day > 14) ||
((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour >= 2) || _tempDateTime.dayofWeek > 1));
} // end if ( previousSunday >= 8 && _dateTime.dayofWeek > 0 )
else
{
// previousSunday has to be < 8 to get here
//return (previousSunday < 8 && (_tempDateTime.dayofWeek - 1) = 0 && _tempDateTime.hour >= 2)
return false;
} // end else
} // end if (_tempDateTime.month == 3 )
// ------------------------------- November -------------------------------
// gets here only if month = November
//In november we must be before the first Sunday to be dst.
//That means the previous Sunday must be before the 2nd.
if (previousSunday < 1)
{
// is not true for Sunday after 2am or any day after 1st Sunday any time
return ((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 1) || (_tempDateTime.dayofWeek > 1));
//return true;
} // end if (previousSunday < 1)
else
{
// return false unless after first wk and dow = Sunday and hour < 2
return (_tempDateTime.day <8 && _tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 1);
} // end else
} // end boolean NTPtime::daylightSavingTime(unsigned long _timeStamp)
unsigned long NTPtime::adjustTimeZone(unsigned long _timeStamp, float _timeZone, int _DayLightSaving) {
if (_DayLightSaving ==1 && summerTime(_timeStamp)) _timeStamp += 3600; // European Summer time
_timeStamp += (unsigned long)(_timeZone * 3600.0); // adjust timezone
if (_DayLightSaving ==2 && daylightSavingTime(_timeStamp)) _timeStamp += 3600; // US daylight time
return _timeStamp;
}
// time zone is the difference to UTC in hours
// if _isDayLightSaving is true, time will be adjusted accordingly
// Use returned time only after checking "ret.valid" flag
strDateTime NTPtime::getNTPtime(float _timeZone, int _DayLightSaving) {
int cb;
strDateTime _dateTime;
unsigned long _unixTime = 0;
_dateTime.valid = false;
unsigned long _currentTimeStamp;
if (_sendPhase) {
if (_sentTime && ((millis() - _sentTime) < _sendInterval)) {
return _dateTime;
}
_sendPhase = false;
UDPNTPClient.begin(1337); // Port for NTP receive
#ifdef DEBUG_ON
IPAddress _timeServerIP;
WiFi.hostByName(_NTPserver.c_str(), _timeServerIP);
Serial.println();
Serial.println(_timeServerIP);
Serial.println("Sending NTP packet");
#endif
memset(_packetBuffer, 0, NTP_PACKET_SIZE);
_packetBuffer[0] = 0b11100011; // LI, Version, Mode
_packetBuffer[1] = 0; // Stratum, or type of clock
_packetBuffer[2] = 6; // Polling Interval
_packetBuffer[3] = 0xEC; // Peer Clock Precision
_packetBuffer[12] = 49;
_packetBuffer[13] = 0x4E;
_packetBuffer[14] = 49;
_packetBuffer[15] = 52;
UDPNTPClient.beginPacket(_NTPserver.c_str(), 123);
UDPNTPClient.write(_packetBuffer, NTP_PACKET_SIZE);
UDPNTPClient.endPacket();
_sentTime = millis();
} else {
cb = UDPNTPClient.parsePacket();
if (cb == 0) {
if ((millis() - _sentTime) > _recvTimeout) {
_sendPhase = true;
_sentTime = 0;
}
} else {
#ifdef DEBUG_ON
Serial.print("NTP packet received, length=");
Serial.println(cb);
#endif
UDPNTPClient.read(_packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
unsigned long highWord = word(_packetBuffer[40], _packetBuffer[41]);
unsigned long lowWord = word(_packetBuffer[42], _packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
const unsigned long seventyYears = 2208988800UL;
_unixTime = secsSince1900 - seventyYears;
if (secsSince1900 > 0) {
_currentTimeStamp = adjustTimeZone(_unixTime, _timeZone, _DayLightSaving);
_dateTime = ConvertUnixTimestamp(_currentTimeStamp);
_dateTime.valid = true;
} else
_dateTime.valid = false;
_sendPhase = true;
}
}
return _dateTime;
}
Código NTPtimeESP.h:
/*
NTPtime for ESP8266/ESP32
This routine gets the unixtime from a NTP server and adjusts it to the time zone and the
Middle European summer time if requested
Author: Andreas Spiess V1.0 2016-6-28
Based on work from John Lassen: http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig
*/
#ifndef NTPtime_h
#define NTPtime_h
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiUdp.h>
struct strDateTime
{
byte hour;
byte minute;
byte second;
int year;
byte month;
byte day;
byte dayofWeek;
unsigned long epochTime;
boolean valid;
};
class NTPtime {
public:
NTPtime(String NTPtime);
strDateTime getNTPtime(float _timeZone, int _DayLightSaving);
void printDateTime(strDateTime _dateTime);
bool setSendInterval(unsigned long _sendInterval); // in seconds
bool setRecvTimeout(unsigned long _recvTimeout); // in seconds
private:
bool _sendPhase;
unsigned long _sentTime;
unsigned long _sendInterval;
unsigned long _recvTimeout;
strDateTime ConvertUnixTimestamp( unsigned long _tempTimeStamp);
boolean summerTime(unsigned long _timeStamp );
boolean daylightSavingTime(unsigned long _timeStamp);
unsigned long adjustTimeZone(unsigned long _timeStamp, float _timeZone, int _DayLightSavingSaving);
WiFiUDP UDPNTPClient;
};
#endif
Código Olimexserver:
/*
WiFi Web Server for ESP32-EVB and WATER-VALVE-6-5MM-12VDC
from www.olimex.com
A simple web server that lets turn on/off the relay 1
through a button or through delay command on a specific time.
This example is written for a network using WPA encryption. For
WEP or WPA, change the Wifi.begin() call accordingly.
created on Olimex ESP32-EVB, 5 december 2012 by Stanimir Petev @ olimex
this software is far for complete and just for demo purposes, feel free to use and change
The project is based on the example of Tom Igoe (SimpleWiFiServer) on 25 Nov 2012
and ported for sparkfun esp32 on 31.01.2017 by Jan Hendrik Berlin
*/
#include <WiFi.h>
#include "Arduino.h"
#include <NTPtimeESP.h>
#define DEBUG_ON
#define RELAY 32
NTPtime NTPch("ch.pool.ntp.org"); // Choose server pool as required
strDateTime dateTime;
const char* ssid = "nombreWifiRouter"; //enter here your WiFi SSID
const char* password = "ClaveWifiRouter"; //enter here your WiFi password
WiFiServer server(80);
// Client variables
char linebuf[80];
int charcount=0;
int Hour=12, Minute=0, Second=0;
int SetHourON=0, SetMinuteON=0, SetSecondON=0;
int SetHourOFF=0, SetMinuteOFF=0, SetSecondOFF=0;
byte actualHour = dateTime.hour;
byte actualMinute = dateTime.minute;
byte actualSecond = dateTime.second;
int actualyear = dateTime.year;
byte actualMonth = dateTime.month;
byte actualday = dateTime.day;
byte actualdayofWeek = dateTime.dayofWeek;
extern const char WebPage [168][80];
void Print_Webpage (WiFiClient &client)
{
int i;
char Buff[100], Parameter[10];
for (i=0; WebPage[i][0]; i++)
{
switch (i)
{
// list of lines where parameters should be placed
case 125: // <div class=\"left\">Status <b class=%s</b></div>",
if (digitalRead (RELAY))
sprintf (Parameter, "\"%s\">%s", "on", "ON");
else
sprintf (Parameter, "\"%s\">%s", "off", "OFF");
break;
case 126: // <div class=\"right\">Current time <b>%s</b></div>",
sprintf (Parameter, "%02d:%02d:%02d", actualHour, actualMinute, actualSecond);
break;
case 130: // <div class=\"value\">%s</div>",
sprintf (Parameter, "%02d", Hour);
break;
case 137: // <div class=\"value\">%s</div>",
sprintf (Parameter, "%02d", Minute);
break;
case 144: // <div class=\"value\">%s</div>",
sprintf (Parameter, "%02d", Second);
break;
case 153: // <div class=\"value\">%s</div>",
sprintf (Parameter, "%02d:%02d:%02d", SetHourON, SetMinuteON, SetSecondON);
break;
case 157: // <div class=\"value\">%s</div>",
sprintf (Parameter, "%02d:%02d:%02d", SetHourOFF, SetMinuteOFF, SetSecondOFF);
break;
default:
Parameter[0] = 0;
break;
}
sprintf (Buff, WebPage[i], Parameter);
client.println (Buff);
}
}
void setup()
{
Serial.begin(9600);
pinMode(RELAY, OUTPUT); // set the LED pin mode
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Modo Wi-Fi: ");
Serial.println(WiFi.getMode());
server.begin();
}
long int NTPLastUpdate, LastUpdate, Time;
bool NTPUpdateFlag=true;
void loop()
{
Time = millis ();
if (Time - NTPLastUpdate > 120000)
NTPUpdateFlag = true;
if (NTPUpdateFlag)
{
dateTime = NTPch.getNTPtime(1.0, 1);
// check dateTime.valid before using the returned time
// Use "setSendInterval" or "setRecvTimeout" if required
if(dateTime.valid)
{
NTPUpdateFlag = false;
NTPch.printDateTime(dateTime);
actualHour = dateTime.hour;
actualMinute = dateTime.minute;
actualSecond = dateTime.second;
actualyear = dateTime.year;
actualMonth = dateTime.month;
actualday =dateTime.day;
actualdayofWeek = dateTime.dayofWeek;
NTPLastUpdate = millis();
LastUpdate = millis();
}
}
if (Time - LastUpdate > 1000)
{
LastUpdate = Time;
actualSecond++;
if (actualSecond >= 60)
{
actualSecond = 0;
actualMinute++;
if (actualMinute >= 60)
{
actualMinute = 0;
actualHour++;
if (actualHour >= 24)
actualHour = 0;
}
}
}
if ((actualHour == SetHourON) && (actualMinute == SetMinuteON) && (actualSecond == SetSecondON))
digitalWrite(RELAY, HIGH);
if ((actualHour == SetHourOFF) && (actualMinute == SetMinuteOFF) && (actualSecond == SetSecondOFF))
digitalWrite(RELAY, LOW);
// listen for incoming clients
WiFiClient client = server.available();
if (client) {
Serial.println("New client");
memset(linebuf,0,sizeof(linebuf));
charcount=0;
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected())
{
if (client.available())
{
char c = client.read();
Serial.write(c);
//read char by char HTTP request
linebuf[charcount]=c;
if (charcount<sizeof(linebuf)-1) charcount++;
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank)
{
Print_Webpage (client);
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
if (strstr(linebuf,"GET /setON") > 0)
{
SetHourON = Hour;
SetMinuteON = Minute;
SetSecondON = Second;
}
else
if (strstr(linebuf,"GET /setOFF") > 0)
{
SetHourOFF = Hour;
SetMinuteOFF = Minute;
SetSecondOFF = Second;
}
else
if (strstr(linebuf,"GET /off") > 0)
{
digitalWrite (RELAY, LOW);
}
else
if (strstr(linebuf,"GET /on") > 0)
{
digitalWrite (RELAY, HIGH);
}
else
if (strstr(linebuf,"GET /h+") > 0)
{
Hour = (Hour + 1) % 24;
}
else
if (strstr(linebuf,"GET /h-") > 0)
{
Hour = (Hour + 24 - 1) % 24;
}
else
if (strstr(linebuf,"GET /m+") > 0)
{
Minute = (Minute + 1) % 60;
}
else
if (strstr(linebuf,"GET /m-") > 0)
{
Minute = (Minute + 60 - 1) % 60;
}
else
if (strstr(linebuf,"GET /s+") > 0)
{
Second = (Second + 1) % 60;
}
else
if (strstr(linebuf,"GET /s-") > 0)
{
Second = (Second + 60 - 1) % 60;
}
// you're starting a new line
currentLineIsBlank = true;
memset(linebuf,0,sizeof(linebuf));
charcount=0;
}
else
if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
Código Infrarrojo:
#include <Arduino.h>
//necesario importar las librerias IRrecv.h, IRutils. Para esto incluir en VSCode Platformio :lib_deps = IRremoteESP8266
#include <IRutils.h>
#include <IRsend.h>
#define IR_SEND_PIN 12 // Pin del emisor IR en la ESP32-EVB
#define TV_POWER_CODE 0x20DF10EF // Código IR de encendido/apagado de la TV
#define TV_PROTOCOL NEC // Protocolo del control remoto (generalmente NEC)
IRsend irsend(IR_SEND_PIN);
bool estado = false; // Variable para alternar el encendido y apagado
void setup() {
Serial.begin(9600);
irsend.begin(); // Inicializa el transmisor IR
Serial.println("Enviando señal IR cada 10 segundos...");
}
void loop() {
Serial.print("Enviando código IR: ");
Serial.println(TV_POWER_CODE, HEX);
irsend.sendNEC(TV_POWER_CODE, 32); // Enviar el código IR con 32 bits
estado = !estado; // Alternar estado
Serial.println(estado ? "Encendiendo TV" : "Apagando TV");
delay(20000); // Esperar 10 segundos antes de enviar de nuevo
}
#include <Arduino.h>
//necesario importar las librerias IRrecv.h, IRutils. Para esto incluir en VSCode Platformio :lib_deps = IRremoteESP8266
#include <IRrecv.h>
#include <IRutils.h>
#define IR_RECEIVE_PIN 39 // Pin del receptor IR en la ESP32-EVB
IRrecv irrecv(IR_RECEIVE_PIN);
decode_results results;
void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); // Inicia el receptor IR
Serial.println("Receptor IR listo. Apunta el mando y presiona un botón...");
}
void loop() {
if (irrecv.decode(&results)) {
Serial.print("Código recibido: ");
Serial.println(results.value, HEX);
irrecv.resume(); // Recibir la siguiente señal
}
}
Código Acces Point ESP32:
#include <WiFi.h>
#include <WebSocketsServer.h> // Asegúrate de haber instalado esta librería
const char* apSSID = "nombreOlimex";
const char* apPassword = "12345678";
WiFiServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81); // WebSocket en el puerto 81
#define RELAY1 32
#define RELAY2 33
// **DECLARACIÓN DE LA FUNCIÓN ANTES DE setup()**
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
void setup() {
Serial.begin(9600);
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
WiFi.softAP(apSSID, apPassword);
Serial.println("WiFi AP started!");
Serial.print("Connect to: ");
Serial.println(apSSID);
Serial.print("Then open: http://");
Serial.println(WiFi.softAPIP());
server.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
WiFiClient client = server.available();
if (client) {
Serial.println("New client connected");
String request = "";
while (client.available()) {
char c = client.read();
request += c;
}
Serial.println("Request: " + request);
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html><html><head>");
client.println("<meta name='viewport' content='width=device-width, initial-scale=1'>");
client.println("<script>");
client.println("var socket = new WebSocket('ws://' + location.hostname + ':81/');");
client.println("function sendRelayCommand(cmd) { socket.send(cmd); }");
client.println("socket.onmessage = function(event) {");
client.println(" var state = JSON.parse(event.data);");
client.println(" document.getElementById('relay1').textContent = state.relay1 ? 'ON' : 'OFF';");
client.println(" document.getElementById('relay2').textContent = state.relay2 ? 'ON' : 'OFF';");
client.println("};");
client.println("</script>");
client.println("<style>");
client.println("body { font-family: Arial, sans-serif; text-align: center; }");
client.println(".container { margin-top: 50px; }");
client.println(".relay-block { margin-bottom: 20px; }");
client.println("button { font-size: 30px; padding: 10px; width: 150px; margin: 5px; display: block; }");
client.println(".on { background-color: green; color: white; }");
client.println(".off { background-color: red; color: white; }");
client.println("</style>");
client.println("</head><body>");
client.println("<h1>ESP32 Relay Control</h1>");
client.println("<div class='container'>");
client.println("<div class='relay-block'>");
client.println("<h2>Relay 1</h2>");
client.println("<button id='relay1' class='on' onclick=\"sendRelayCommand('relay1_on')\">ON</button>");
client.println("<button class='off' onclick=\"sendRelayCommand('relay1_off')\">OFF</button>");
client.println("</div>");
client.println("<div class='relay-block'>");
client.println("<h2>Relay 2</h2>");
client.println("<button id='relay2' class='on' onclick=\"sendRelayCommand('relay2_on')\">ON</button>");
client.println("<button class='off' onclick=\"sendRelayCommand('relay2_off')\">OFF</button>");
client.println("</div>");
client.println("</div>");
client.println("</body></html>");
delay(10);
client.stop();
Serial.println("Client disconnected");
}
}
// **DEFINICIÓN de webSocketEvent()**
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
String message = String((char *)payload);
if (message == "relay1_on") {
digitalWrite(RELAY1, HIGH);
} else if (message == "relay1_off") {
digitalWrite(RELAY1, LOW);
} else if (message == "relay2_on") {
digitalWrite(RELAY2, HIGH);
} else if (message == "relay2_off") {
digitalWrite(RELAY2, LOW);
}
// **Enviar estado actualizado de los relés**
String relayState = "{\"relay1\": " + String(digitalRead(RELAY1)) + ", \"relay2\": " + String(digitalRead(RELAY2)) + "}";
webSocket.broadcastTXT(relayState);
}