HCesp/WiFiHost.cpp
2026-04-19 16:50:40 +09:00

863 lines
29 KiB
C++

#include <lwip/sockets.h>
#undef INADDR_NONE
#include <lwip/netdb.h>
#include <WiFiServer.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <esp_task_wdt.h>
#include <netinet/in.h> // For struct in_addr
#include <esp_task_wdt.h>
#include <esp_system.h>
#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;
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();
}