ESPMegaPRO-v3-SDK/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/InternalDisplay.cpp

923 lines
30 KiB
C++
Raw Normal View History

2023-12-29 13:04:25 +00:00
#include <InternalDisplay.hpp>
2024-01-01 05:56:52 +00:00
/**
* @brief Initialize the Internal Display
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @note You should not call this function directly, instead use ESPMegaIoT::enableInternalDisplay()
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param iot The ESPMegaIoT object
* @param getRtcTime A function that returns the current time
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::begin(ESPMegaIoT *iot, std::function<rtctime_t()> getRtcTime)
{
2023-12-29 17:49:09 +00:00
this->iot = iot;
this->getRtcTime = getRtcTime;
this->mqttConfig = this->iot->getMqttConfig();
this->networkConfig = this->iot->getNetworkConfig();
// Register callbacks
2023-12-30 15:50:19 +00:00
auto bindedPageChangeCallback = std::bind(&InternalDisplay::handlePageChange, this, std::placeholders::_1);
this->registerPageChangeCallback(bindedPageChangeCallback);
auto bindedTouchCallback = std::bind(&InternalDisplay::handleTouch, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
this->registerTouchCallback(bindedTouchCallback);
2023-12-30 11:27:39 +00:00
// Initialize the display
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 11:27:39 +00:00
this->displayAdapter->begin(115200);
this->displayAdapter->setTimeout(100);
this->displayAdapter->flush();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 11:27:39 +00:00
this->reset();
delay(500);
this->jumpToPage(1);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief The main loop of the Internal Display
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @note You should not call this function directly, instead use ESPMega::loop()
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::loop()
{
2023-12-29 17:49:09 +00:00
// Keep reading the Serial Adapter
this->recieveSerialCommand();
2023-12-30 15:50:19 +00:00
2023-12-29 17:49:09 +00:00
// Refresh the top bar every 5 seconds
static uint32_t lastTopBarRefresh;
2023-12-31 06:41:48 +00:00
if (millis() - lastTopBarRefresh > INTERNAL_DISPLAY_TOP_BAR_REFRESH_INTERVAL)
{
2023-12-29 17:49:09 +00:00
this->updateStatusIcons(this->iot->networkConnected(), this->iot->mqttConnected());
lastTopBarRefresh = millis();
2023-12-29 13:04:25 +00:00
}
2023-12-29 17:49:09 +00:00
// Refresh the clock every 10 seconds
static uint32_t lastClockRefresh;
2023-12-31 06:41:48 +00:00
if (millis() - lastClockRefresh > INTERNAL_DISPLAY_CLOCK_REFRESH_INTERVAL)
{
2023-12-29 17:49:09 +00:00
this->updateClock();
lastClockRefresh = millis();
2023-12-29 13:04:25 +00:00
}
}
2024-01-01 05:56:52 +00:00
/**
* @brief Update the display in response to a change in the input state
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param pin The pin that changed
* @param state The new state of the pin
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handleInputStateChange(uint8_t pin, bool state)
{
2023-12-29 13:04:25 +00:00
// If the input card is binded to the display and the current page is the input page
// then update the respective input component
2024-01-11 15:36:16 +00:00
if (this->inputCard == nullptr || this->currentPage != INTERNAL_DISPLAY_INPUT_PAGE)
2023-12-31 06:41:48 +00:00
return;
2023-12-29 16:43:12 +00:00
// Update the input state
this->setInputMarker(pin, state);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Update the display in response to a change in the PWM state
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param pin The pin that changed
* @param state The new state of the pin
* @param value The new value of the pin
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handlePwmStateChange(uint8_t pin, bool state, uint16_t value)
{
2023-12-29 13:04:25 +00:00
// If the output card is binded to the display and the current page is the output page
// then update the respective output component
2024-01-11 15:35:52 +00:00
if (this->outputCard == nullptr)
2023-12-31 06:41:48 +00:00
return;
2024-01-15 09:44:36 +00:00
if (this->currentPage == INTERNAL_DISPLAY_OUTPUT_PAGE)
{
// Update the output state
this->setOutputBar(pin, value);
this->setOutputStateColor(pin, state);
2024-01-11 15:26:57 +00:00
}
2023-12-30 17:37:50 +00:00
// Refresh the PWM Adjustment page if the current page is the PWM Adjustment page and the pin is the same
2024-01-11 15:26:57 +00:00
else if (this->currentPage == INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE && this->pmwAdjustmentPin == pin)
2023-12-31 06:41:48 +00:00
{
2023-12-30 17:37:50 +00:00
this->refreshPWMAdjustment();
}
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Update the display in response to page change
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param page The new page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handlePageChange(uint8_t page)
{
2023-12-29 16:43:12 +00:00
// Refresh the page
this->refreshPage(page);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Save the network config to the FRAM
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::saveNetworkConfig()
{
2023-12-31 08:53:39 +00:00
// The network config page have the following components:
// ip_set -> a text input to set the ip address
// netmask_set -> a text input to set the netmask
// gateway_set -> a text input to set the gateway
// dns_set -> a text input to set the dns
// host_set -> a text input to set the hostname
// Save the ip address
IPAddress ip;
// 000.000.000.000, 16 characters, 3 dots, 3 characters per octet, 1 null terminator
char ip_buffer[30];
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("ip_set.txt", ip_buffer, 30))
2023-12-31 08:53:39 +00:00
{
return;
}
2023-12-31 08:53:39 +00:00
// Validate the ip address
2024-01-15 09:44:36 +00:00
if (!ip.fromString(ip_buffer))
{
2023-12-31 08:53:39 +00:00
return;
}
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the netmask
IPAddress netmask;
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("netmask_set.txt", ip_buffer, 30))
{
2023-12-31 08:53:39 +00:00
return;
}
// Validate the netmask
2024-01-15 09:44:36 +00:00
if (!netmask.fromString(ip_buffer))
{
2023-12-31 08:53:39 +00:00
return;
}
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the gateway
IPAddress gateway;
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("gateway_set.txt", ip_buffer, 30))
{
2023-12-31 08:53:39 +00:00
return;
}
// Validate the gateway
2024-01-15 09:44:36 +00:00
if (!gateway.fromString(ip_buffer))
{
2023-12-31 08:53:39 +00:00
return;
}
// Save the dns
IPAddress dns;
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("dns_set.txt", ip_buffer, 30))
2023-12-31 08:53:39 +00:00
return;
// Validate the dns
if (!dns.fromString(ip_buffer))
return;
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the hostname
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("host_set.txt", this->networkConfig->hostname, 32))
2023-12-31 08:53:39 +00:00
return;
// Write the ip address, netmask and gateway to the network config
this->networkConfig->ip = ip;
this->networkConfig->subnet = netmask;
this->networkConfig->gateway = gateway;
this->networkConfig->dns1 = dns;
this->networkConfig->dns2 = dns;
this->networkConfig->useStaticIp = true;
this->networkConfig->useWifi = false;
this->networkConfig->wifiUseAuth = false;
this->iot->saveNetworkConfig();
ESP.restart();
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Save the MQTT config to the FRAM
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::saveMQTTConfig()
{
2023-12-31 08:53:39 +00:00
// The MQTT config page have the following components:
// mqttsv_set -> a text input to set the mqtt server
// port_set -> a text input to set the mqtt port
// use_auth -> a checkbox to enable/disable mqtt authentication
// user_set -> a text input to set the mqtt username
// password_set -> a text input to set the mqtt password
// topic_set -> a text input to set the mqtt base topic
2024-01-15 09:44:36 +00:00
2023-12-31 10:55:13 +00:00
// Send the stop bytes to flush the serial buffer
this->sendStopBytes();
2023-12-31 08:53:39 +00:00
// Save the mqtt server
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("mqttsv_set.txt", this->mqttConfig->mqtt_server, 16))
2023-12-31 08:53:39 +00:00
return;
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the mqtt port
this->mqttConfig->mqtt_port = this->getNumber("port_set.val");
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the mqtt username
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("user_set.txt", this->mqttConfig->mqtt_user, 16))
2023-12-31 08:53:39 +00:00
return;
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the mqtt password
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("password_set.txt", this->mqttConfig->mqtt_password, 16))
2023-12-31 08:53:39 +00:00
return;
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the mqtt base topic
2024-01-15 09:44:36 +00:00
if (!this->getStringToBuffer("topic_set.txt", this->mqttConfig->base_topic, 16))
2023-12-31 08:53:39 +00:00
return;
2024-01-15 09:44:36 +00:00
2023-12-31 08:53:39 +00:00
// Save the mqtt use auth
2023-12-31 10:55:13 +00:00
uint8_t use_auth = this->getNumber("use_auth.val");
2024-01-15 09:44:36 +00:00
this->mqttConfig->mqtt_useauth = use_auth == 1 ? true : false;
2023-12-31 08:53:39 +00:00
this->iot->saveMqttConfig();
ESP.restart();
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Update the status icons on the Internal Display's top bar
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param networkStatus The network status
* @param mqttStatus The MQTT status
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::updateStatusIcons(bool networkStatus, bool mqttStatus)
{
2023-12-29 16:43:12 +00:00
this->setNumber("server.pic", mqttStatus ? PIC_MQTT_CONNECTED : PIC_MQTT_DISCONNECTED);
this->setNumber("lan.pic", networkStatus ? PIC_LAN_CONNECTED : PIC_LAN_DISCONNECTED);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Update the clock on the Internal Display's top bar
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::updateClock()
{
2023-12-29 16:43:12 +00:00
rtctime_t time = this->getRtcTime();
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-31 06:41:48 +00:00
this->displayAdapter->printf("time.txt=\"%02d:%02d %s\"", time.hours % 12, time.minutes, time.hours / 12 ? "PM" : "AM");
2023-12-29 16:43:12 +00:00
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the current page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPage()
{
2023-12-29 16:43:12 +00:00
this->refreshPage(this->currentPage);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the specified page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @note The current page must be the specified page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param page The page to refresh
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPage(uint8_t page)
{
switch (page)
{
case INTERNAL_DISPLAY_DASHBOARD_PAGE:
this->refreshDashboard();
break;
case INTERNAL_DISPLAY_INPUT_PAGE:
2023-12-31 08:53:39 +00:00
if (this->inputCard == nullptr)
{
this->jumpToPage(INTERNAL_DISPLAY_INPUT_NULL_PTR_PAGE);
break;
}
2023-12-31 06:41:48 +00:00
this->refreshInput();
break;
case INTERNAL_DISPLAY_OUTPUT_PAGE:
2023-12-31 08:53:39 +00:00
if (this->outputCard == nullptr)
{
this->jumpToPage(INTERNAL_DISPLAY_OUTPUT_NULL_PTR_PAGE);
break;
}
2023-12-31 06:41:48 +00:00
this->refreshOutput();
break;
case INTERNAL_DISPLAY_AC_PAGE:
if (this->climateCard == nullptr)
{
this->jumpToPage(INTERNAL_DISPLAY_CLIMATE_NULL_PTR_PAGE);
2023-12-30 15:50:19 +00:00
break;
2023-12-31 06:41:48 +00:00
}
this->refreshAC();
break;
case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE:
this->refreshPWMAdjustment();
break;
case INTERNAL_DISPLAY_NETWORK_CONFIG_PAGE:
this->refreshNetworkConfig();
break;
case INTERNAL_DISPLAY_MQTT_CONFIG_PAGE:
this->refreshMQTTConfig();
break;
default:
break;
2023-12-29 16:43:12 +00:00
}
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the dashboard page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshDashboard()
{
2023-12-29 16:43:12 +00:00
// The dashboard have the following components:
// 1. Hostname
// 2. IP Address
// 3. MQTT Server with port
// 4. MQTT Connection status
2023-12-29 17:49:09 +00:00
this->setString("hostname.txt", this->networkConfig->hostname);
// Construct the IP address string
static char ip_address[25];
sprintf(ip_address, "%d.%d.%d.%d", this->networkConfig->ip[0], this->networkConfig->ip[1], this->networkConfig->ip[2], this->networkConfig->ip[3]);
this->setString("ip_address.txt", ip_address);
// Send the MQTT server and port
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 15:50:19 +00:00
this->displayAdapter->print("server_address.txt=\"");
2023-12-29 17:49:09 +00:00
this->displayAdapter->print(this->mqttConfig->mqtt_server);
2023-12-30 15:50:19 +00:00
this->displayAdapter->print("\"");
2023-12-29 17:49:09 +00:00
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 17:49:09 +00:00
// Send the MQTT connection status
this->setString("status_txt.txt", this->iot->mqttConnected() ? MSG_MQTT_CONNECTED : MSG_MQTT_DISCONNECTED);
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the input page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshInput()
{
for (uint8_t i = 0; i < 16; i++)
{
2023-12-30 15:50:19 +00:00
this->setInputMarker(i, this->inputCard->digitalRead(i, false));
2023-12-29 17:49:09 +00:00
}
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the output page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshOutput()
{
for (uint8_t i = 0; i < 16; i++)
{
2023-12-29 17:49:09 +00:00
this->setOutputBar(i, this->outputCard->getValue(i));
this->setOutputStateColor(i, this->outputCard->getState(i));
}
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the AC page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshAC()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 17:25:07 +00:00
this->displayAdapter->print("temp.txt=\"");
this->displayAdapter->print(this->climateCard->getTemperature());
2023-12-30 17:37:50 +00:00
this->displayAdapter->print("C\"");
2023-12-30 17:25:07 +00:00
this->sendStopBytes();
this->displayAdapter->print("fan_auto.pic=");
this->displayAdapter->print(this->climateCard->getFanSpeed() == AC_FAN_SPEED_AUTO ? PIC_AC_FAN_SPEED_AUTO_ACTIVE : PIC_AC_FAN_SPEED_AUTO_INACTIVE);
this->sendStopBytes();
this->displayAdapter->print("fan_low.pic=");
this->displayAdapter->print(this->climateCard->getFanSpeed() == AC_FAN_SPEED_LOW ? PIC_AC_FAN_SPEED_LOW_ACTIVE : PIC_AC_FAN_SPEED_LOW_INACTIVE);
this->sendStopBytes();
2023-12-30 17:37:50 +00:00
this->displayAdapter->print("fan_mid.pic=");
2023-12-30 17:25:07 +00:00
this->displayAdapter->print(this->climateCard->getFanSpeed() == AC_FAN_SPEED_MEDIUM ? PIC_AC_FAN_SPEED_MEDIUM_ACTIVE : PIC_AC_FAN_SPEED_MEDIUM_INACTIVE);
this->sendStopBytes();
this->displayAdapter->print("fan_high.pic=");
this->displayAdapter->print(this->climateCard->getFanSpeed() == AC_FAN_SPEED_HIGH ? PIC_AC_FAN_SPEED_HIGH_ACTIVE : PIC_AC_FAN_SPEED_HIGH_INACTIVE);
this->sendStopBytes();
this->displayAdapter->print("mode_off.pic=");
this->displayAdapter->print(this->climateCard->getMode() == AC_MODE_OFF ? PIC_AC_MODE_OFF_ACTIVE : PIC_AC_MODE_OFF_INACTIVE);
this->sendStopBytes();
this->displayAdapter->print("mode_fan.pic=");
this->displayAdapter->print(this->climateCard->getMode() == AC_MODE_FAN_ONLY ? PIC_AC_MODE_FAN_ACTIVE : PIC_AC_MODE_FAN_INACTIVE);
this->sendStopBytes();
this->displayAdapter->print("mode_cool.pic=");
this->displayAdapter->print(this->climateCard->getMode() == AC_MODE_COOL ? PIC_AC_MODE_COOL_ACTIVE : PIC_AC_MODE_COOL_INACTIVE);
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-31 06:41:48 +00:00
if (this->climateCard->getSensorType() == AC_SENSOR_TYPE_DHT22)
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 17:25:07 +00:00
this->displayAdapter->print("roomtemp.txt=\"");
this->displayAdapter->print(this->climateCard->getRoomTemperature());
this->displayAdapter->print("C\"");
this->sendStopBytes();
this->displayAdapter->print("roomhumid.txt=\"");
this->displayAdapter->print(this->climateCard->getHumidity());
this->displayAdapter->print("%\"");
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 17:25:07 +00:00
}
2023-12-31 06:41:48 +00:00
else if (this->climateCard->getSensorType() == AC_SENSOR_TYPE_DS18B20)
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 17:25:07 +00:00
this->displayAdapter->print("roomtemp.txt=\"");
this->displayAdapter->print(this->climateCard->getRoomTemperature());
this->displayAdapter->print("C\"");
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 17:25:07 +00:00
this->setString("roomhumid.txt", "N/A");
}
2023-12-31 06:41:48 +00:00
else
{
2023-12-30 17:25:07 +00:00
this->setString("roomtemp.txt", "N/A");
this->setString("roomhumid.txt", "N/A");
}
2023-12-29 13:04:25 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set the PWM status output bar value (Fullness of the bar)
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param pin The pin of the PWM
* @param value The value of the PWM (0 - 4095)
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::setOutputBar(uint8_t pin, uint16_t value)
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-29 17:49:09 +00:00
// Write the value to the output bar
this->displayAdapter->print("j");
this->displayAdapter->print(pin);
this->displayAdapter->print(".val=");
2023-12-31 06:41:48 +00:00
this->displayAdapter->print((int)(value * 100 / 4095));
2023-12-29 17:49:09 +00:00
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 17:49:09 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set the PWM status output bar color to match the PWM state
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param pin The pin of the PWM
* @param state The state of the PWM
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::setOutputStateColor(uint8_t pin, bool state)
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-29 17:49:09 +00:00
this->displayAdapter->print("j");
this->displayAdapter->print(pin);
this->displayAdapter->print(".ppic=");
this->displayAdapter->print(state ? PIC_PWM_BAR_ON : PIC_PWM_BAR_OFF);
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 14:41:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set Input Marker to match the input state
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param pin The pin of the input
* @param state The state of the input
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::setInputMarker(uint8_t pin, bool state)
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-29 17:49:09 +00:00
this->displayAdapter->print("I");
this->displayAdapter->print(pin);
this->displayAdapter->print(".val=");
this->displayAdapter->print(state ? 1 : 0);
2023-12-29 17:49:09 +00:00
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 14:41:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Create a new Internal Display object
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param displayAdapter The HardwareSerial object that is connected to the display
*/
2024-01-16 15:08:13 +00:00
InternalDisplay::InternalDisplay(HardwareSerial *displayAdapter) : ESPMegaDisplay(displayAdapter, 115200, 921600, 1, 3)
2023-12-31 06:41:48 +00:00
{
2023-12-29 14:41:19 +00:00
this->currentPage = INTERNAL_DISPLAY_DASHBOARD_PAGE;
2023-12-30 15:50:19 +00:00
this->iot = nullptr;
this->inputCard = nullptr;
this->outputCard = nullptr;
this->climateCard = nullptr;
this->pmwAdjustmentPin = 0;
2023-12-30 11:27:39 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set the input card to be be shown on the input page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param inputCard The input card object to be shown
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::bindInputCard(DigitalInputCard *inputCard)
{
// Check if the input card is already binded
// If it is, then unbind it first
if (this->inputCard != nullptr)
this->unbindInputCard();
2023-12-30 11:27:39 +00:00
this->inputCard = inputCard;
2023-12-31 06:41:48 +00:00
auto bindedInputStateChangeCallback =
std::bind(&InternalDisplay::handleInputStateChange, this,
std::placeholders::_1, std::placeholders::_2);
this->bindedInputCardCallbackHandler =
this->inputCard->registerCallback(bindedInputStateChangeCallback);
}
2024-01-01 05:56:52 +00:00
/**
* @brief Unbind the input card from the display
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::unbindInputCard()
{
if (this->inputCard == nullptr)
return;
this->inputCard->unregisterCallback(this->bindedInputCardCallbackHandler);
this->inputCard = nullptr;
2023-12-30 11:27:39 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set the output card to be be shown on the output page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param outputCard The output card object to be shown
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::bindOutputCard(DigitalOutputCard *outputCard)
{
// Check if the output card is already binded
// If it is, then unbind it first
if (this->outputCard != nullptr)
this->unbindOutputCard();
2023-12-30 11:27:39 +00:00
this->outputCard = outputCard;
2023-12-31 06:41:48 +00:00
auto bindedPwmStateChangeCallback = std::bind(&InternalDisplay::handlePwmStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
this->bindedOutputCardCallbackHandler =
this->outputCard->registerChangeCallback(bindedPwmStateChangeCallback);
}
2024-01-01 05:56:52 +00:00
/**
* @brief Unbind the output card from the display
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::unbindOutputCard()
{
if (this->outputCard == nullptr)
return;
this->outputCard->unregisterChangeCallback(this->bindedOutputCardCallbackHandler);
this->outputCard = nullptr;
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Set the climate card to be be shown on the AC page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* This assume that your ClimeateCard has the mode and fan speed names in the following order:
* mode: [off, fan_only, cool]
* fan_speed: [auto, low, medium, high]
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param climateCard The climate card object to be shown
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::bindClimateCard(ClimateCard *climateCard)
2024-01-15 09:44:36 +00:00
{
2023-12-31 06:41:48 +00:00
// Check if the climate card is already binded
// If it is, then unbind it first
if (this->climateCard != nullptr)
this->unbindClimateCard();
2023-12-30 15:50:19 +00:00
this->climateCard = climateCard;
2023-12-30 19:18:57 +00:00
auto bindedACStateChangeCallback = std::bind(&InternalDisplay::handleACStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
2023-12-31 06:41:48 +00:00
this->bindedClimateCardCallbackHandler =
this->climateCard->registerChangeCallback(bindedACStateChangeCallback);
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Unbind the climate card from the display
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::unbindClimateCard()
{
if (this->climateCard == nullptr)
return;
this->climateCard->unregisterChangeCallback(this->bindedClimateCardCallbackHandler);
this->climateCard = nullptr;
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the PWM Adjustment page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPWMAdjustment()
{
2023-12-30 15:50:19 +00:00
// The PWM Adjustment page have the following components:
// pwm_value -> a slider to adjust the PWM value
// pwm_state -> a button to toggle the PWM state
// pwm_id -> a text to show the PWM pin
// Refresh the PWM pin
this->refreshPWMAdjustmentId();
// Refresh the PWM value
this->refreshPWMAdjustmentSlider();
// Refresh the PWM state
this->refreshPWMAdjustmentState();
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send the PWM pin id to the display on the PWM Adjustment page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPWMAdjustmentId()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 15:50:19 +00:00
// Send the PWM pin
this->displayAdapter->print("pwm_id.txt=\"P");
this->displayAdapter->print(pmwAdjustmentPin);
this->displayAdapter->print("\"");
this->sendStopBytes();
this->giveSerialMutex();
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send the PWM value to the display on the PWM Adjustment page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPWMAdjustmentSlider()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 15:50:19 +00:00
// Send the PWM value
this->displayAdapter->print("pwm_value.val=");
this->displayAdapter->print(this->outputCard->getValue(this->pmwAdjustmentPin));
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send the PWM state to the display on the PWM Adjustment page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshPWMAdjustmentState()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 15:50:19 +00:00
// Send the PWM state
this->displayAdapter->print("pwm_state.txt=\"");
this->displayAdapter->print(this->outputCard->getState(this->pmwAdjustmentPin) ? MSG_PWM_ADJUSTMENT_STATE_ON : MSG_PWM_ADJUSTMENT_STATE_OFF);
this->displayAdapter->print("\"");
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Handle the touch event on the display
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param page The page that the touch event occured
* @param component The component that the touch event occured
* @param type The type of the touch event
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handleTouch(uint8_t page, uint8_t component, uint8_t type)
{
2023-12-30 15:50:19 +00:00
// Switch based on the page
2023-12-31 06:41:48 +00:00
switch (page)
{
case INTERNAL_DISPLAY_AC_PAGE:
this->handleACTouch(type, component);
break;
case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE:
this->handlePWMAdjustmentTouch(type, component);
break;
2023-12-31 08:53:39 +00:00
case INTERNAL_DISPLAY_NETWORK_CONFIG_PAGE:
if (type == TOUCH_TYPE_RELEASE && component == 7)
this->saveNetworkConfig();
break;
case INTERNAL_DISPLAY_MQTT_CONFIG_PAGE:
if (type == TOUCH_TYPE_RELEASE && component == 2)
this->saveMQTTConfig();
break;
2023-12-31 06:41:48 +00:00
default:
break;
2023-12-30 15:50:19 +00:00
}
}
2024-01-01 05:56:52 +00:00
/**
* @brief Handle the touch event on the AC page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param type The type of the touch event
* @param component The component that the touch event occured
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handleACTouch(uint8_t type, uint8_t component)
{
2023-12-30 17:25:07 +00:00
// b1 [component 18] -> inclement AC temperature by 1
// b0 [component 17] -> declement AC temperature by 1
// fan_auto [component 4] -> set the fan speed to auto
// fan_low [component 5] -> set the fan speed to low
// fan_med [component 6] -> set the fan speed to medium
// fan_high [component 7] -> set the fan speed to high
// mode_off [component 10] -> set the mode to off
// mode_fan [component 9] -> set the mode to fan only
// mode_cool [component 8] -> set the mode to cool
// For b0 and b1, if the type is not release then return
// For other components, if the type is not press then return
2023-12-31 06:41:48 +00:00
if ((component == 17 || component == 18) && type != TOUCH_TYPE_RELEASE)
return;
if ((component != 17 && component != 18) && type != TOUCH_TYPE_PRESS)
return;
2023-12-30 17:25:07 +00:00
// Switch based on the component
2023-12-31 06:41:48 +00:00
switch (component)
{
case 17:
// Decrement the temperature
this->climateCard->setTemperature(this->climateCard->getTemperature() - 1);
break;
case 18:
// Increment the temperature
this->climateCard->setTemperature(this->climateCard->getTemperature() + 1);
break;
case 4:
// Set the fan speed to auto
this->climateCard->setFanSpeed(AC_FAN_SPEED_AUTO);
break;
case 5:
// Set the fan speed to low
this->climateCard->setFanSpeed(AC_FAN_SPEED_LOW);
break;
case 6:
// Set the fan speed to medium
this->climateCard->setFanSpeed(AC_FAN_SPEED_MEDIUM);
break;
case 7:
// Set the fan speed to high
this->climateCard->setFanSpeed(AC_FAN_SPEED_HIGH);
break;
case 10:
// Set the mode to off
this->climateCard->setMode(AC_MODE_OFF);
break;
case 9:
// Set the mode to fan only
this->climateCard->setMode(AC_MODE_FAN_ONLY);
break;
case 8:
// Set the mode to cool
this->climateCard->setMode(AC_MODE_COOL);
break;
default:
break;
2023-12-30 17:25:07 +00:00
}
2023-12-30 15:50:19 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Handle the touch event on the PWM Adjustment page
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param type The type of the touch event
* @param component The component that the touch event occured
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handlePWMAdjustmentTouch(uint8_t type, uint8_t component)
{
2023-12-30 15:50:19 +00:00
// b0 [component 5] -> decrement the PWM id if its greater than 0, else set it to 15
// b1 [component 6] -> increment the PWM id if its less than 15, else set it to 0
// pwm_state [component 4] -> toggle the PWM state
// pwm_value [component 1] -> set the PWM value based on the slider value
// If the type is not release then return
2023-12-31 06:41:48 +00:00
if (type != TOUCH_TYPE_RELEASE)
return;
2023-12-30 15:50:19 +00:00
uint16_t val = 0;
// switch based on the component
2023-12-31 06:41:48 +00:00
switch (component)
{
case 5:
// Decrement the PWM id
this->pmwAdjustmentPin = this->pmwAdjustmentPin > 0 ? this->pmwAdjustmentPin - 1 : 15;
this->refreshPWMAdjustment();
break;
case 6:
// Increment the PWM id
this->pmwAdjustmentPin = this->pmwAdjustmentPin < 15 ? this->pmwAdjustmentPin + 1 : 0;
this->refreshPWMAdjustment();
break;
case 4:
// Toggle the PWM state
this->outputCard->setState(this->pmwAdjustmentPin, !this->outputCard->getState(this->pmwAdjustmentPin));
this->refreshPWMAdjustmentState();
break;
case 1:
// Set the PWM value
val = (uint16_t)this->getNumber("pwm_value.val");
this->outputCard->setValue(this->pmwAdjustmentPin, val);
break;
default:
break;
2023-12-30 15:50:19 +00:00
}
2023-12-30 17:51:34 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the network config page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshNetworkConfig()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 17:51:34 +00:00
// The network config page have the following components:
// ip_set -> a text input to set the ip address
// netmask_set -> a text input to set the netmask
// gateway_set -> a text input to set the gateway
// dns_set -> a text input to set the dns
2023-12-31 08:53:39 +00:00
// host_set -> a text input to set the hostname
2023-12-30 17:51:34 +00:00
// Refresh the ip address
this->displayAdapter->print("ip_set.txt=\"");
this->sendIpToDisplay(this->networkConfig->ip);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the netmask
this->displayAdapter->print("netmask_set.txt=\"");
this->sendIpToDisplay(this->networkConfig->subnet);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the gateway
this->displayAdapter->print("gateway_set.txt=\"");
this->sendIpToDisplay(this->networkConfig->gateway);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the dns
this->displayAdapter->print("dns_set.txt=\"");
this->sendIpToDisplay(this->networkConfig->dns1);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the hostname
2023-12-31 08:53:39 +00:00
this->displayAdapter->print("host_set.txt=\"");
2023-12-30 17:51:34 +00:00
this->displayAdapter->print(this->networkConfig->hostname);
this->displayAdapter->print("\"");
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 17:51:34 +00:00
}
2023-12-30 15:50:19 +00:00
2024-01-01 05:56:52 +00:00
/**
* @brief Send data to display element on the mqtt config page
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::refreshMQTTConfig()
{
2024-01-15 09:44:36 +00:00
if(!this->takeSerialMutex()) return;
2023-12-30 17:51:34 +00:00
// The MQTT config page have the following components:
// mqttsv_set -> a text input to set the mqtt server
// port_set -> a text input to set the mqtt port
// use_auth -> a checkbox to enable/disable mqtt authentication
// user_set -> a text input to set the mqtt username
// password_set -> a text input to set the mqtt password
// topic_set -> a text input to set the mqtt base topic
// Refresh the mqtt server
this->displayAdapter->print("mqttsv_set.txt=\"");
this->displayAdapter->print(this->mqttConfig->mqtt_server);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the mqtt port
2023-12-30 19:18:57 +00:00
this->displayAdapter->print("port_set.val=");
2023-12-30 17:51:34 +00:00
this->displayAdapter->print(this->mqttConfig->mqtt_port);
this->sendStopBytes();
// Refresh the mqtt username
this->displayAdapter->print("user_set.txt=\"");
this->displayAdapter->print(this->mqttConfig->mqtt_user);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the mqtt password
this->displayAdapter->print("password_set.txt=\"");
this->displayAdapter->print(this->mqttConfig->mqtt_password);
this->displayAdapter->print("\"");
this->sendStopBytes();
// Refresh the mqtt base topic
this->displayAdapter->print("topic_set.txt=\"");
this->displayAdapter->print(this->mqttConfig->base_topic);
this->displayAdapter->print("\"");
this->sendStopBytes();
2023-12-30 19:18:57 +00:00
// Refresh the mqtt use auth
this->displayAdapter->print("use_auth.val=");
this->displayAdapter->print(this->mqttConfig->mqtt_useauth ? 1 : 0);
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-30 17:51:34 +00:00
}
2023-12-30 15:50:19 +00:00
2024-01-01 05:56:52 +00:00
/**
* @brief Write an ip address to the display
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @note This function only writes the ip address to the display, you need to send the prefix and suffix yourself
2024-01-15 09:44:36 +00:00
* @warning This function does not take the serial mutex, you need to take it yourself
*
2024-01-01 05:56:52 +00:00
* @param ip The ip address to send
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::sendIpToDisplay(IPAddress ip)
{
2023-12-30 17:51:34 +00:00
// Send the ip address
this->displayAdapter->print(ip[0]);
this->displayAdapter->print(".");
this->displayAdapter->print(ip[1]);
this->displayAdapter->print(".");
this->displayAdapter->print(ip[2]);
this->displayAdapter->print(".");
this->displayAdapter->print(ip[3]);
2023-12-30 19:18:57 +00:00
}
2024-01-01 05:56:52 +00:00
/**
* @brief Handle the AC state change
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @note This function is registered as a callback to the ClimateCard
2024-01-15 09:44:36 +00:00
*
2024-01-01 05:56:52 +00:00
* @param mode The new mode
* @param fan_speed The new fan speed
* @param temperature The new temperature
*/
2023-12-31 06:41:48 +00:00
void InternalDisplay::handleACStateChange(uint8_t mode, uint8_t fan_speed, uint8_t temperature)
{
2023-12-30 19:18:57 +00:00
// If the climate card is binded to the display and the current page is the AC page
// then update the respective AC component
2023-12-31 06:41:48 +00:00
if (this->climateCard == nullptr || this->currentPage != INTERNAL_DISPLAY_AC_PAGE)
return;
2023-12-30 19:18:57 +00:00
this->sendStopBytes();
// Update the AC state
this->refreshAC();
}
/**
* @brief Set the boot status text
2024-01-15 09:44:36 +00:00
*
* @param text The text to set
*/
2024-01-15 09:44:36 +00:00
void InternalDisplay::setBootStatus(const char *text)
{
if(!this->takeSerialMutex()) return;
this->displayAdapter->print("boot_state.txt=\"");
this->displayAdapter->print(text);
this->displayAdapter->print("\"");
this->sendStopBytes();
2024-01-15 09:44:36 +00:00
this->giveSerialMutex();
2023-12-29 14:41:19 +00:00
}