#include "display.hpp" CUDDisplay::CUDDisplay(cud_display_conf_t *conf) : ESPMegaDisplay(conf->uart, conf->communication_baudrate, conf->ota_baudrate, conf->tx, conf->rx) { this->conf = conf; // Initialize Light Group and Fan Group this->light_group = { .element_id = {LCD_DASHBOARD_ELEMENT_LIGHT_1, LCD_DASHBOARD_ELEMENT_LIGHT_2, LCD_DASHBOARD_ELEMENT_LIGHT_3, LCD_DASHBOARD_ELEMENT_LIGHT_4}, .element_name = {LCD_DASHBOARD_ELEMENT_NAME_LIGHT_1, LCD_DASHBOARD_ELEMENT_NAME_LIGHT_2, LCD_DASHBOARD_ELEMENT_NAME_LIGHT_3, LCD_DASHBOARD_ELEMENT_NAME_LIGHT_4}, .picture_on = {LCD_DASHBOARD_PIC_LIGHT_1_ON, LCD_DASHBOARD_PIC_LIGHT_2_ON, LCD_DASHBOARD_PIC_LIGHT_3_ON, LCD_DASHBOARD_PIC_LIGHT_4_ON}, .picture_on_pressed = {LCD_DASHBOARD_PIC_LIGHT_1_ON_PRESSED, LCD_DASHBOARD_PIC_LIGHT_2_ON_PRESSED, LCD_DASHBOARD_PIC_LIGHT_3_ON_PRESSED, LCD_DASHBOARD_PIC_LIGHT_4_ON_PRESSED}, .picture_off = {LCD_DASHBOARD_PIC_LIGHT_1_OFF, LCD_DASHBOARD_PIC_LIGHT_2_OFF, LCD_DASHBOARD_PIC_LIGHT_3_OFF, LCD_DASHBOARD_PIC_LIGHT_4_OFF}, .picture_off_pressed = {LCD_DASHBOARD_PIC_LIGHT_1_OFF_PRESSED, LCD_DASHBOARD_PIC_LIGHT_2_OFF_PRESSED, LCD_DASHBOARD_PIC_LIGHT_3_OFF_PRESSED, LCD_DASHBOARD_PIC_LIGHT_4_OFF_PRESSED}}; this->fan_group = { .element_id = {LCD_DASHBOARD_ELEMENT_FAN_1, LCD_DASHBOARD_ELEMENT_FAN_2, LCD_DASHBOARD_ELEMENT_FAN_3}, .element_name = {LCD_DASHBOARD_ELEMENT_NAME_FAN_1, LCD_DASHBOARD_ELEMENT_NAME_FAN_2, LCD_DASHBOARD_ELEMENT_NAME_FAN_3}, .picture_on = {LCD_DASHBOARD_PIC_FAN_1_ON, LCD_DASHBOARD_PIC_FAN_2_ON, LCD_DASHBOARD_PIC_FAN_3_ON}, .picture_on_pressed = {LCD_DASHBOARD_PIC_FAN_1_ON_PRESSED, LCD_DASHBOARD_PIC_FAN_2_ON_PRESSED, LCD_DASHBOARD_PIC_FAN_3_ON_PRESSED}, .picture_off = {LCD_DASHBOARD_PIC_FAN_1_OFF, LCD_DASHBOARD_PIC_FAN_2_OFF, LCD_DASHBOARD_PIC_FAN_3_OFF}, .picture_off_pressed = {LCD_DASHBOARD_PIC_FAN_1_OFF_PRESSED, LCD_DASHBOARD_PIC_FAN_2_OFF_PRESSED, LCD_DASHBOARD_PIC_FAN_3_OFF_PRESSED}}; } CUDDisplay::~CUDDisplay() { if (ac_lock_topic != nullptr) { free(ac_lock_topic); } if (ac_lock_set_topic != nullptr) { free(ac_lock_set_topic); } if (ac_lock_request_topic != nullptr) { free(ac_lock_request_topic); } if (ac_temp_upper_bound_topic != nullptr) { free(ac_temp_upper_bound_topic); } if (ac_temp_upper_bound_set_topic != nullptr) { free(ac_temp_upper_bound_set_topic); } if (ac_temp_upper_bound_request_topic != nullptr) { free(ac_temp_upper_bound_request_topic); } if (ac_temp_lower_bound_topic != nullptr) { free(ac_temp_lower_bound_topic); } if (ac_temp_lower_bound_set_topic != nullptr) { free(ac_temp_lower_bound_set_topic); } if (ac_temp_lower_bound_request_topic != nullptr) { free(ac_temp_lower_bound_request_topic); } } void CUDDisplay::begin(cud_display_cards_t cards) { // Save Cards this->cards = cards; // Register callbacks ESP_LOGV("CUD Display", "Registering callbacks"); auto binded_input_callback = std::bind(&CUDDisplay::handle_input_change, this, std::placeholders::_1, std::placeholders::_2); auto binded_output_callback = std::bind(&CUDDisplay::handle_output_change, this, std::placeholders::_1, std::placeholders::_2); auto binded_aqi_callback = std::bind(&CUDDisplay::handle_aqi_change, this, std::placeholders::_1); auto binded_payload_callback = std::bind(&CUDDisplay::handle_payload, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto binded_touch_callback = std::bind(&CUDDisplay::handle_touch, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto binded_ac_callback = std::bind(&CUDDisplay::handle_ac_change, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto binded_ac_sensor_callback = std::bind(&CUDDisplay::handle_ac_sensor, this, std::placeholders::_1, std::placeholders::_2); auto binded_handle_mqtt_connected = std::bind(&CUDDisplay::handle_mqtt_connected, this); ESP_LOGV("CUD Display", "Registering Input Card Callbacks"); this->cards.inputCard->registerCallback(binded_input_callback); ESP_LOGV("CUD Display", "Registering Output Card Callbacks"); this->cards.outputCard->registerChangeCallback(binded_output_callback); ESP_LOGV("CUD Display", "Registering AQI Callbacks"); this->conf->aqi->registerCallback(binded_aqi_callback); ESP_LOGV("CUD Display", "Registering MQTT Connected Callbacks"); this->cards.iot->registerSubscribeCallback(binded_handle_mqtt_connected); ESP_LOGV("CUD Display", "Registering Display Payload Callbacks"); this->registerPayloadCallback(binded_payload_callback); ESP_LOGV("CUD Display", "Registering Display Touch Callbacks"); this->registerTouchCallback(binded_touch_callback); ESP_LOGV("CUD Display", "Registering AC Callbacks"); this->cards.ac->registerChangeCallback(binded_ac_callback); ESP_LOGV("CUD Display", "Registering AC Sensor Callbacks"); this->cards.ac->registerSensorCallback(binded_ac_sensor_callback); // Initialize Smart Variables ESP_LOGV("CUD Display", "Initializing Smart Variables"); // Get Base Topic char *base_topic = this->cards.iot->getMqttConfig()->base_topic; uint8_t base_topic_length = strlen(base_topic); // Smart Variables // AC Lock this->ac_lock.begin(10); this->ac_lock.bindFRAM(this->cards.fram, AC_LOCK_FRAM_ADDR); this->ac_lock.setValueAutoSave(true); ac_lock_topic = (char *)malloc(base_topic_length + strlen(AC_LOCK_RELATIVE_TOPIC) + 3); sprintf(ac_lock_topic, "%s%s", base_topic, AC_LOCK_RELATIVE_TOPIC); this->ac_lock.enableIoT(this->cards.iot, ac_lock_topic); ac_lock_set_topic = (char *)malloc(base_topic_length + strlen(AC_LOCK_RELATIVE_TOPIC) + sizeof("/set") + 3); sprintf(ac_lock_set_topic, "%s%s/set", base_topic, AC_LOCK_RELATIVE_TOPIC); this->ac_lock.enableSetValue(ac_lock_set_topic); ac_lock_request_topic = (char *)malloc(base_topic_length + strlen(AC_LOCK_RELATIVE_TOPIC) + sizeof("/request") + 3); sprintf(ac_lock_request_topic, "%s%s/request", base_topic, AC_LOCK_RELATIVE_TOPIC); this->ac_lock.enableValueRequest(ac_lock_request_topic); auto binded_ac_lock_callback = std::bind(&CUDDisplay::handle_lock_change, this, std::placeholders::_1); this->ac_lock.registerCallback(binded_ac_lock_callback); // AC Temp Lower Bound this->ac_temp_lower_bound.begin(6); this->ac_temp_lower_bound.bindFRAM(this->cards.fram, AC_DISPLAY_TEMP_LOWER_BOUND_ADDR); this->ac_temp_lower_bound.setValueAutoSave(true); ac_temp_lower_bound_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC) + 3); sprintf(ac_temp_lower_bound_topic, "%s%s", base_topic, AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC); this->ac_temp_lower_bound.enableIoT(this->cards.iot, ac_temp_lower_bound_topic); ac_temp_lower_bound_set_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC) + sizeof("/set") + 3); sprintf(ac_temp_lower_bound_set_topic, "%s%s/set", base_topic, AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC); this->ac_temp_lower_bound.enableSetValue(ac_temp_lower_bound_set_topic); ac_temp_lower_bound_request_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC) + sizeof("/request") + 3); sprintf(ac_temp_lower_bound_request_topic, "%s%s/request", base_topic, AC_TEMP_LOWER_BOUND_RELATIVE_TOPIC); this->ac_temp_lower_bound.enableValueRequest(ac_temp_lower_bound_request_topic); auto binded_ac_temp_lower_bound_callback = std::bind(&CUDDisplay::handle_bound_change, this, std::placeholders::_1); this->ac_temp_lower_bound.registerCallback(binded_ac_temp_lower_bound_callback); // AC Temp Upper Bound this->ac_temp_upper_bound.begin(6); this->ac_temp_upper_bound.bindFRAM(this->cards.fram, AC_DISPLAY_TEMP_UPPER_BOUND_ADDR); this->ac_temp_upper_bound.setValueAutoSave(true); ac_temp_upper_bound_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC) + 3); sprintf(ac_temp_upper_bound_topic, "%s%s", base_topic, AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC); this->ac_temp_upper_bound.enableIoT(this->cards.iot, ac_temp_upper_bound_topic); ac_temp_upper_bound_set_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC) + sizeof("/set") + 3); sprintf(ac_temp_upper_bound_set_topic, "%s%s/set", base_topic, AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC); this->ac_temp_upper_bound.enableSetValue(ac_temp_upper_bound_set_topic); ac_temp_upper_bound_request_topic = (char *)malloc(base_topic_length + strlen(AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC) + sizeof("/request") + 3); sprintf(ac_temp_upper_bound_request_topic, "%s%s/request", base_topic, AC_TEMP_UPPER_BOUND_RELATIVE_TOPIC); this->ac_temp_upper_bound.enableValueRequest(ac_temp_upper_bound_request_topic); auto binded_ac_temp_upper_bound_callback = std::bind(&CUDDisplay::handle_bound_change, this, std::placeholders::_1); this->ac_temp_upper_bound.registerCallback(binded_ac_temp_upper_bound_callback); // Check Bound Validity // Lower Bound must be less than Upper Bound // Lower Bound can't be less than AC_MIN_TEMP // Upper Bound can't be more than AC_MAX_TEMP // If any of the bound is invalid, set all to default if (this->ac_temp_lower_bound.getIntValue() < AC_MIN_TEMP || this->ac_temp_upper_bound.getIntValue() > AC_MAX_TEMP || this->ac_temp_lower_bound.getIntValue() >= this->ac_temp_upper_bound.getIntValue()) { ESP_LOGW("CUD Display", "Temperature Bounds are invalid, setting to default"); this->ac_temp_lower_bound.setIntValue(DEFAULT_TEMP_LOWER_BOUND); this->ac_temp_upper_bound.setIntValue(DEFAULT_TEMP_UPPER_BOUND); } // Initialize the display ESP_LOGV("CUD Display", "Initializing display"); this->display_init(); } void CUDDisplay::loop() { ESPMegaDisplay::loop(); // Check if the AC button press is pending if (this->ac_button_press_pending) { // Check if the delay has passed if (millis() - this->last_ac_button_press > AC_TEMP_PRESS_DELAY) { ESP_LOGV("CUD Display", "Sending pending temperature"); // Send the pending temperature this->cards.ac->setTemperature(this->pending_temperature); // Reset the pending flag this->ac_button_press_pending = false; } } // Check if MQTT is connected static uint32_t last_mqtt_connected_check = 0; if (last_mqtt_connected_check == 0) { last_mqtt_connected_check = millis() + 15000; // Wait 15 seconds before checking } static bool first_disconnect = true; if (millis() - last_mqtt_connected_check > 3000) { ESP_LOGD("CUD Display", "Checking MQTT Connection, Connection is %s", this->cards.iot->mqttConnected() ? "true" : "false"); if (!this->cards.iot->mqttConnected()) { this->standalone = true; if (first_disconnect) { // When MQTT is disconnected, enter standalone mode // In standalone mode, socket contactor is turned on // A/C lock is lifted // A/C temperature range limits are lifted this->refresh_display_ac(); this->cards.outputCard->setState(this->conf->socket_contactor_pin, true); first_disconnect = false; } } else { standalone = false; if (first_disconnect == false) { // When MQTT is connected, exit standalone mode // In standalone mode, socket contactor is turned off // A/C lock is set // A/C temperature range limits are set first_disconnect = true; // Rebound the temperature if (this->cards.ac->getTemperature() < this->get_ac_temp_lower_bound()) { this->cards.ac->setTemperature(this->get_ac_temp_lower_bound()); } else if (this->cards.ac->getTemperature() > this->get_ac_temp_upper_bound()) { this->cards.ac->setTemperature(this->get_ac_temp_upper_bound()); } this->refresh_display_ac(); } } last_mqtt_connected_check = millis(); } } void CUDDisplay::display_init() { // Perform a reset on the display ESP_LOGV("CUD Display", "Resetting display"); this->reset(); vTaskDelay(1000 / portTICK_PERIOD_MS); // Set the display to the main screen ESP_LOGV("CUD Display", "Setting display to main screen"); this->jumpToPage(LCD_PAGE_ID_DASHBOARD); // Send the initial states to the display ESP_LOGV("CUD Display", "Sending initial states to display"); this->refresh_display(); } bool CUDDisplay::get_lights_state() { for (int i = 0; i < 4; i++) { if (this->cards.outputCard->getState(this->conf->light_pins[i])) return true; } return false; } bool CUDDisplay::get_fans_state() { for (int i = 0; i < 3; i++) { if (this->cards.outputCard->getState(this->conf->fan_pins[i])) return true; } return false; } void CUDDisplay::handle_input_change(uint8_t pin, bool state) { // This is not needed for now. We are only handling outputs // Putting this here in case we need to handle inputs in the future } void CUDDisplay::handle_output_change(uint8_t pin, bool state) { // Check if it is a light or fan // If it's a light, call set_display_light_state // If it's a fan, call set_display_fan_state // If it's the air purifier, call set_display_air_purifier_state // If it's the mosquito zapper, call set_display_mosquito_zapper_state // Check if it's the air purifier if (pin == this->conf->air_purifier_pin) { this->set_display_air_purifier_state(state); this->refresh_display_allsystem(); return; } // Check if it's the mosquito zapper if (pin == this->conf->mosquito_zapper_pin) { this->set_display_mosquito_zapper_state(state); this->refresh_display_allsystem(); return; } // Check if it's the socket contactor if (pin == this->conf->socket_contactor_pin) { this->refresh_display_socket(); return; } // Loop through each to check if the pin is a light for (int i = 0; i < 4; i++) { if (pin == this->conf->light_pins[i]) { this->set_display_light_state(i, state); this->set_display_light_all_state(); this->refresh_display_allsystem(); return; } } // Loop through each to check if the pin is a fan for (int i = 0; i < 3; i++) { if (pin == this->conf->fan_pins[i]) { this->set_display_fan_state(i, state); this->set_display_fan_all_state(); this->refresh_display_allsystem(); return; } } // The pin is not the one that our display is handling, so we can ignore it } void CUDDisplay::handle_touch(uint8_t page_id, uint8_t element_id, uint8_t touch_type) { // Check if element_id is the light all button if (element_id == LCD_DASHBOARD_ELEMENT_LIGHT_ALL) { // If it is, toggle all the lights bool light_on = this->get_lights_state(); for (int i = 0; i < 4; i++) { this->cards.outputCard->setState(this->conf->light_pins[i], !light_on); } return; } // Check if element_id is the fan all button else if (element_id == LCD_DASHBOARD_ELEMENT_FAN_ALL) { // If it is, toggle all the fans bool fan_on = this->get_fans_state(); for (int i = 0; i < 3; i++) { this->cards.outputCard->setState(this->conf->fan_pins[i], !fan_on); } return; } // Check if element_id is the air purifier button else if (element_id == LCD_DASHBOARD_ELEMENT_AIR_PURIFIER) { // If it is, toggle the air purifier this->cards.outputCard->setState(this->conf->air_purifier_pin, !this->cards.outputCard->getState(this->conf->air_purifier_pin)); return; } // Check if element_id is the mosquito zapper button else if (element_id == LCD_DASHBOARD_ELEMENT_MOSQUITO_ZAPPER) { // If it is, toggle the mosquito zapper this->cards.outputCard->setState(this->conf->mosquito_zapper_pin, !this->cards.outputCard->getState(this->conf->mosquito_zapper_pin)); return; } // Check if element_id is a light button for (int i = 0; i < 4; i++) { if (element_id == this->light_group.element_id[i]) { // If it is, toggle the light this->cards.outputCard->setState(this->conf->light_pins[i], !this->cards.outputCard->getState(this->conf->light_pins[i])); return; } } // Check if element_id is a fan button for (int i = 0; i < 3; i++) { if (element_id == this->fan_group.element_id[i]) { // If it is, toggle the fan this->cards.outputCard->setState(this->conf->fan_pins[i], !this->cards.outputCard->getState(this->conf->fan_pins[i])); return; } } // Check if element_id is the AC state button if (element_id == LCD_DASHBOARD_ELEMENT_AC_STATE) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Toggle the AC // Is the AC on? if (this->cards.ac->getMode() != 0) { // If it is, turn it off this->cards.ac->setMode(0); } else { // If it is not, turn it on this->cards.ac->setMode(previous_mode); } return; } // Check if element_id is the AC mode fan button if (element_id == LCD_DASHBOARD_ELEMENT_AC_MODE_FAN) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC mode to fan this->cards.ac->setMode(1); return; } // Check if element_id is the AC mode cool button if (element_id == LCD_DASHBOARD_ELEMENT_AC_MODE_COOL) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC mode to cool this->cards.ac->setMode(2); return; } // Check if element_id is the AC fan speed auto button if (element_id == LCD_DASHBOARD_ELEMENT_AC_FAN_SPEED_AUTO) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC fan speed to auto this->cards.ac->setFanSpeed(0); return; } // Check if element_id is the AC fan speed low button if (element_id == LCD_DASHBOARD_ELEMENT_AC_FAN_SPEED_LOW) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC fan speed to low this->cards.ac->setFanSpeed(1); return; } // Check if element_id is the AC fan speed medium button if (element_id == LCD_DASHBOARD_ELEMENT_AC_FAN_SPEED_MEDIUM) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC fan speed to medium this->cards.ac->setFanSpeed(2); return; } // Check if element_id is the AC fan speed high button if (element_id == LCD_DASHBOARD_ELEMENT_AC_FAN_SPEED_HIGH) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; // Set the AC fan speed to high this->cards.ac->setFanSpeed(3); return; } // Check if element_id is the AC temperature up button if (element_id == LCD_DASHBOARD_ELEMENT_AC_TEMP_UP_BUTTON) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; uint8_t newTemp = this->cards.ac->getTemperature(); if (this->ac_button_press_pending) { // If the button press is pending, use the pending temperature as base newTemp = this->pending_temperature; } newTemp++; // Does the temperature exceed the upper bound?, if it does, bound it if (newTemp > this->get_ac_temp_upper_bound()) { newTemp = this->get_ac_temp_upper_bound(); } ESP_LOGD("CUD Display", "New Temp: %d", newTemp); // Increase the AC temperature pending_temperature = newTemp; ac_button_press_pending = true; last_ac_button_press = millis(); // Send the new temperature to the Display this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"%d\"", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMPERATURE, newTemp); this->sendStopBytes(); this->giveSerialMutex(); return; } // Check if element_id is the AC temperature down button if (element_id == LCD_DASHBOARD_ELEMENT_AC_TEMP_DOWN_BUTTON) { // Is the control locked? If it is, we can ignore the touch if (this->get_ac_lock()) return; uint8_t newTemp = this->cards.ac->getTemperature(); if (this->ac_button_press_pending) { // If the button press is pending, use the pending temperature as base newTemp = this->pending_temperature; } newTemp--; // Does the temperature exceed the lower bound?, if it does, bound it ESP_LOGD("CUD Display", "Requested Temp: %d, Lower Bound: %d", newTemp, this->get_ac_temp_lower_bound()); if (newTemp < this->get_ac_temp_lower_bound()) { newTemp = this->get_ac_temp_lower_bound(); } ESP_LOGD("CUD Display", "New Temp: %d", newTemp); // Decrease the AC temperature pending_temperature = newTemp; ac_button_press_pending = true; last_ac_button_press = millis(); // Send the new temperature to the Display this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"%d\"", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMPERATURE, newTemp); this->sendStopBytes(); this->giveSerialMutex(); return; } if (element_id == LCD_DASHBOARD_ELEMENT_ALL_SYSTEM_TOGGLE) { this->system_toggle(); return; } // The element_id is not the one that our display is handling, so we can ignore it } void CUDDisplay::handle_lock_change(char *value) { this->refresh_display_ac(); } void CUDDisplay::handle_bound_change(char *value) { // Bound is changed, check if the bounds are valid // Lower Bound must be less than Upper Bound // Lower Bound can't be less than AC_MIN_TEMP // Upper Bound can't be more than AC_MAX_TEMP // If any of the bound is invalid, set all to default if (this->ac_temp_lower_bound.getIntValue() < AC_MIN_TEMP || this->ac_temp_lower_bound.getIntValue() >= this->ac_temp_upper_bound.getIntValue()) { ESP_LOGV("CUD Display", "Invalid Lower Bound, Setting to Default"); this->ac_temp_lower_bound.setIntValue(DEFAULT_TEMP_LOWER_BOUND); } if (this->ac_temp_upper_bound.getIntValue() > AC_MAX_TEMP || this->ac_temp_lower_bound.getIntValue() >= this->ac_temp_upper_bound.getIntValue()) { ESP_LOGV("CUD Display", "Invalid Upper Bound, Setting to Default"); this->ac_temp_upper_bound.setIntValue(DEFAULT_TEMP_UPPER_BOUND); } // Does the current temperature exceed the new upper bound?, if it does, bound it if (this->cards.ac->getTemperature() > this->ac_temp_upper_bound.getIntValue()) { this->cards.ac->setTemperature(this->ac_temp_upper_bound.getIntValue()); } // Does the current temperature exceed the new lower bound?, if it does, bound it if (this->cards.ac->getTemperature() < this->ac_temp_lower_bound.getIntValue()) { this->cards.ac->setTemperature(this->ac_temp_lower_bound.getIntValue()); } } void CUDDisplay::handle_aqi_change(char *value) { ESP_LOGV("CUD Display", "AQI Changed: %s", value); // Update the AQI value on the display uint16_t aqi = atoi(value); this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"%03d\"", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, (int)aqi); this->sendStopBytes(); // Update the AQI picture on the display if (aqi <= 50) { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_GOOD); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_GOOD); this->sendStopBytes(); } else if (aqi <= 100) { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_MODERATE); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_MODERATE); this->sendStopBytes(); } else if (aqi <= 150) { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_UNHEALTHY_FOR_SENSITIVE_GROUPS); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_UNHEALTHY_FOR_SENSITIVE_GROUPS); this->sendStopBytes(); } else if (aqi <= 200) { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_UNHEALTHY); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_UNHEALTHY); this->sendStopBytes(); } else if (aqi <= 300) { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_VERY_UNHEALTHY); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_VERY_UNHEALTHY); this->sendStopBytes(); } else { this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_PICTURE, LCD_DASHBOARD_PIC_AQI_HAZARDOUS); this->sendStopBytes(); this->displayAdapter->printf("%s.pco=%d", LCD_DASHBOARD_ELEMENT_NAME_AQI_TEXT, LCD_DASHBOARD_COLOR_AQI_TEXT_HAZARDOUS); this->sendStopBytes(); } this->giveSerialMutex(); } /** * @brief Handle the payload from the display that is not handled by the parent class * * @param type Payload type * @param payload The payload itself * @param length The length of the payload excluding the type */ void CUDDisplay::handle_payload(uint8_t type, uint8_t *payload, uint8_t length) { // If payload of type 0x92 is received // Reset the display and reinitialize it if (type == 0x92) { this->display_init(); } } void CUDDisplay::handle_ac_change(uint8_t mode, uint8_t fan_speed, uint8_t temperature) { // Set the previous mode to the current mode if the current mode is not 0 if (mode != 0) { previous_mode = mode; } this->refresh_display_ac(); this->refresh_display_allsystem(); } void CUDDisplay::handle_ac_sensor(float temperature, float humidity) { // Is the temperature valid? // A temperature of -999.0 means the sensor is not connected ESP_LOGV("CUD Display", "AC Sensor Temperature: %f", temperature); if (temperature == -999.0) { // If the temperature is not valid, Send NA to the display this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"NA\"", LCD_DASHBOARD_ELEMENT_NAME_ROOM_TEMPERATURE); this->sendStopBytes(); this->giveSerialMutex(); return; } // Temperature is valid, send it to the display this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"%d\"", LCD_DASHBOARD_ELEMENT_NAME_ROOM_TEMPERATURE, (int)temperature); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::handle_mqtt_connected() { // Refresh the display this->refresh_display_ac(); } void CUDDisplay::set_display_light_state(uint8_t row, bool state) { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", this->light_group.element_name[row], state ? this->light_group.picture_on[row] : this->light_group.picture_off[row]); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", this->light_group.element_name[row], state ? this->light_group.picture_on_pressed[row] : this->light_group.picture_off_pressed[row]); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::set_display_light_all_state() { bool light_on = this->get_lights_state(); this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_LIGHT_ALL, light_on ? LCD_DASHBOARD_PIC_LIGHT_ALL_ON : LCD_DASHBOARD_PIC_LIGHT_ALL_OFF); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_LIGHT_ALL, light_on ? LCD_DASHBOARD_PIC_LIGHT_ALL_ON_PRESSED : LCD_DASHBOARD_PIC_LIGHT_ALL_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::set_display_fan_state(uint8_t row, bool state) { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", this->fan_group.element_name[row], state ? this->fan_group.picture_on[row] : this->fan_group.picture_off[row]); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", this->fan_group.element_name[row], state ? this->fan_group.picture_on_pressed[row] : this->fan_group.picture_off_pressed[row]); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::set_display_fan_all_state() { bool fan_on = this->get_fans_state(); this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_FAN_ALL, fan_on ? LCD_DASHBOARD_PIC_FAN_ALL_ON : LCD_DASHBOARD_PIC_FAN_ALL_OFF); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_FAN_ALL, fan_on ? LCD_DASHBOARD_PIC_FAN_ALL_ON_PRESSED : LCD_DASHBOARD_PIC_FAN_ALL_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::set_display_mosquito_zapper_state(bool state) { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_MOSQUITO_ZAPPER, state ? LCD_DASHBOARD_PIC_MOSQUITO_ZAPPER_ON : LCD_DASHBOARD_PIC_MOSQUITO_ZAPPER_OFF); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_MOSQUITO_ZAPPER, state ? LCD_DASHBOARD_PIC_MOSQUITO_ZAPPER_ON_PRESSED : LCD_DASHBOARD_PIC_MOSQUITO_ZAPPER_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::set_display_air_purifier_state(bool state) { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AIR_PURIFIER, state ? LCD_DASHBOARD_PIC_AIR_PURIFIER_ON : LCD_DASHBOARD_PIC_AIR_PURIFIER_OFF); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AIR_PURIFIER, state ? LCD_DASHBOARD_PIC_AIR_PURIFIER_ON_PRESSED : LCD_DASHBOARD_PIC_AIR_PURIFIER_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::refresh_display() { // Send every states to the display ESP_LOGV("CUD Display", "Refreshing all light button states"); this->set_display_light_all_state(); ESP_LOGV("CUD Display", "Refreshing all fan button states"); this->set_display_fan_all_state(); ESP_LOGV("CUD Display", "Refreshing air purifier state"); this->set_display_air_purifier_state(this->cards.outputCard->getState(this->conf->air_purifier_pin)); ESP_LOGV("CUD Display", "Refreshing mosquito zapper state"); this->set_display_mosquito_zapper_state(this->cards.outputCard->getState(this->conf->mosquito_zapper_pin)); ESP_LOGV("CUD Display", "Refreshing light states"); for (int i = 0; i < 4; i++) { this->set_display_light_state(i, this->cards.outputCard->getState(this->conf->light_pins[i])); } ESP_LOGV("CUD Display", "Refreshing Fan state"); for (int i = 0; i < 3; i++) { this->set_display_fan_state(i, this->cards.outputCard->getState(this->conf->fan_pins[i])); } refresh_display_ac(); refresh_display_allsystem(); refresh_display_socket(); } void CUDDisplay::refresh_display_ac() { // Fetch data from the AC uint8_t mode = this->cards.ac->getMode(); bool state = mode != 0; previous_mode = previous_mode == 0 ? 2 : previous_mode; uint8_t drawn_mode = mode == 0 ? previous_mode : mode; uint8_t fan_speed = this->cards.ac->getFanSpeed(); uint8_t temperature = this->cards.ac->getTemperature(); ESP_LOGV("CUD Display", "Mode: %d, Fan Speed: %d, Temperature: %d", mode, fan_speed, temperature); ESP_LOGV("CUD Display", "Previous Mode: %d, Drawn Mode: %d", previous_mode, drawn_mode); // Is the AC locked? if (this->get_ac_lock()) { // Draw the state picture set // When the display is locked // the state picture set we use is the locked state picture set this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_STATE, state ? LCD_DASHBOARD_PIC_AC_STATE_ON_LOCKED : LCD_DASHBOARD_PIC_AC_STATE_OFF_LOCKED); this->sendStopBytes(); // Since the display is locked, when pressed, the state picture set should not change this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_STATE, state ? LCD_DASHBOARD_PIC_AC_STATE_ON_LOCKED : LCD_DASHBOARD_PIC_AC_STATE_OFF_LOCKED); this->sendStopBytes(); // Set Alpha of Locked Icon to 127 this->displayAdapter->printf("%s.aph=%d", LCD_DASHBOARD_ELEMENT_NAME_ICO_LOCK, 127); this->sendStopBytes(); // Overlay the ac container this->displayAdapter->printf("vis %s,1", LCD_DASHBOARD_ELEMENT_NAME_AC_PANEL_OVERLAY); this->sendStopBytes(); // Hide the temperature adjustment buttons this->displayAdapter->printf("vis %s,0", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMP_UP_BUTTON); this->sendStopBytes(); this->displayAdapter->printf("vis %s,0", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMP_DOWN_BUTTON); this->sendStopBytes(); // Draw the mode picture set // If it is not locked this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_COOL, drawn_mode == 2 ? (LCD_DASHBOARD_PIC_AC_MODE_COOL_ACTIVE_LOCKED) : LCD_DASHBOARD_PIC_AC_MODE_COOL_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_COOL, drawn_mode == 2 ? LCD_DASHBOARD_PIC_AC_MODE_COOL_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_MODE_COOL_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_FAN, drawn_mode == 1 ? LCD_DASHBOARD_PIC_AC_MODE_FAN_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_MODE_FAN_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_FAN, drawn_mode == 1 ? LCD_DASHBOARD_PIC_AC_MODE_FAN_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_MODE_FAN_INACTIVE); this->sendStopBytes(); // Draw fan speed auto picture set this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_AUTO, fan_speed == 0 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_AUTO, fan_speed == 0 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_LOW, fan_speed == 1 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_LOW, fan_speed == 1 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_MEDIUM, fan_speed == 2 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_MEDIUM, fan_speed == 2 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_HIGH, fan_speed == 3 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_HIGH, fan_speed == 3 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_ACTIVE_LOCKED : LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_INACTIVE); this->sendStopBytes(); this->giveSerialMutex(); } else { // When the display is not locked // the state picture set we use is the unlocked state picture set this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_STATE, state ? LCD_DASHBOARD_PIC_AC_STATE_ON : LCD_DASHBOARD_PIC_AC_STATE_OFF); this->sendStopBytes(); // When pressed, the state picture set should change this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_STATE, state ? LCD_DASHBOARD_PIC_AC_STATE_ON_PRESSED : LCD_DASHBOARD_PIC_AC_STATE_OFF_PRESSED); this->sendStopBytes(); // Set Alpha of Locked Icon to 0 this->displayAdapter->printf("%s.aph=%d", LCD_DASHBOARD_ELEMENT_NAME_ICO_LOCK, 0); this->sendStopBytes(); // Hide the ac container overlay this->displayAdapter->printf("vis %s,0", LCD_DASHBOARD_ELEMENT_NAME_AC_PANEL_OVERLAY); this->sendStopBytes(); // Show the temperature adjustment buttons this->displayAdapter->printf("vis %s,1", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMP_UP_BUTTON); this->sendStopBytes(); this->displayAdapter->printf("vis %s,1", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMP_DOWN_BUTTON); this->sendStopBytes(); // Draw the mode picture set this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_COOL, drawn_mode == 2 ? (LCD_DASHBOARD_PIC_AC_MODE_COOL_ACTIVE) : LCD_DASHBOARD_PIC_AC_MODE_COOL_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_COOL, drawn_mode == 2 ? LCD_DASHBOARD_PIC_AC_MODE_COOL_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_MODE_COOL_INACTIVE_PRESS); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_FAN, drawn_mode == 1 ? LCD_DASHBOARD_PIC_AC_MODE_FAN_ACTIVE : LCD_DASHBOARD_PIC_AC_MODE_FAN_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_MODE_FAN, drawn_mode == 1 ? LCD_DASHBOARD_PIC_AC_MODE_FAN_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_MODE_FAN_INACTIVE_PRESS); this->sendStopBytes(); this->giveSerialMutex(); // Draw fan speed picture set this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_AUTO, fan_speed == 0 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_ACTIVE : LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_AUTO, fan_speed == 0 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_FAN_SPEED_AUTO_INACTIVE_PRESS); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_LOW, fan_speed == 1 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_ACTIVE : LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_LOW, fan_speed == 1 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_FAN_SPEED_LOW_INACTIVE_PRESS); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_MEDIUM, fan_speed == 2 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_ACTIVE : LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_MEDIUM, fan_speed == 2 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_FAN_SPEED_MEDIUM_INACTIVE_PRESS); this->sendStopBytes(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_HIGH, fan_speed == 3 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_ACTIVE : LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_INACTIVE); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_AC_FAN_SPEED_HIGH, fan_speed == 3 ? LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_ACTIVE_PRESS : LCD_DASHBOARD_PIC_AC_FAN_SPEED_HIGH_INACTIVE_PRESS); this->sendStopBytes(); this->giveSerialMutex(); } // Draw the fan speed picture set // Draw the temperature this->takeSerialMutex(); this->displayAdapter->printf("%s.txt=\"%d\"", LCD_DASHBOARD_ELEMENT_NAME_AC_TEMPERATURE, temperature); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::refresh_display_allsystem() { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_ALL_SYSTEM_TOGGLE, this->get_system_state() ? LCD_DASHBOARD_PIC_ALL_SYSTEM_TOGGLE_ON : LCD_DASHBOARD_PIC_ALL_SYSTEM_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->printf("%s.pic2=%d", LCD_DASHBOARD_ELEMENT_NAME_ALL_SYSTEM_TOGGLE, this->get_system_state() ? LCD_DASHBOARD_PIC_ALL_SYSTEM_TOGGLE_ON_PRESSED : LCD_DASHBOARD_PIC_ALL_SYSTEM_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void CUDDisplay::refresh_display_socket() { this->takeSerialMutex(); this->displayAdapter->printf("%s.pic=%d", LCD_DASHBOARD_ELEMENT_NAME_SOCKET_POWER, this->cards.outputCard->getState(this->conf->socket_contactor_pin) ? LCD_DASHBOARD_PIC_SOCKET_POWER_ON : LCD_DASHBOARD_PIC_SOCKET_POWER_OFF); this->sendStopBytes(); this->giveSerialMutex(); } bool CUDDisplay::get_system_state() { // The system state is defined to be on when any of the lights, fans, air purifier, mosquito zapper or AC is on return this->get_lights_state() || this->get_fans_state() || this->cards.outputCard->getState(this->conf->air_purifier_pin) || this->cards.outputCard->getState(this->conf->mosquito_zapper_pin) || this->cards.ac->getMode() != 0; } void CUDDisplay::system_toggle() { // If the system is on, turn everything off if it is on if (this->get_system_state()) { for (int i = 0; i < 4; i++) { if (this->cards.outputCard->getState(this->conf->light_pins[i])) this->cards.outputCard->setState(this->conf->light_pins[i], false); } for (int i = 0; i < 3; i++) { if (this->cards.outputCard->getState(this->conf->fan_pins[i])) this->cards.outputCard->setState(this->conf->fan_pins[i], false); } if (this->cards.outputCard->getState(this->conf->air_purifier_pin)) this->cards.outputCard->setState(this->conf->air_purifier_pin, false); if (this->cards.outputCard->getState(this->conf->mosquito_zapper_pin)) this->cards.outputCard->setState(this->conf->mosquito_zapper_pin, false); if (!get_ac_lock() && this->cards.ac->getMode() != 0) this->cards.ac->setMode(0); } // If the system is off, turn lights, mosquito zapper, air purifier and AC on if they are off else { for (int i = 0; i < 4; i++) { if (!this->cards.outputCard->getState(this->conf->light_pins[i])) this->cards.outputCard->setState(this->conf->light_pins[i], true); } if (!this->cards.outputCard->getState(this->conf->mosquito_zapper_pin)) this->cards.outputCard->setState(this->conf->mosquito_zapper_pin, true); if (!this->cards.outputCard->getState(this->conf->air_purifier_pin)) this->cards.outputCard->setState(this->conf->air_purifier_pin, true); if (!get_ac_lock()) this->cards.ac->setMode(previous_mode); } } void CUDDisplay::set_ac_lock(bool state) { ac_lock.setIntValue((bool)state); this->refresh_display_ac(); } bool CUDDisplay::get_ac_lock() { if (standalone) { return false; } return (bool)ac_lock.getIntValue(); } uint8_t CUDDisplay::get_ac_temp_lower_bound() { if (standalone) { return AC_MIN_TEMP; } return ac_temp_lower_bound.getIntValue(); } uint8_t CUDDisplay::get_ac_temp_upper_bound() { if (standalone) { return AC_MAX_TEMP; } return ac_temp_upper_bound.getIntValue(); }