#include #include #include #include #include Servo myservo; // create servo object to control a servo // Constants const char *ssid = "ESP32-AP"; const char *password = "LetMeInPlz"; const int dns_port = 53; const int http_port = 80; const int ws_port = 1337; const int mist_pin = 21; const int led_pin = 6; const int motor_pin = 20; const int servo_pin = 7; const int TDS_pin = 4; const float temperature = 20; // arbitrary temperature for TDS compensation #define VREF 3.3 // analog reference voltage(Volt) of the ADC on TDS sensor // Globals AsyncWebServer server(80); WebSocketsServer webSocket = WebSocketsServer(1337); char msg_buf[10]; int led_state = 0; int mist_state = 0; int motor_state = 0; int servo_state = 90; int TDS_value = 0; /*********************************************************** * Functions */ // Callback: receiving any WebSocket message void onWebSocketEvent(uint8_t client_num, WStype_t type, uint8_t *payload, size_t length) { // Figure out the type of WebSocket event switch (type) { // Client has disconnected case WStype_DISCONNECTED: Serial.printf("[%u] Disconnected!\n", client_num); break; // New client has connected case WStype_CONNECTED: { IPAddress ip = webSocket.remoteIP(client_num); Serial.printf("[%u] Connection from ", client_num); Serial.println(ip.toString()); } break; // Handle text messages from client case WStype_TEXT: // Print out raw message Serial.printf("[%u] Received text: %s\n", client_num, payload); // Toggle LED if (strcmp((char *)payload, "toggleLED") == 0) { led_state = led_state ? 0 : 1; Serial.printf("Toggling LED to %u\n", led_state); digitalWrite(led_pin, led_state); } else if (strncmp((char *)payload, "motorPWM=", 9) == 0) { motor_state = atoi((char *)payload + 9); // Convert the substring after "motorSpeed=" to an integer if (motor_state >= 0 && motor_state <= 255) { Serial.printf("Setting motor PWM to %d", motor_state); ledcWrite(motor_pin, motor_state); // analogWrite(motor_pin, motor_state); } else { Serial.printf("Invalid motor speed: %d. Must be between 0 and 255.\n", motor_state); } } else if (strncmp((char *)payload, "servoAngle=", 11) == 0) { servo_state = atoi((char *)payload + 11); Serial.printf("Setting servoAngle to %d", servo_state); if (servo_state >= 0 && servo_state <= 180) { analogWrite(servo_pin, servo_state); // FIXME myservo.write(servo_state); } else { Serial.printf("Invalid servo angle: %d. Must be between 0 and 255.\n", servo_state); } } else if (strncmp((char *)payload, "toggleMist", 10) == 0) { mist_state = mist_state ? 0 : 1; Serial.printf("Toggling mist to %u\n", mist_state); digitalWrite(mist_pin, mist_state); } else if (strcmp((char *)payload, "getLEDState") == 0) { sprintf(msg_buf, "led=%d", led_state); Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf); webSocket.sendTXT(client_num, msg_buf); } else if (strcmp((char *)payload, "getMistState") == 0) { sprintf(msg_buf, "mist=%d", mist_state); Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf); webSocket.sendTXT(client_num, msg_buf); } else if (strcmp((char *)payload, "getMotorState") == 0) { sprintf(msg_buf, "motor=%d", motor_state); Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf); webSocket.sendTXT(client_num, msg_buf); } else if (strcmp((char *)payload, "getServoState") == 0) { sprintf(msg_buf, "servo=%d", servo_state); Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf); webSocket.sendTXT(client_num, msg_buf); } else if (strcmp((char *)payload, "getTDSState") == 0) { TDS_value = readTDS(); sprintf(msg_buf, "TDS=%d", TDS_value); Serial.printf("Sending to [%u]: %s\n", client_num, msg_buf); webSocket.sendTXT(client_num, msg_buf); } // Message not recognized else { Serial.println("[%u] Message not recognized"); } break; // For everything else: do nothing case WStype_BIN: case WStype_ERROR: case WStype_FRAGMENT_TEXT_START: case WStype_FRAGMENT_BIN_START: case WStype_FRAGMENT: case WStype_FRAGMENT_FIN: default: break; } } // Callback: send homepage void onIndexRequest(AsyncWebServerRequest *request) { IPAddress remote_ip = request->client()->remoteIP(); Serial.println("[" + remote_ip.toString() + "] HTTP GET request of " + request->url()); request->send(SPIFFS, "/index.html", "text/html"); } // Callback: send style sheet void onCSSRequest(AsyncWebServerRequest *request) { IPAddress remote_ip = request->client()->remoteIP(); Serial.println("[" + remote_ip.toString() + "] HTTP GET request of " + request->url()); request->send(SPIFFS, "/style.css", "text/css"); } // Callback: send 404 if requested file does not exist void onPageNotFound(AsyncWebServerRequest *request) { IPAddress remote_ip = request->client()->remoteIP(); Serial.println("[" + remote_ip.toString() + "] HTTP GET request of " + request->url()); request->send(404, "text/plain", "Not found"); } // read 10 TDS values from the sensor and return the average int readTDS() { float sumValue = 0; for (int i = 0; i < 10; i++) { sumValue += analogRead(TDS_pin) * (float)VREF / 4096.0; } float averageVoltage = sumValue / 10; float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0); float compensationVolatge = averageVoltage / compensationCoefficient; // temperature compensation float tdsValue = (133.42 * compensationVolatge * compensationVolatge * compensationVolatge - 255.86 * compensationVolatge * compensationVolatge + 857.39 * compensationVolatge) * 0.5; // convert voltage value to tds value return tdsValue; } /*********************************************************** * Main */ void setup() { // Pin initializations pinMode(TDS_pin, INPUT); pinMode(led_pin, OUTPUT); digitalWrite(led_pin, LOW); pinMode(mist_pin, OUTPUT); digitalWrite(mist_pin, LOW); pinMode(motor_pin, OUTPUT); digitalWrite(motor_pin, LOW); ledcAttachChannel(motor_pin, 10000, 8, 3); // Servo // Allow allocation of all timers ESP32PWM::allocateTimer(0); ESP32PWM::allocateTimer(1); ESP32PWM::allocateTimer(2); ESP32PWM::allocateTimer(3); myservo.setPeriodHertz(50); // standard 50 hz servo myservo.attach(servo_pin, 500, 2500); // // using default min/max of 500us and 2500us // different servos may require different min/max settings // for an accurate 0 to 180 sweep myservo.write(servo_state); // Start Serial port Serial.begin(115200); // Make sure we can read the file system if (!SPIFFS.begin()) { Serial.println("Error mounting SPIFFS"); while (1) ; } // Start access point WiFi.softAP(ssid, password); // Print our IP address Serial.println(); Serial.println("AP running"); Serial.print("My IP address: "); Serial.println(WiFi.softAPIP()); // On HTTP request for root, provide index.html file server.on("/", HTTP_GET, onIndexRequest); // On HTTP request for style sheet, provide style.css server.on("/style.css", HTTP_GET, onCSSRequest); // Handle requests for pages that do not exist server.onNotFound(onPageNotFound); // Start web server server.begin(); // Start WebSocket server and assign callback webSocket.begin(); webSocket.onEvent(onWebSocketEvent); } void loop() { // Look for and handle WebSocket data webSocket.loop(); }