866 lines
29 KiB
C++
866 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 - 10);
|
|
}
|
|
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 - 2);
|
|
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 = g_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();
|
|
}
|