#include #undef INADDR_NONE #include #include #include #include #include #include // For struct in_addr #include #include #include "OTA.h" #include "HermitCrab.h" #include "Config.h" #include "ConnectWiFi.h" #include "TimeManager.h" #include "History.h" #include "zcd.h" #include "AHT2x.h" #include "WiFiHost.h" //#include "UPnPClient.h" #define TAG_WIFI_HOST "WiFi Host" #define TCP_PACKET_SIZE_MAX 1460 //WiFiServer wifiServer(SERVER_PORT); //WiFiClient wifiClient; CWiFiHost host; CONFIG_TYPE configCopy; void CWiFiHost::Setup() { // UDP Packet packetUDP = { .sig1 = SIGNATURE1, .m_nSize = sizeof(UDP_PACKET), .m_nMessage = UDP_MESSAGE::MESSAGE_HEARTBEAT, .m_nDeviceType = config.m_nDeviceType, .m_nResetReason = RESET_REASON_CHIP_POWER_ON, .m_nChipID = config.m_nChipId, .m_nDeviceID = 0, //.m_nVersion = (uint32_t)atoll(&HC__VERSION[2]), .dwIPAddress = 0, .m_nPort = UDP_PORT, //.m_MACAddress = "", //.m_sDeviceName = "", .status = {0}, .sig2 = SIGNATURE2 }; packetUDP.m_nVersion = (uint32_t)atoll(&HC__VERSION[2]); strncpy((char *)packetUDP.m_MACAddress, WiFi.macAddress().c_str(), 17); packetUDP.m_MACAddress[17] = 0; strcpy(packetUDP.m_sDeviceName, config.m_sDeviceName); // TCP Packet hostPacket = { .sig1 = SIGNATURE1, .len = sizeof(TCP_PACKET), .cmd = ENUM_COMMAND::CMD_HELLO, .op = OPERATION_MODE::MODE_WAITING, .time = 0, .status = {0}, .sig2 = SIGNATURE2 }; clientPacket = hostPacket; //m_nPublicPort = config.m_nPublicPort; wifiServer = WiFiServer(SERVER_PORT, 1); //wifiExternal = WiFiServer(m_nPublicPort, 1); //wifiStatus = WIFI_NOT_CONNECTED; m_nDataSend_sent = 0; m_nDataReceive_size = 0; m_pDataSend_data = nullptr; m_nDataReceive_received = 0; m_nDataReceive_size = 0; m_pDataReceive_data = nullptr; externalServerIP = IPAddress((uint32_t) 0UL); //sockfd = -1; //connectStartTime = 0; //isConnecting = false; // Operation m_nMode = MODE_WAITING; m_bHelloSent = false; m_bSendHistoryPending = false; m_nLastReceivedTime = m_nLastHeartBeatSentTime = m_nLastUDPBroadcastTime = millis(); m_bClientConnected = false; //m_dwPublicIP = 0; wifiClient.stop(); if (isWiFiConnected()) { // UPnP Client // { // uint32_t ip = WiFi.gatewayIP(); // uint16_t port = m_nPublicPort; // //CUpnpClient upnp; // //if (upnp.registerUPnP(&ip, &port)) { // // status.nFlags |= FLAG_UPNP; // //} else { // status.nFlags &= ~FLAG_UPNP; // //} // if (ip != 0) // m_dwPublicIP = ip; // if (port != m_nPublicPort) { // config.m_nPublicPort = port; // config.save(); // m_nPublicPort = port; // } // } // Server wifiServer.begin(SERVER_PORT, 1); //wifiExternal.begin(m_nPublicPort, 1); m_bClientConnected = false; // UDP packetUDP.dwIPAddress = WiFi.localIP(); udpLocal.begin(UDP_PORT); udpExternal.begin(UDP_EXTERNAL_PORT); if (m_cExternalServerIPAddress == IPAddress((uint32_t) 0l)) { if (WiFi.hostByName("visionsoft.kr", m_cExternalServerIPAddress)) { DPRINTF("WiFi - ExternalServer IP resolved as \"%s\"\n", m_cExternalServerIPAddress.toString().c_str()); } else { m_cExternalServerIPAddress = IPAddress((uint32_t) 0); DPRINTF("WiFi - ExternalServer IP NOT resolved\n"); } } } } MY_IRAM_ATTR void CWiFiHost::Stop() { CloseConnection(); // Stop server wifiServer.stop(); //wifiExternal.stop(); m_bClientConnected = false; // Stop Client if (wifiClient) wifiClient.stop(); // Stop UDP udpLocal.stop(); // or udpLocal.end(); depending on your preference udpExternal.stop(); // or udpExternal.end(); depending on your preference } MY_IRAM_ATTR void CWiFiHost::CloseConnection() { if (wifiClient && wifiClient.connected()) wifiClient.stop(); m_bClientConnected = false; m_nMode = MODE_WAITING; } IRAM_ATTR void CWiFiHost::Loop(unsigned long clock) { if (!isWiFiConnected()) return; // --- State: WAITING (Accepting new clients) --- if (m_nMode == MODE_WAITING) { // If we think we are connected but the object is dead, reset if (m_bClientConnected) { wifiClient.stop(); m_bClientConnected = false; } // Try accepting from internal, then external if internal fails wifiClient = wifiServer.accept(); //if (!wifiClient) wifiClient = wifiExternal.accept(); if (wifiClient && wifiClient.connected()) { ESP_LOGI(TAG_WIFI_HOST, "Host: Connection Accepted"); wifiClient.setNoDelay(true); m_nLastReceivedTime = clock; m_bClientConnected = true; m_bHelloSent = false; m_nMode = MODE_PACKET; ledcWrite(PIN_LED_WIFI, PWM_FULL * 39 / 40); } return; } // --- Global Safety Check for all other modes --- // If we lose connection mid-process, jump back to WAITING immediately if (!wifiClient || !wifiClient.connected()) { m_bClientConnected = false; m_nMode = MODE_WAITING; ledcWrite(PIN_LED_WIFI, PWM_FULL / 10 ); return; } // --- Main State Machine --- switch (m_nMode) { case MODE_PACKET: CheckClient(clock); // Timeout Check (60 seconds) if (clock - m_nLastReceivedTime > 60000) { ESP_LOGW(TAG_WIFI_HOST, "Host: Timeout - Dropping Connection"); wifiClient.stop(); m_bClientConnected = false; m_nMode = MODE_WAITING; } // Heartbeat Pulse (Every 1 second) else if (clock - m_nLastHeartBeatSentTime >= 1000) { SendHeartBeat(); m_nLastHeartBeatSentTime = clock; } break; case MODE_SEND: // SendData returns true only when the CURRENT buffer is empty if (SendData(clock)) { // Check if there is a second part of the history ring buffer if (m_bSendHistoryPending && m_nPendingHistoryCount > 0) { ESP_LOGI(TAG_WIFI_HOST, "WiFi Host: Preparing History Part 2"); // Setup the next chunk SendData(history.getRingData2(), sizeof(STATUS_TYPE) * m_nPendingHistoryCount); // Clear flags so we don't loop here forever m_bSendHistoryPending = false; m_nPendingHistoryCount = 0; // We stay in MODE_SEND. The next Loop() turn will start sending Part 2. } else { // All data (including history parts) is done m_nMode = MODE_PACKET; } } break; case MODE_RECV: if (ReceiveData(clock)) { m_nMode = MODE_PACKET; } break; } } MY_IRAM_ATTR void CWiFiHost::SendHeartBeat(unsigned long clock) { if (!isWiFiConnected()) { //ESP_LOGI(TAG_WIFI_HOST,"WiFiHost - SendHeartBeat() called while not connected!"); return; } // Send Heartbeats to external server and to local devices if (clock - m_nLastUDPBroadcastTime > 1000) { static int count = 55; // UDP Heartbeat if (++count >= 60) { // External Heartbeat UDP_CONFIG_TYPE pktConfig; pktConfig.udp = packetUDP; pktConfig.udp.m_nPort = 3939; pktConfig.udp.dwIPAddress = (uint32_t)WiFi.localIP(); pktConfig.udp.status = status; if (((uint32_t)m_cExternalServerIPAddress) != (uint32_t)0l) udpExternal.beginPacket(m_cExternalServerIPAddress, (uint16_t)UDP_EXTERNAL_PORT); else udpExternal.beginPacket("visionsoft.kr", (uint16_t)UDP_EXTERNAL_PORT); if (config.bConfigSaved) { // Config is save locally. Save it on cloud config.bConfigSaved = false; pktConfig.udp.m_nMessage = MESSAGE_CONFIG_SAVE; pktConfig.con = config; udpExternal.write((uint8_t*)&pktConfig, sizeof(pktConfig)); ESP_LOGI(TAG_WIFI_HOST,"HeartBeat Packet *Config Save* sent out to external Server"); } else { // Send only UDP packet udpExternal.write((uint8_t*)&(pktConfig.udp), sizeof(UDP_PACKET)); } udpExternal.endPacket(); count = 0; } else if (!m_bClientConnected) { // Local AP broadcast packetUDP.m_nMessage = UDP_MESSAGE::MESSAGE_HEARTBEAT; packetUDP.dwIPAddress = WiFi.localIP(); packetUDP.m_nPort = SERVER_PORT; strcpy(packetUDP.m_sCompanyName, COMPANY_NAME); strcpy(packetUDP.m_sService, SERVICE_NAME); udpLocal.beginPacket((IPAddress)0xFFFFFFFF, (uint16_t)UDP_PORT); udpLocal.write((uint8_t*)&packetUDP, sizeof(UDP_PACKET)); udpLocal.endPacket(); } m_nLastUDPBroadcastTime = clock; } } MY_IRAM_ATTR void CWiFiHost::MonitorUDP() { // Listen for UDP External port IPAddress ip; int size = udpExternal.parsePacket(); if (size >= sizeof(packetUDP)) { if ((udpExternal.read((char *) &packetUDP, sizeof(packetUDP)) == sizeof(packetUDP)) && packetUDP.sig1 == SIGNATURE1 && packetUDP.sig2 == SIGNATURE2 && packetUDP.m_nChipID == config.m_nChipId) { switch (packetUDP.m_nMessage) { case MESSAGE_IP: // Extenal IP and Port set // if (packetUDP.m_nChipID == config.m_nChipId) { // m_dwPublicIP = packetUDP.dwIPAddress; // m_nPublicPort = packetUDP.m_nPort; // ip = IPAddress(m_dwPublicIP); // ESP_LOGI(TAG_WIFI_HOST,"External IP(%s) and Port(%d)\n", ip.toString().c_str(), m_nPublicPort); // } else { // ESP_LOGI(TAG_WIFI_HOST,"External Server Response for other device Received\n"); // } break; case MESSAGE_CONFIG_SEND: if (size == sizeof(UDP_PACKET) + sizeof(CONFIG_STRUCT)) { if (udpExternal.read((char*) &configCopy, sizeof(configCopy))) { ESP_LOGI(TAG_WIFI_HOST,"CONFIG received from the external DB server\n"); } } else { char *buffer[256]; while((size = udpExternal.parsePacket()) > 0) { // Discard any leftover data udpExternal.read((char*) &buffer, sizeof(buffer)); } } break; case MESSAGE_QUERY_IP: // if (m_nMode == MODE_WAITING) { // // Get sender's IP and port // externalServerIP = udpExternal.remoteIP(); // uint16_t senderPort = udpExternal.remotePort(); // ESP_LOGI(TAG_WIFI_HOST,"External Server - MESSAGE_QUERY_IP from %s:%d\n", externalServerIP.toString().c_str(), senderPort); // m_nMode = MODE_EXTERNAL_SERVER; // } break; case MESSAGE_RESET: Restart(); break; default: break; } } } } IRAM_ATTR void CWiFiHost::CheckClient(unsigned long clock) { // 1. Quick exit if no data is ready to be read int available = wifiClient.available(); if (available < sizeof(TCP_PACKET)) return; static TCP_PACKET cpkt; // 2. Peek or Read the packet // We use readBytes because we already verified 'available' >= size int count = wifiClient.readBytes((uint8_t*)&cpkt, sizeof(TCP_PACKET)); if (count == sizeof(TCP_PACKET)) { // 3. Validation Logic bool sigMatch = (cpkt.sig1 == SIGNATURE1 && cpkt.sig2 == SIGNATURE2); bool lenMatch = (cpkt.len == sizeof(TCP_PACKET)); if (sigMatch && lenMatch) { ProcessPacket(cpkt); // Cleanly dispatched to sub-handlers now m_nLastReceivedTime = clock; } else { // 4. Recovery Logic: Instead of a blocking while-loop, // clear the socket buffer and wait for the next loop cycle. ESP_LOGW(TAG_WIFI_HOST, "Protocol out of sync. Flushing %d bytes", available); while(wifiClient.available() > 0) { wifiClient.read(); // Efficiently dump the garbage } } } } IRAM_ATTR void CWiFiHost::ProcessPacket(TCP_PACKET& pkt) { switch (pkt.cmd) { // System case CMD_HEARTBEAT: m_nLastReceivedTime = millis(); //ESP_LOGI(TAG_WIFI_HOST,"H"); break; case CMD_HELLO: case CMD_HELLO_DEBUG: { // Send the Config Data to PC // Send Packet Back ESP_LOGI(TAG_WIFI_HOST,"WiFi - HELLO received"); pkt.u16[0] = SIGNATURE1; pkt.n16[1] = sizeof(CONFIG_TYPE); pkt.u16[2] = SIGNATURE2; config.m_nChipId; SendPacket(pkt); // Send Data Packets ESP_LOGI(TAG_WIFI_HOST,"WiFi - Config Send pending..."); int sent = SendData((uint8_t*)&config, sizeof(CONFIG_TYPE)); m_bHelloSent = true; } break; case CMD_DROP_CONNECTION: wifiClient.stop(); m_bClientConnected = false; m_nMode = MODE_WAITING; ESP_LOGI(TAG_WIFI_HOST,"WiFI - Client requets to DROP CONNECTION"); break; case CMD_RESET_REASON: pkt.n16[0] = esp_reset_reason(); SendPacket(pkt); break; case CMD_SAVE_RESTART: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { yield(); Restart(); } break; case CMD_RESET_RESTART: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { pkt.cmd = CMD_DROP_CONNECTION; SendPacket(pkt); yield(); Restart(); } break; case CMD_SEND_HISTORY: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { int16_t count = history.getRingCount(); if (count > 0 ) { // inform client the count of history pkt.op = count; SendPacket(pkt); int16_t size = history.getRingSize(); if (count < size) { ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData - Whold part of History (%d)\n", count); SendData(history.getRingData1()/* &ring[tail] */, sizeof(STATUS_TYPE) * count); } else { int count1st = size - history.getRingTail(); ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData - 1st part of History Total(%d), 1st(%d) H(%d) T(%d)\n", count, count1st, history.getRingHead(), history.getRingTail()); SendData(history.getRingData1(), sizeof(STATUS_TYPE) * count1st), // Mark pending to send the second part: from the start to head-1 //SendData(history.getRingData2() /* &ring[0] */, sizeof(STATUS_TYPE) * head); m_bSendHistoryPending = true; m_nPendingHistoryCount = history.getRingHead(); } } } break; case CMD_RESET_SENSOR: aht25.setScanFlag(true); aht10_0x39.setScanFlag(true); break; // Config case CMD_INIT_CONFIG: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { config.init(); config.save(); } break; case CMD_LOAD_CONFIG: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { config.load(); history.loadPID(); } break; case CMD_SAVE_CONFIG: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { config.save(); } break; case CMD_RECV_CONFIG: // Receive Confif Data from PC if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { ReceiveData((uint8_t *)&configCopy, sizeof(CONFIG_TYPE)); m_bReceiveConfigPending = true; ESP_LOGI(TAG_WIFI_HOST,"WiFi - Receive Config initiated..."); } break; case CMD_SEND_CONFIG: if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { SendPacket(pkt); SendData((const uint8_t *)&config, (unsigned int) sizeof(config)); ESP_LOGI(TAG_WIFI_HOST,"WiFi - Send Config initiated..."); } break; // PID case CMD_INIT_PID_PARAM: history.savePID(); break; case CMD_LOAD_PID_PARAM: history.loadPID(); break; case CMD_SAVE_PID_PARAM: history.savePID(); break; case CMD_SET_PID: config.Kp_Temp1 = pkt.f[0]; config.Kd_Temp1 = pkt.f[1]; config.LR_Temp1 = pkt.f[2]; config.Kp_Humidity = pkt.f[3]; config.Kd_Humidity = pkt.f[4]; config.LR_Humidity = pkt.f[5]; history.loadPID(); break; case CMD_GET_PID: pkt.f[0] = config.Kp_Temp1; pkt.f[1] = config.Kd_Temp1; pkt.f[2] = config.LR_Temp1; pkt.f[3] = config.Kp_Humidity; pkt.f[4] = config.Kd_Humidity; pkt.f[5] = config.LR_Humidity; SendPacket(pkt); break; // Control case CMD_SET_CONTROL: config.bSmartControl = pkt.by[0] ? true : false; config.bNightControl = pkt.by[1] ? true : false; config.bControlTemperature = pkt.by[2] ? true : false; config.bControlHumidity = pkt.by[3] ? true : false; break; case CMD_GET_CONTROL: pkt.by[0] = config.bSmartControl ? 0xFF : 0; pkt.by[1] = config.bNightControl ? 0xFF : 0; pkt.by[2] = config.bControlTemperature ? 0xFF : 0; pkt.by[3] = config.bControlHumidity ? 0xFF : 0; SendPacket(pkt); break; // Operation case CMD_SET_TEMP_TARGET: config.nTempTarget = pkt.u16[0]; ESP_LOGI(TAG_WIFI_HOST,"WiFi - TempTarget changed to: %d\n", pkt.u16[0]); break; case CMD_SET_TEMP_TARGET_NIGHT: config.nTempTargetNight = pkt.u16[0]; ESP_LOGI(TAG_WIFI_HOST,"WiFi - TempTargetNight changed to: %d\n", pkt.u16[0]); break; case CMD_SET_HUMID_TARGET: config.nHumidTarget = pkt.u16[0]; ESP_LOGI(TAG_WIFI_HOST,"WiFi - HumidTarget changed to: %d\n", pkt.u16[0]); break; case CMD_SET_SENSOR_OFFSET: config.nTemp1Offset = pkt.n16[0]; config.nHumid1Offset = pkt.n16[1]; if (pkt.n16[2] > 1) { config.nTemp2Offset = pkt.n16[2]; config.nHumid2Offset = pkt.n16[3]; if (pkt.n16[2] > 2) config.nTemp3Offset = pkt.n16[4]; } ESP_LOGI(TAG_WIFI_HOST,"WiFi - SensorOffset changed to: %d, %d\n", pkt.n16[0], pkt.n16[1]); break; case CMD_SET_AC1_PARAM: config.ac1 = pkt.device; break; case CMD_SET_AC2_PARAM: config.ac2 = pkt.device; break; case CMD_SET_MIST_PARAM: config.mist = pkt.device; break; case CMD_SET_FAN_PARAM: config.fan = pkt.device; break; case CMD_SET_MOTOR_PARAM: config.motor = pkt.device; break; case CMD_SET_LIGHT_PARAM: config.light = pkt.device; break; // Status case CMD_SET_HEATER1_DUTY: status.nHeater1Duty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_HEATER1; else status.nFlags &= ~FLAG_MANUAL_HEATER1; if (status.nHeater1Duty == 0) { setHeater1Duty(0); } break; case CMD_SET_HEATER2_DUTY: status.nHeater2Duty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_HEATER2; else status.nFlags &= ~FLAG_MANUAL_HEATER2; if (status.nHeater2Duty == 0) { setHeater2Duty(0); } break; case CMD_SET_MIST_DUTY: status.nMistDuty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_MIST; else status.nFlags &= ~FLAG_MANUAL_MIST; break; case CMD_SET_FAN_DUTY: status.nFanDuty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_FAN; else status.nFlags &= ~FLAG_MANUAL_FAN; break; case CMD_SET_MOTOR_DUTY: status.nMotorDuty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_MOTOR; else status.nFlags &= ~FLAG_MANUAL_MOTOR; break; case CMD_SET_LIGHT_DUTY: status.nLightTargetDuty = pkt.u16[0]; if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_LIGHT; else status.nFlags &= ~FLAG_MANUAL_LIGHT; break; // Manual Operation case CMD_SET_MANUAL_HEATER1: if (pkt.u16[0]) status.nFlags |= FLAG_MANUAL_HEATER1; else status.nFlags &= ~FLAG_MANUAL_HEATER1; break; case CMD_SET_MANUAL_HEATER2: if (pkt.u16[0]) status.nFlags |= FLAG_MANUAL_HEATER2; else status.nFlags &= ~FLAG_MANUAL_HEATER2; break; case CMD_SET_MANUAL_MIST: if (pkt.u16[0]) status.nFlags |= FLAG_MANUAL_MIST; else status.nFlags &= ~FLAG_MANUAL_MIST; break; case CMD_SET_MANUAL_FAN: if (pkt.u16[0]) status.nFlags |= FLAG_MANUAL_FAN; else status.nFlags &= ~FLAG_MANUAL_FAN; break; case CMD_SET_MANUAL_LIGHT: if (pkt.u16[0]) status.nFlags |= FLAG_MANUAL_LIGHT; else status.nFlags &= ~FLAG_MANUAL_LIGHT; break; // Time case CMD_SET_TIME_NIGHT: config.nNightStartHour = pkt.u16[0]; config.nNightStartMin = pkt.u16[1]; config.nNightEndHour = pkt.u16[2]; config.nNightEndMin = pkt.u16[3]; break; case CMD_SET_WIFI_CLIENT_DISPLAY: config.m_nDisplayTempHigh = pkt.n16[0]; config.m_nDisplayTempLow = pkt.n16[1]; config.m_nDisplayTime = pkt.n16[2]; config.m_fShowRealTime = pkt.n16[3]; config.m_fShowHistory = pkt.n16[4]; ESP_LOGI(TAG_WIFI_HOST,"WiFi - Client Display Settings changed."); break; default: ESP_LOGI(TAG_WIFI_HOST,"WiFi - Packet Received Type: %d\n", pkt.cmd); break; } } IRAM_ATTR int CWiFiHost::SendPacket(TCP_PACKET& pkt) { size_t sent = 0; if (m_bClientConnected && wifiClient && wifiClient.connected()) { sent = wifiClient.write((char*)&pkt, sizeof(TCP_PACKET)); } return sent; } IRAM_ATTR size_t CWiFiHost::SendData(const uint8_t* data, size_t size) { if (data != nullptr) { m_nMode = MODE_SEND; m_pDataSend_data = (char *) data; m_nDataSend_size = size; m_nDataSend_sent = 0; ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData(size: %d)\n", size); return size; } return 0; } IRAM_ATTR // This function sends a small "chunk" then returns false. // It returns true ONLY when the entire buffer is finished. bool CWiFiHost::SendData(unsigned long clock) { if (!m_pDataSend_data || m_nDataSend_size == 0) return true; // Calculate how much is left size_t remaining = m_nDataSend_size - m_nDataSend_sent; // Send a "Chunk" (e.g., 512 bytes). // Sending too much at once blocks the CPU. // Sending too little makes the WiFi overhead too high. size_t chunkSize = (remaining > 512) ? 512 : remaining; size_t written = wifiClient.write((const uint8_t*)(m_pDataSend_data + m_nDataSend_sent), chunkSize); if (written > 0) { m_nDataSend_sent += written; } // If we aren't done, return false to stay in MODE_SEND for the next Loop() if (m_nDataSend_sent < m_nDataSend_size) { return false; } // Done! Reset pointers m_pDataSend_data = nullptr; m_nDataSend_size = 0; m_nDataSend_sent = 0; return true; } IRAM_ATTR size_t CWiFiHost::ReceiveData(uint8_t* data, size_t size) { m_nMode = MODE_RECV; m_pDataReceive_data = (char *) data; m_nDataReceive_size = size; m_nDataReceive_received = 0; #ifdef ESP8266 digitalWrite(PIN_EXTRA, LED_ON); #endif return size; } IRAM_ATTR bool CWiFiHost::ReceiveData(unsigned long clock) { // Receive Data size_t nSize = 0; if (m_nDataReceive_received < m_nDataReceive_size) { if (m_bClientConnected && wifiClient && wifiClient.connected()) { int16_t count = m_nDataReceive_size - m_nDataReceive_received; if (count > TCP_PACKET_SIZE_MAX) count = TCP_PACKET_SIZE_MAX; nSize = wifiClient.readBytes(&m_pDataReceive_data[m_nDataReceive_received], count); if (nSize > 0) { m_nLastReceivedTime = clock; m_nDataReceive_received += nSize; } } else { m_nMode = MODE_WAITING; m_pDataReceive_data = nullptr; m_nDataReceive_size = 0; m_nDataReceive_received = 0; ESP_LOGI(TAG_WIFI_HOST," SendData: Connection lost - reset receiveData()!"); return true; } } // Check for any pending action if (m_nDataReceive_received == m_nDataReceive_size) { if (m_bReceiveConfigPending && m_pDataReceive_data == (char *)&configCopy) { config = configCopy; history.loadPID(); ESP_LOGI(TAG_WIFI_HOST,"WiFi - Config Received"); m_bReceiveConfigPending = false; } ESP_LOGI(TAG_WIFI_HOST," ReceiveData: Data Receive Completed!"); return true; } if (nSize <= 0 && clock - m_nLastReceivedTime > 5000) { ESP_LOGI(TAG_WIFI_HOST," ReceiveData: TimeOut Abort!"); return true; } return false; } IRAM_ATTR void CWiFiHost::SendHeartBeat() { if (m_bHelloSent) { hostPacket.cmd = CMD_HEARTBEAT; time_t now = time(NULL); // Get current time in seconds status.now = (uint32_t) time(NULL); //status.uptime = now - timeManager.getFirstNTPTime(); hostPacket.status = status; SendPacket(hostPacket); } } MY_IRAM_ATTR void CWiFiHost::Restart() { if (isWiFiConnected()) { if (m_bClientConnected && m_bClientConnected && wifiClient && wifiClient.connected()) { hostPacket.cmd = CMD_DROP_CONNECTION; SendPacket(hostPacket); } } vTaskDelay(500/portTICK_PERIOD_MS); // stop all network sockets Stop(); // Stop Sockets vTaskDelay(50/portTICK_PERIOD_MS); // Turn Off setHeater1Duty(0); setHeater2Duty(0); ledcWrite(PIN_MIST, 0); ledcWrite(PIN_FAN, 0); ledcWrite(PIN_MOTOR, 0); ledcWrite(PIN_LIGHT, 0); vTaskDelay(50/portTICK_PERIOD_MS); config.statusSave = status; config.save(); vTaskDelay(50/portTICK_PERIOD_MS); ESP.restart(); }