// author: Ricardo Lerch @RickLerch // ricardo.lerch@gmail.com #include //ESP8266 Core WiFi Library #include #include //Local DNS Server used for redirecting all requests to the configuration portal #include #include //Local WebServer used to serve the configuration portal #include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic #include #include #include #include #include extern "C" { #include "user_interface.h" } #define LEDA D7 // led testigo #define LEDE D6 // led estimulo de salida #define TRIGGER_PIN D5 // pulsador uso multiple #define TRIGGER D1 // trigger ultrasonico #define ECHO D2 // echo ultrasonico const char htmlHeader[] PROGMEM = R"rawliteral( TrainerLights
)rawliteral"; const char htmlFooter[] PROGMEM = R"rawliteral(
)rawliteral"; const char htmlCss[] PROGMEM = R"rawliteral( )rawliteral"; const char htmlContent[] PROGMEM = R"rawliteral(

Tiempo de la prueba

00:00.00




Puntos

0

Errores

0


Tiempos de reacción (ms)

Promedio

0

Mínimo

0

Máximo

0


Distancias de reacción (cm)

Promedio

0

Mínimo

0

Máximo

0




Modos de entrenamiento

Delay

Elije un valor de delay (ms) al azar entre:

Timeout

Elije un valor de timeout (ms) al azar entre:
Mínimo
Máximo

Rango de detección

Detecta un objeto entre mínimo y máximo (cm)
Mínimo
Máximo





Listar Sensores

Sensores Conectados:






)rawliteral"; // configuration String tmode = "random"; int min_delay = 0; int max_delay = 0; int mim_timeout = 1000; int max_timeout = 1000; int accelerate_delay_percent = 0; int accelerate_delay_per_seconds = 0; int accelerate_timeout_percent = 0; int accelerate_timeout_per_seconds = 0; int min_detection_range = 0; int max_detection_range = 50; int timeout = 1000; int tdelay = 0; bool isTesting; // si esta dentro del tiempo de prueba mada los datos a la app int currentSensor; // test variables int test_score = 0; int test_errors = 0; int max_distance = 0; int min_distance = 9999; int avg_distance = 0; int max_response_time = 0; int min_response_time = 9999; int avg_response_time = 0; int test_count = 0; time_t app_time = 0; Scheduler ts; void MeasureDistance(); void StimulusTimeout(); // Tasks // Task tMeasureDistance(30, TASK_FOREVER, &MeasureDistance, &ts, true); Task tStimulusTimeout(2000, TASK_ONCE, &StimulusTimeout, &ts, false); ESP8266WebServer webServer = ESP8266WebServer(80); WebSocketsServer webSocket = WebSocketsServer(81); const char* apName = "TrainerLights"; const char* apPassword = "1234567890"; const char* host = ""; // class para la lista de sensores conectados class Sensor { public: IPAddress ip; // ip del sensor bool isEnabled; // esta enabled uint8_t num; }; LinkedList sensorList = LinkedList(); uint8_t appConnected = NULL; // class para guardar el sensor que se esta ejecutando el estimulo class sensorStimulating { public: IPAddress ip; // ip del sensor }; // esto se ejecuta cuando una estacion se desconecta WiFiEventHandler stationDisconnectedHandler; void onStationDisconnected(const WiFiEventSoftAPModeStationDisconnected& evt) { Serial.println("** Station disconnected: **"); } bool stimulating = false; int lastSensor = 1000; // last sensor stimulating in sensorList void setup() { delay(100); pinMode(TRIGGER_PIN, INPUT); pinMode(LEDE , OUTPUT); pinMode(LEDA , OUTPUT); pinMode(TRIGGER, OUTPUT); pinMode(ECHO, INPUT); Serial.begin (115200); Serial.setDebugOutput(true); Serial.println(" "); Serial.println(" "); Serial.println(" "); Serial.println("*****************************"); Serial.println("* *"); Serial.println("* TrainerLights *"); Serial.println("* By: Ricardo Lerch *"); Serial.println("* ricardo.lerch@gmail.com *"); Serial.println("* *"); Serial.println("*****************************"); Serial.println(" "); Serial.println(" "); Serial.println(" "); // Serial.end(); // https://github.com/esp8266/Arduino/issues/570 // aumenta el maximo de conexiones de 4(default) a 32 struct softap_config config; wifi_softap_get_config(&config); // Get config first. config.max_connection = 32; // how many stations can connect to ESP8266 softAP at most. wifi_softap_set_config(&config);// Set ESP8266 softap config // no duerme el wifi wifi_set_sleep_type(NONE_SLEEP_T); // // WiFi.disconnect(); WiFi.mode(WIFI_AP_STA); // definition // bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4); // WiFi.softAP(apName, apPassword, 1, 0, 32); WiFi.softAP(apName, apPassword); Serial.print("AP IP address "); Serial.println(WiFi.softAPIP()); // start webSocket server webSocket.begin(); webSocket.onEvent(webSocketEvent); if(MDNS.begin("esp8266")) { Serial.println("MDNS responder started"); } // handle index webServer.on("/", []() { // send index.html webServer.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); webServer.sendHeader("Pragma", "no-cache"); webServer.sendHeader("Expires", "-1"); webServer.setContentLength(strlen_P(htmlHeader) + strlen_P(htmlCss) + strlen_P(htmlContent) + strlen_P(htmlFooter)); webServer.send(200, "text/html", ""); webServer.sendContent_P(htmlHeader); webServer.sendContent_P(htmlCss); webServer.sendContent_P(htmlContent); webServer.sendContent_P(htmlFooter); webServer.client().stop(); }); // start webServer server webServer.begin(); // Add service to MDNS MDNS.addService("http", "tcp", 80); MDNS.addService("ws", "tcp", 81); // avisa cuando un cliente se desconecta del ap stationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(&onStationDisconnected); } void loop() { webSocket.loop(); webServer.handleClient(); ts.execute(); // ejecutar programa de entrenamiento // si no esta estimulando elige un sensor al azar y lo pone on Sensor *s; String a; if (!stimulating){ // stimulustTimeout = stimulustTimeout - stimulustTimeout * 0.009; // elige un sensor al azar if (tmode == "random") { currentSensor = random(0,sensorList.size()); }else{ currentSensor++; if (currentSensor >= sensorList.size()){ currentSensor = 0; } } timeout = random(mim_timeout, max_timeout+1); tdelay = random(min_delay, max_delay+1); if (timeout < 100){ timeout = 100; } if (tdelay < 0){ tdelay = 0; } if (currentSensor != lastSensor && sensorList.size() > 0){ // solo elije uno diferente al ultimo lastSensor = currentSensor; s = sensorList.get(currentSensor); if (s){ a = "{\"type\":\"stimulus\""; a += ",\"timeout\":\"" + String(timeout) + "\""; a += ",\"delay\":\"" + String(tdelay) + "\""; a += ",\"min_detection_range\":\"" + String(min_detection_range) + "\""; a += ",\"max_detection_range\":\"" + String(max_detection_range) + "\""; a += ",\"light\":{\"mode\":\"on\",\"intensity\":\"100\",\"color\":{\"R\":\"255\",\"G\":\"255\",\"B\":\"255\"}}}"; webSocket.sendTXT(s->num, a); // pone el timeout del sensor mas 1000ms tStimulusTimeout.setInterval(tdelay+timeout+1000); tStimulusTimeout.restartDelayed(); stimulating = true; Serial.println(a); } } } } void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { IPAddress ip = webSocket.remoteIP(num); switch(type) { case WStype_DISCONNECTED: Serial.printf("[%u] Disconnected!\n", num); break; case WStype_CONNECTED: Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); // send message to client webSocket.sendTXT(num, "{\"status\":\"connected\"}"); break; case WStype_TEXT: Serial.printf("[%u] get Text: %s\n", num, payload); // recibe json desde el js en la pagina de control StaticJsonBuffer<512> jsonBuffer; JsonObject& root = jsonBuffer.parseObject(payload); if (!root.success()) { Serial.println("JSON parsing failed!"); } const char* jtype = root["type"]; Serial.print("recibe: "); Serial.println(jtype); Sensor *s; int i; String a=""; // ************************************ // List Sensors if (String(jtype) == String("list_sensors")){ // lista sensores conectados Serial.println("List Sensors"); // devuelve un json con la lista de sensores conectados a="{\"type\":\"sensor_list\",\"sensors\":["; for (i = 0; i < sensorList.size(); i++){ // Get sensors from list s = sensorList.get(i); Serial.println(s->ip); // arma el json con la ip if (i){ a +=","; } a += "{\"id\":\"" +String(s->ip)+ "\""; a += ",\"ip\":\"" + String(s->ip[0]) + "." + String(s->ip[1]) + "." + String(s->ip[2]) + "." + String(s->ip[3]) + "\""; a += ",\"num\":\"" + String(s->num) + "\""; a += ",\"state\":\"on\"}"; // String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]) // a.concat("\"}"); } a +="]}"; char jstr[a.length()+1]; a.toCharArray(jstr, a.length()+1); // send websocket packet webSocket.sendTXT(num, a); } // ************************************ // recibe un nuevo sensor via websocket if (String(jtype) == String("sensor")){ Serial.println("SENSOR"); Sensor *newSensor = new Sensor(); newSensor->ip = ip; newSensor->isEnabled = true; newSensor->num = num; bool sensorExists = false; Sensor *s; int i; for(i = 0; i < sensorList.size(); i++){ // Get sensors from list s = sensorList.get(i); if (s->ip == newSensor->ip){ // el sensor ya existe en la lista lo deja ahi sensorExists = true; } } if (!sensorExists){ sensorList.add(newSensor); } Serial.println("Sensores conectados: "); // manda la lista de sensores conectados al serial for (i = 0; i < sensorList.size(); i++){ // Get sensors from list s = sensorList.get(i); Serial.println(s->ip); } } // ************************************ // response if (String(jtype) == String("response")){ Serial.println("SENSOR response"); tStimulusTimeout.disable(); stimulating = false; // si esta en modo test y la app_connected manda info a la app conectada if (isTesting){ int test_error = root["error"]; if (test_error){ test_errors++; }else{ test_score++; if (test_count){ // solo la primer cuenta avg_response_time = (avg_response_time + int(root["time"])) / 2; avg_distance = (avg_distance + int(root["distance"])) / 2; }else{ test_score = 0; test_errors = 0; max_distance = root["distance"]; min_distance = root["distance"]; avg_distance = root["distance"]; max_response_time = root["time"]; min_response_time = root["time"]; avg_response_time = root["time"]; } if (max_response_time < root["time"]){max_response_time = root["time"];} if (min_response_time > root["time"]){min_response_time = root["time"];} if (max_distance < root["distance"]){max_distance = root["distance"];} if (min_distance > root["distance"]){min_distance = root["distance"];} } // si esta conectada la app manda la info via websocket if (appConnected != NULL){ String a; a = "{\"type\":\"stats\""; a += ",\"test_score\":\"" + String(test_score) + "\""; a += ",\"test_errors\":\"" + String(test_errors) + "\""; a += ",\"max_distance\":\"" + String(max_distance) + "\""; a += ",\"min_distance\":\"" + String(min_distance) + "\""; a += ",\"avg_distance\":\"" + String(avg_distance) + "\""; a += ",\"max_response_time\":\"" + String(max_response_time) + "\""; a += ",\"min_response_time\":\"" + String(min_response_time) + "\""; a += ",\"avg_response_time\":\"" + String(avg_response_time) + "\""; a += "}"; webSocket.sendTXT(appConnected, a); Serial.println(a); } test_count++; } } // ************************************ // start_test if (String(jtype) == String("start_test")){ Serial.println("start_test"); isTesting = true; // test variables test_score = 0; test_errors = 0; max_distance = 0; min_distance = 9999; avg_distance = 0; max_response_time = 0; min_response_time = 9999; avg_response_time = 0; test_count = 0; } // ************************************ // stop_test if (String(jtype) == String("stop_test")){ Serial.println("stop_test"); isTesting = false; } // ************************************ // app_connected if (String(jtype) == String("app_connected")){ appConnected = num; app_time = root["current_time"]; Serial.print("current_time: "); Serial.println(app_time); Serial.print("app_connected: "); Serial.println(appConnected); } // ************************************ // restart if (String(jtype) == String("restart")){ for (i = 0; i < sensorList.size(); i++){ s = sensorList.get(i); a="{\"type\":\"restart\"}"; webSocket.sendTXT(s->num, a); } Serial.println("RESET"); ESP.reset(); } // ************************************ // config if (String(jtype) == String("config")){ // lista sensores conectados Serial.println("Get Configuration"); const char* ctmode = root["tmode"]; tmode = String(ctmode); min_delay = root["min_delay"]; max_delay = root["max_delay"]; mim_timeout = root["mim_timeout"]; max_timeout = root["max_timeout"]; accelerate_delay_percent = root["accelerate_delay_percent"]; accelerate_delay_per_seconds = root["accelerate_delay_per_seconds"]; accelerate_timeout_percent = root["accelerate_timeout_percent"]; accelerate_timeout_per_seconds = root["accelerate_timeout_per_seconds"]; min_detection_range = root["min_detection_range"]; max_detection_range = root["max_detection_range"]; Serial.println(max_detection_range); } break; } } void StimulusTimeout(){ // el ultimo sensor estimulado no respondio lo saca de la lista sensorList.remove(lastSensor); lastSensor = 1000; stimulating = false; Serial.println("StimulusTimeout"); }