#include void InternalDisplay::begin(ESPMegaIoT *iot, std::function getRtcTime) { ESP_LOGD("InternalDisplay", "Assigning IoT Module and RTC Time Getter"); this->iot = iot; this->getRtcTime = getRtcTime; ESP_LOGD("InternalDisplay", "Acquiring Network and MQTT Configs"); this->mqttConfig = this->iot->getMqttConfig(); this->networkConfig = this->iot->getNetworkConfig(); // Register callbacks ESP_LOGD("InternalDisplay", "Registering Callbacks"); 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); ESP_LOGD("InternalDisplay", "Binding Page Change Callback"); auto bindedInputStateChangeCallback = std::bind(&InternalDisplay::handleInputStateChange, this, std::placeholders::_1, std::placeholders::_2); ESP_LOGD("InternalDisplay", "Binding Input State Change Callback"); auto bindedPwmStateChangeCallback = std::bind(&InternalDisplay::handlePwmStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); ESP_LOGD("InternalDisplay", "Registering inputCard Callbacks"); this->inputCard->registerCallback(bindedInputStateChangeCallback); ESP_LOGD("InternalDisplay", "Registering outputCard Callbacks"); this->outputCard->registerChangeCallback(bindedPwmStateChangeCallback); // Initialize the display ESP_LOGD("InternalDisplay", "Initializing DisplayAdapter"); this->displayAdapter->begin(115200); ESP_LOGD("InternalDisplay", "Setting DisplayAdapter Timeout"); this->displayAdapter->setTimeout(100); ESP_LOGD("InternalDisplay", "Flushing DisplayAdapter"); this->displayAdapter->flush(); ESP_LOGD("InternalDisplay", "Resetting Display"); this->reset(); delay(500); ESP_LOGD("InternalDisplay", "Jumping to Page 1"); this->jumpToPage(1); ESP_LOGD("InternalDisplay", "Display Initialization Complete"); } void InternalDisplay::loop() { // Keep reading the Serial Adapter this->recieveSerialCommand(); // Refresh the top bar every 5 seconds static uint32_t lastTopBarRefresh; if (millis() - lastTopBarRefresh > INTERNAL_DISPLAY_TOP_BAR_REFRESH_INTERVAL) { this->updateStatusIcons(this->iot->networkConnected(), this->iot->mqttConnected()); lastTopBarRefresh = millis(); } // Refresh the clock every 10 seconds static uint32_t lastClockRefresh; if (millis() - lastClockRefresh > INTERNAL_DISPLAY_CLOCK_REFRESH_INTERVAL) { this->updateClock(); lastClockRefresh = millis(); } } void InternalDisplay::handleInputStateChange(uint8_t pin, bool state) { // If the input card is binded to the display and the current page is the input page // then update the respective input component if (this->inputCard!=nullptr || this->currentPage != INTERNAL_DISPLAY_INPUT_PAGE) return; // Update the input state this->setInputMarker(pin, state); } void InternalDisplay::handlePwmStateChange(uint8_t pin, bool state, uint16_t value) { // If the output card is binded to the display and the current page is the output page // then update the respective output component if (this->outputCard!=nullptr || this->currentPage != INTERNAL_DISPLAY_OUTPUT_PAGE) return; // Update the output state this->setOutputBar(pin, value); this->setOutputStateColor(pin, state); } void InternalDisplay::handlePageChange(uint8_t page) { // Refresh the page this->refreshPage(page); } void InternalDisplay::saveNetworkConfig() { // TODO: implementation } void InternalDisplay::saveMQTTConfig() { // TODO: implementation } void InternalDisplay::updateStatusIcons(bool networkStatus, bool mqttStatus) { this->setNumber("server.pic", mqttStatus ? PIC_MQTT_CONNECTED : PIC_MQTT_DISCONNECTED); this->setNumber("lan.pic", networkStatus ? PIC_LAN_CONNECTED : PIC_LAN_DISCONNECTED); } void InternalDisplay::updateClock() { rtctime_t time = this->getRtcTime(); this->displayAdapter->print("time.txt="); this->displayAdapter->print(time.hours%12); this->displayAdapter->print(":"); this->displayAdapter->print(time.minutes); this->displayAdapter->print(" "); this->displayAdapter->print(time.hours/12 ? "PM" : "AM"); this->sendStopBytes(); } void InternalDisplay::refreshPage() { this->refreshPage(this->currentPage); } void InternalDisplay::refreshPage(uint8_t page) { switch (page) { case INTERNAL_DISPLAY_DASHBOARD_PAGE: this->refreshDashboard(); break; case INTERNAL_DISPLAY_INPUT_PAGE: this->refreshInput(); break; case INTERNAL_DISPLAY_OUTPUT_PAGE: this->refreshOutput(); break; case INTERNAL_DISPLAY_AC_PAGE: this->refreshAC(); break; case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE: this->refreshPWMAdjustment(); break; default: break; } } void InternalDisplay::refreshDashboard() { // The dashboard have the following components: // 1. Hostname // 2. IP Address // 3. MQTT Server with port // 4. MQTT Connection status 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 this->displayAdapter->print("server_address.txt=\""); this->displayAdapter->print(this->mqttConfig->mqtt_server); this->displayAdapter->print(":"); this->displayAdapter->print(this->mqttConfig->mqtt_port); this->displayAdapter->print("\""); this->sendStopBytes(); // Send the MQTT connection status this->setString("status_txt.txt", this->iot->mqttConnected() ? MSG_MQTT_CONNECTED : MSG_MQTT_DISCONNECTED); } void InternalDisplay::refreshInput() { for (uint8_t i=0; i<16; i++) { this->setInputMarker(i, this->inputCard->digitalRead(i, false)); } } void InternalDisplay::refreshOutput() { for (uint8_t i=0; i<16; i++) { this->setOutputBar(i, this->outputCard->getValue(i)); this->setOutputStateColor(i, this->outputCard->getState(i)); } } void InternalDisplay::refreshAC() { // TODO: implementation } void InternalDisplay::setPWMAdjustmentSlider(uint16_t value) { // TODO: implementation } void InternalDisplay::setPWMAdjustmentPin(uint8_t pin) { // TODO: implementation } void InternalDisplay::setPWMAdjustmentButton(bool state) { // TODO: implementation } void InternalDisplay::setOutputBar(uint8_t pin, uint16_t value) { // Write the value to the output bar this->displayAdapter->print("j"); this->displayAdapter->print(pin); this->displayAdapter->print(".val="); this->displayAdapter->print((int)(value*100/4095)); this->sendStopBytes(); } void InternalDisplay::setOutputStateColor(uint8_t pin, bool state) { 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(); } void InternalDisplay::setInputMarker(uint8_t pin, bool state) { this->displayAdapter->print("I"); this->displayAdapter->print(pin); this->displayAdapter->print(".val="); this->displayAdapter->print(state ? 0:1); this->sendStopBytes(); } InternalDisplay::InternalDisplay(HardwareSerial *displayAdapter) : ESPMegaDisplay(displayAdapter) { this->currentPage = INTERNAL_DISPLAY_DASHBOARD_PAGE; this->iot = nullptr; this->inputCard = nullptr; this->outputCard = nullptr; this->climateCard = nullptr; this->pmwAdjustmentPin = 0; } void InternalDisplay::bindInputCard(DigitalInputCard *inputCard) { this->inputCard = inputCard; } void InternalDisplay::bindOutputCard(DigitalOutputCard *outputCard) { this->outputCard = outputCard; } void InternalDisplay::bindClimateCard(ClimateCard *climateCard) { this->climateCard = climateCard; } void InternalDisplay::refreshPWMAdjustment() { // 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(); } void InternalDisplay::refreshPWMAdjustmentId() { // Send the PWM pin this->displayAdapter->print("pwm_id.txt=\"P"); this->displayAdapter->print(pmwAdjustmentPin); this->displayAdapter->print("\""); this->sendStopBytes(); } void InternalDisplay::refreshPWMAdjustmentSlider() { // Send the PWM value this->displayAdapter->print("pwm_value.val="); this->displayAdapter->print(this->outputCard->getValue(this->pmwAdjustmentPin)); this->sendStopBytes(); } void InternalDisplay::refreshPWMAdjustmentState() { // 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(); } void InternalDisplay::handleTouch(uint8_t page, uint8_t component, uint8_t type) { // Switch based on the page switch (page) { case INTERNAL_DISPLAY_AC_PAGE: this->handleACTouch(type, component); break; case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE: this->handlePWMAdjustmentTouch(type, component); break; default: break; } } void InternalDisplay::handleACTouch(uint8_t type, uint8_t component) { } void InternalDisplay::handlePWMAdjustmentTouch(uint8_t type, uint8_t component) { // 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 if (type != TOUCH_TYPE_RELEASE) return; uint16_t val = 0; // switch based on the component 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; } }