#include ISEDisplay::ISEDisplay(HardwareSerial *adapter, const uint8_t *light_array, uint8_t row, uint8_t column) : ESPMegaDisplay(adapter, 115200, 912600, 4, 17) { this->light_array = light_array; this->row = row; this->column = column; } void ISEDisplay::begin(DigitalInputCard *inputCard, DigitalOutputCard *outputCard, ClimateCard *climateCard_daikin, ClimateCard *climateCard_york, RemoteVariable *pm_switch, RemoteVariable *pm_fan_speed, RemoteVariable *ac_lock, RemoteVariable *pm_lock) { this->inputCard = inputCard; this->outputCard = outputCard; this->climateCard_daikin = climateCard_daikin; this->climateCard_york = climateCard_york; this->pm_switch = pm_switch; this->pm_lock = pm_lock; this->ac_lock = ac_lock; this->remote_pm_fan_speed = pm_fan_speed; auto bindedHandlePWMChange = std::bind(&ISEDisplay::handlePWMChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto bindedHandleACChange = std::bind(&ISEDisplay::handleACChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto bindedHandleTouch = std::bind(&ISEDisplay::handleTouch, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); this->outputCallbackHandle = this->outputCard->registerChangeCallback(bindedHandlePWMChange); this->climateCallbackHandle = this->climateCard_daikin->registerChangeCallback(bindedHandleACChange); // this->climateCallbackHandle = this->climateCard_york->registerChangeCallback(bindedHandleACChange); this->user_mode = 2; // initialized to cool by default this->ac_lock_state = strcmp(ac_lock->getValue(), "on") == 0;// initialized to get value this->pm_lock_state = strcmp(pm_lock->getValue(), "on") == 0; // initialized to get value this->pm_fan_speed = 10; // remote_pm_fan_speed->setValue(pm_fan_speed); this->ac_fan_speed = 0; this->ac_mode = 0; this->ac_temperature = 25; this->lightLevelRow1 = 0; this->lightLevelRow2 = 0; this->lightLevelRow3 = 0; this->lightLevelRow4 = 0; this->time_since_last_ac_change = 0; this->ac_press_pending = false; // this->time_since_last_screen_update = 0; this->registerTouchCallback(bindedHandleTouch); this->reset(); delay(1000); // first jump to main then if no activity jump to standby this->jumpToPage(2); // change this back later to 2 delay(100); this->updateAirPurifierState(); this->updateSystemtoggle(); this->updateACState(); this->updateLightGroupStatePageDashboard(); // intialize AC state if(ac_lock_state == false) { setACstate(ac_fan_speed, ac_mode, ac_temperature); // default to off with temp 25 and fan on Auto } } void ISEDisplay::loop() { // Check if there is data in the serial buffer // If there is data, process the data recieveSerialCommand(); // Check if the AC state has been changed if (ac_press_pending && (millis() - time_since_last_ac_change) > 5000) { sendACIRcode(); ac_press_pending = false; } // Check if the MQTT connection has been lost 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("ISE Display", "Checking MQTT Connection, Connection is %s", this->cards.iot->mqttConnected() ? "true" : "false"); if (!this->iot->mqttConnected()) { if (first_disconnect) { // When MQTT is disconnected, enter standalone mode // A/C lock is lifted // PM lock are lifted this->ac_lock_state = false; this->pm_lock_state = false; first_disconnect = false; } } else { if (first_disconnect == false) { // When MQTT is connected, exit standalone mode // In standalone mode, socket contactor is turned off // A/C lock is set first_disconnect = true; this->ac_lock_state = strcmp(ac_lock->getValue(), "on") == 0; this->pm_lock_state = strcmp(pm_lock->getValue(), "on") == 0; updateACState(); updateAirPurifierState(); } } last_mqtt_connected_check = millis(); } } void ISEDisplay::handleTouch(uint8_t page, uint8_t component, uint8_t touch_type) { ESP_LOGD("ISEDisplay", "Touch detected on page %d, component %d, touch type %d", page, component, touch_type); char buffer[4]; if (page == PAGE_STANDBY) { switch (component) { case COMPONENT_OBJ_STANDBY_BTN_OPEN_ALL_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; allOn(); this->jumpToPage(2); // the function of the button is to open the dashboard from standby break; case COMPONENT_OBJ_STANDBY_BTN_LIGHT_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightGroupStateStandby(); break; case COMPONENT_OBJ_STANDBY_BTN_AC_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleAC(); break; case COMPONENT_OBJ_STANDBY_BTN_PM_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; togglePMStandby(); break; default: break; } } else if (page == PAGE_DASHBOARD) { switch (component) { case COMPONENT_OBJ_DASHBOARD_NUM_AC_TEMP: break; case COMPONENT_OBJ_DASHBOARD_BTN_AC_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; //if ac_lock is true do nothing if (strcmp(ac_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); break; toggleAC(); break; case COMPONENT_OBJ_DASHBOARD_BTN_AC_MODE: if (touch_type != TOUCH_TYPE_RELEASE) break; //if ac_lock is true do nothing if (strcmp(ac_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); break; changeUserACmode(); break; case COMPONENT_OBJ_DASHBOARD_BTN_AC_FAN_SPEED: if (touch_type != TOUCH_TYPE_RELEASE) break; //if ac_lock is true do nothing if (strcmp(ac_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); break; ac_fan_speed = this->climateCard_daikin->getFanSpeed(); // mode= auto, high, mid, low ESP_LOGI("ISEDisplay", "Current AC fan speed: %d", ac_fan_speed); ac_fan_speed = (ac_fan_speed + 1) % 4; ESP_LOGI("ISEDisplay", "New AC fan speed: %d", ac_fan_speed); setACstate(ac_fan_speed, ac_mode, ac_temperature); break; case COMPONENT_OBJ_DASHBOARD_BTN_AC_TEMP_MINUS: if (touch_type != TOUCH_TYPE_RELEASE) break; //if ac_lock is true do nothing if (strcmp(ac_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); break; ac_temperature = this->climateCard_daikin->getTemperature() - 1; setACstate(ac_fan_speed, ac_mode, ac_temperature); break; case COMPONENT_OBJ_DASHBOARD_BTN_AC_TEMP_PLUS: if (touch_type != TOUCH_TYPE_RELEASE) break; //if ac_lock is true do nothing if (strcmp(ac_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); break; ac_temperature = this->climateCard_daikin->getTemperature() + 1; setACstate(ac_fan_speed, ac_mode, ac_temperature); break; case COMPONENT_OBJ_DASHBOARD_BTN_PM_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; //if pm_lock is true do nothing if (strcmp(pm_lock->getValue(), "on") == 0) ESP_LOGI("ISEDisplay", "PM lock is on, do nothing"); break; togglePM(); break; case COMPONENT_OBJ_DASHBOARD_TXT_PM_INSIDE: break; case COMPONENT_OBJ_DASHBOARD_TXT_PM_OUTSIDE: break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_LIGHT_ROW1: break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_LIGHT_ROW2: break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_LIGHT_ROW3: break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_LIGHT_ROW4: break; case COMPONENT_OBJ_DASHBOARD_BTN_LIGHT_ROW1: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightIndividual(1); break; case COMPONENT_OBJ_DASHBOARD_BTN_LIGHT_ROW2: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightIndividual(2); break; case COMPONENT_OBJ_DASHBOARD_BTN_LIGHT_ROW3: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightIndividual(3); break; case COMPONENT_OBJ_DASHBOARD_BTN_LIGHT_ROW4: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightIndividual(4); break; case COMPONENT_OBJ_DASHBOARD_TIMER_TEN_SEC: break; case COMPONENT_OBJ_DASHBOARD_VAL_TIME_PAST: break; case COMPONENT_OBJ_DASHBOARD_TIMER_INACTIVE_CHECK: break; case COMPONENT_OBJ_DASHBOARD_BTN_SYSTEM_TOGGLE: if (touch_type != TOUCH_TYPE_RELEASE) break; // implement system toggle // check light on or off // check ac on or off // check pm on or off toggleSystem(); break; case COMPONENT_OBJ_DASHBOARD_BTN_PM_SPEED: if (touch_type != TOUCH_TYPE_RELEASE) break; // implement pm speed change break; case COMPONENT_OBJ_DASHBOARD_BTN_PM_MODE: if (touch_type != TOUCH_TYPE_RELEASE) break; // implement pm mode change break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_MASTER_LIGHT: break; case COMPONENT_OBJ_DASHBOARD_LOGO: break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_PM_LOCK: if (touch_type != TOUCH_TYPE_RELEASE) break; // toggle_pm_lock(); break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_AC_LOCK: if (touch_type != TOUCH_TYPE_RELEASE) break; // toggle_ac_lock(); break; case COMPONENT_OBJ_DASHBOARD_BTN_LIGHT_MASTER: if (touch_type != TOUCH_TYPE_RELEASE) break; toggleLightGroupState(); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_MASTER_LV1: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightGroupState(1); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_MASTER_LV2: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightGroupState(2); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_MASTER_LV3: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightGroupState(3); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW1_LV1: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(1, 1); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW1_LV2: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(1, 2); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW1_LV3: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(1, 3); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW2_LV1: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(2, 1); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW2_LV2: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(2, 2); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW2_LV3: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(2, 3); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW3_LV1: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(3, 1); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW3_LV2: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(3, 2); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW3_LV3: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(3, 3); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW4_LV1: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(4, 1); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW4_LV2: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(4, 2); break; case COMPONENT_OBJ_DASHBOARD_HOTSPOT_LIGHT_ROW4_LV3: if (touch_type != TOUCH_TYPE_RELEASE) break; setLightLevel(4, 3); break; case COMPONENT_OBJ_DASHBOARD_HOLDER_PIC_C_DEGREE: break; default: break; } } else { return; } } void ISEDisplay::handlePWMChange(uint8_t pin, bool state, uint16_t value) { // NEED to switch case for different page uint8_t current_page = this->currentPage; // uint8_t first_pin = *(light_array); // uint8_t last_pin = *(light_array + 7); if (current_page == PAGE_STANDBY) { if (LIGHT_ROW1_COLUMN1 || LIGHT_ROW1_COLUMN2 || LIGHT_ROW2_COLUMN1 || LIGHT_ROW2_COLUMN2 || LIGHT_ROW3_COLUMN1 || LIGHT_ROW3_COLUMN2 || LIGHT_ROW4_COLUMN1 || LIGHT_ROW4_COLUMN2) // change { // Light updateLightGroupStatePageStandby(); // time_since_last_screen_update = millis(); // update time since last activity } } else if (current_page == PAGE_DASHBOARD) { if (LIGHT_ROW1_COLUMN1 || LIGHT_ROW1_COLUMN2 || LIGHT_ROW2_COLUMN1 || LIGHT_ROW2_COLUMN2 || LIGHT_ROW3_COLUMN1 || LIGHT_ROW3_COLUMN2 || LIGHT_ROW4_COLUMN1 || LIGHT_ROW4_COLUMN2) // change { // Light updateLightGroupStatePageDashboard(); // time_since_last_screen_update = millis(); // update time since last activity } } else { return; } } void ISEDisplay::updateDateTimeText(rtctime_t time) { if (!this->takeSerialMutex()) return; // Send the time to the display this->displayAdapter->printf("time.txt=\"%02d:%02d\"", time.hours, time.minutes); this->sendStopBytes(); this->displayAdapter->printf("date.txt=\"%02d.%02d.%d\"", time.day, time.month, time.year); this->sendStopBytes(); this->giveSerialMutex(); } // TODO : Implement // user remote var // appdeamon // void ISEDisplay::updateTempOutside(float temp_outside) // { // // TODO : use remotevar to get PM2.5 data from appdaemon and update the display // // change temp_outside to int then display // u_int8_t temp_outside_int = (u_int8_t)temp_outside; // ESP_LOGI("ISEDisplay", "Updating temperature outside to: %d", temp_outside_int); // if (!this->takeSerialMutex()) // return; // this->displayAdapter->printf("outside_temp.txt=\"%d\"", temp_outside_int); // this->sendStopBytes(); // this->giveSerialMutex(); // } void ISEDisplay::updatePMoutside(u_int16_t pm25_outside) { ESP_LOGI("ISEDisplay", "Updating PM2.5 outside to: %d", pm25_outside); u_int16_t curPage = this->currentPage; if (curPage == 2) { if (!this->takeSerialMutex()) return; this->displayAdapter->printf("pm_out.txt=\"%d\"", pm25_outside); this->sendStopBytes(); this->giveSerialMutex(); } // TODO : use remotevar to get PM2.5 data from appdaemon and update the display } void ISEDisplay::updatePMinside(u_int16_t pm25_inside) { // TODO : get data from HA's Xiaomi air purifier sensor ESP_LOGI("ISEDisplay", "Updating PM2.5 inside to: %d", pm25_inside); u_int16_t curPage = this->currentPage; if (curPage == 2) { if (!this->takeSerialMutex()) return; this->displayAdapter->printf("pm_in.txt=\"%d\"", pm25_inside); this->sendStopBytes(); this->giveSerialMutex(); } } void ISEDisplay::setPMstate(bool is_pm_on, uint8_t pm_fan_speed) { ESP_LOGI("ISEDisplay", "Setting PM state: %d, fan speed: %d", is_pm_on, pm_fan_speed); char buffer[4]; itoa(pm_fan_speed, buffer, DEC); remote_pm_fan_speed->setValue(buffer); pm_switch->setValue(is_pm_on ? "on" : "off"); } void ISEDisplay::setPMlockstate(bool is_pm_lock_on) { ESP_LOGI("ISEDisplay", "Setting PM lock state: %d", is_pm_lock_on); pm_lock->setValue(is_pm_lock_on ? "on" : "off"); } void ISEDisplay::setAClockstate(bool is_ac_lock_on) { ESP_LOGI("ISEDisplay", "Setting AC lock state: %d", is_ac_lock_on); ac_lock->setValue(is_ac_lock_on ? "on" : "off"); } void ISEDisplay::setACstate(uint8_t ac_fan_speed, uint8_t ac_mode, uint8_t ac_temperature) { ESP_LOGI("ISEDisplay", "Setting AC state in memory to: = fan speed: %d, mode: %d, temperature: %d", ac_fan_speed, ac_mode, ac_temperature); this->ac_fan_speed = ac_fan_speed; this->ac_mode = ac_mode; this->ac_temperature = ac_temperature; this->time_since_last_ac_change = millis(); this->ac_press_pending = true; updateACState(); } void ISEDisplay::sendACIRcode() { uint8_t cur_ac_fan_speed = this->ac_fan_speed; uint8_t cur_ac_mode = this->ac_mode; uint8_t cur_ac_temperature = this->ac_temperature; uint8_t york_temp = cur_ac_temperature; // this->climateCard->setFanSpeed(ac_fan_speed); ESP_LOGI("ISEDisplay", "AC fan speed set to: %d", cur_ac_fan_speed); // this->climateCard->setMode(ac_mode); ESP_LOGI("ISEDisplay", "AC mode set to: %d", cur_ac_mode); // this->climateCard->setTemperature(ac_temperature); ESP_LOGI("ISEDisplay", "AC temperature set to: %d", cur_ac_temperature); // check if temp is within range of min and max for york if not set an min or max for only york this->climateCard_daikin->setState(cur_ac_mode, cur_ac_fan_speed, cur_ac_temperature); if (cur_ac_temperature < YORK_MIN_TEMP) { york_temp = YORK_MIN_TEMP; } else if (cur_ac_temperature > YORK_MAX_TEMP) { york_temp = YORK_MAX_TEMP; } if (ac_mode == 3) { this->climateCard_york->setState(0, cur_ac_fan_speed, york_temp); } else { this->climateCard_york->setState(cur_ac_mode, cur_ac_fan_speed, york_temp); } } void ISEDisplay::toggleLightGroupState() { // Get the current group state bool state = calculateLightGroupState(); ESP_LOGI("ISEDisplay", "Current light group state: %d", state); // Toggle light for (uint8_t i = 1; i <= 4; i++) { setLightLevel(i, state ? 0 : 3); } } void ISEDisplay::setLightGroupState(uint8_t level) { // Get the current group state ESP_LOGI("ISEDisplay", "Current light group state: %d", level); // Toggle light for (uint8_t i = 1; i <= 4; i++) { setLightLevel(i, level); } } void ISEDisplay::toggleLightGroupStateStandby() { // Get the current group state bool state = calculateLightGroupState(); ESP_LOGI("ISEDisplay", "Current light group state: %d", state); // Toggle light for (uint8_t i = 1; i <= 4; i++) { setLightLevel(i, state ? 0 : 3); } // updateLightGroupStatePageStandby(); } void ISEDisplay::togglePM() { // Get the current group state bool state = strcmp(pm_switch->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "Current PM state: %d", state); // Toggle the state pm_switch->setValue(state ? "off" : "on"); ESP_LOGI("ISEDisplay", "New PM state: %d", state); // updateAirPurifierState(); } void ISEDisplay::toggleACLock() { // Get the current group state bool state = strcmp(ac_lock->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "Current AC lock state: %d", state); // Toggle the state ac_lock->setValue(state ? "off" : "on"); ESP_LOGI("ISEDisplay", "New AC lock state: %d", state); // updateAirPurifierStateStandby(); } void ISEDisplay::togglePMLock() { // Get the current group state bool state = strcmp(pm_lock->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "Current PM lock state: %d", state); // Toggle the state pm_lock->setValue(state ? "off" : "on"); ESP_LOGI("ISEDisplay", "New PM lock state: %d", state); // updateAirPurifierStateStandby(); } void ISEDisplay::togglePMStandby() { // Get the current group state bool state = strcmp(pm_switch->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "Current PM state: %d", state); // Toggle the state pm_switch->setValue(state ? "off" : "on"); ESP_LOGI("ISEDisplay", "New PM state: %d", state); // updateAirPurifierStateStandby(); } void ISEDisplay::toggleAC() { // Get the current group state uint8_t mode = this->climateCard_daikin->getMode(); // get fan speed and temperature uint8_t fan_speed = this->climateCard_daikin->getFanSpeed(); uint8_t temperature = this->climateCard_daikin->getTemperature(); ESP_LOGI("ISEDisplay", "Current AC mode: %d", mode); // Toggle the state if (mode == 0) { ESP_LOGI("ISEDisplay", " User mode: %d", user_mode); setACstate(fan_speed, user_mode, temperature); } else { ESP_LOGI("ISEDisplay", "User mode BEFORE: %d", user_mode); // update user mode to new mode user_mode = mode; // change actual mode to off ESP_LOGI("ISEDisplay", "User mode AFTER: %d", user_mode); setACstate(fan_speed, 0, temperature); } } void ISEDisplay::changeUserACmode() { // Get the current group state uint8_t mode = this->climateCard_daikin->getMode(); ESP_LOGI("ISEDisplay", "Current actual AC mode: %d", mode); // Toggle the state // user mode alternate between 1 and 2 ESP_LOGI("ISEDisplay", "User mode BEFORE: %d", user_mode); user_mode = (user_mode) % 2 + 1; ESP_LOGI("ISEDisplay", "User mode AFTER: %d", user_mode); if (mode != 0) { // update mode to new mode mode = user_mode; ESP_LOGI("ISEDisplay", "change actual AC mode to user mode: %d", mode); } else { // ie mode is off // do nothing as the state is keep in user_mode // the mode will change to user_mode when turn on by toggleAC() ESP_LOGI("ISEDisplay", "do nothing; user mode: %d , actual mode: %d", user_mode, mode); } updateuserACmode(); // call to update mode part of the display seperately } void ISEDisplay::setLightLevel(uint8_t row, uint8_t level) { // Set the light level // this->outputCard->setValue(row, level); // only value between 1 and 4 is valid ESP_LOGI("ISEDisplay", "Setting light level for row %d to %d", row, level); uint8_t primary_pin = *(light_array + 2 * (row - 1)); uint8_t secondary_pin = *(light_array + 2 * (row - 1) + 1); ESP_LOGI("ISEDisplay", "Primary pin: %d, Secondary pin: %d", primary_pin, secondary_pin); bool primary = false; bool secondary = false; switch (level) { case 0: primary = false; secondary = false; ESP_LOGI("ISEDisplay", "Primary pin is %d, Secondary pin is %d", primary, secondary); break; case 1: primary = false; secondary = true; ESP_LOGI("ISEDisplay", "Primary pin is %d, Secondary pin is %d", primary, secondary); break; case 2: primary = true; secondary = false; ESP_LOGI("ISEDisplay", "Primary pin is %d, Secondary pin is %d", primary, secondary); break; case 3: primary = true; secondary = true; ESP_LOGI("ISEDisplay", "Primary pin is %d, Secondary pin is %d", primary, secondary); break; default: ESP_LOGE("ISEDisplay", "Invalid light level: %d", level); break; } this->outputCard->setState(primary_pin, primary); this->outputCard->setState(secondary_pin, secondary); ESP_LOGI("ISEDisplay", "Light level set for row %d", row); } u_int8_t ISEDisplay::getLightLevel(uint8_t row) { u_int8_t lightLevel = 0; ESP_LOGI("ISEDisplay", "Getting light level for row %d", row); // lightLevel = this->outputCard->getValue(row); // row can only be between 1 and 4 uint8_t primary_pin = *(light_array + 2 * (row - 1)); uint8_t secondary_pin = *(light_array + 2 * (row - 1) + 1); ESP_LOGI("ISEDisplay", "Primary pin: %d, Secondary pin: %d", primary_pin, secondary_pin); bool primary = this->outputCard->getState(primary_pin); bool secondary = this->outputCard->getState(secondary_pin); ESP_LOGI("ISEDisplay", "Primary pin state: %d, Secondary pin state: %d", primary, secondary); if (primary && secondary) { lightLevel = 3; } else if (primary) { lightLevel = 2; } else if (secondary) { lightLevel = 1; } else { lightLevel = 0; } ESP_LOGI("ISEDisplay", "Light level for row %d is %d", row, lightLevel); return lightLevel; } // change to light with the assignment lightPosition ISEDisplay::getRowCol(uint8_t pin) { lightPosition position; // uint8_t row = this->row; // uint8_t column = this->column; // const uint8_t *light_array = this->light_array; // should return the row and column of the light from pin in a row by column array pointer pass from main using pointer arithmetic for (uint8_t i = 0; i < row * column; i++) { uint8_t value = *(light_array + i); if (value == pin) { position.row = i / column; position.column = i % column; return position; } } return position; } void ISEDisplay::updateLightGroupStatePageStandby() { // Calculate the state bool state = calculateLightGroupState(); // Send the state to the display if (!this->takeSerialMutex()) return; this->displayAdapter->print("s_light_toggle.pic="); this->displayAdapter->print(state ? COMPONENT_STANDBY_PIC_LIGHT_TOGGLE_ON : COMPONENT_STANDBY_PIC_LIGHT_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("s_light_toggle.pic2="); this->displayAdapter->print(state ? COMPONENT_STANDBY_PIC_LIGHT_TOGGLE_ON_PRESSED : COMPONENT_STANDBY_PIC_LIGHT_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void ISEDisplay::updateLightGroupStatePageDashboard() { // Calculate the state bool state = calculateLightGroupState(); // Send the state to the display if (!this->takeSerialMutex()) return; this->displayAdapter->print("light_m_sw.pic="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_LIGHT_MASTER_ON : COMPONENT_DASHBOARD_PIC_LIGHT_MASTER_OFF); this->sendStopBytes(); this->displayAdapter->print("light_m_sw.pic2="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_LIGHT_MASTER_ON_PRESSED : COMPONENT_DASHBOARD_PIC_LIGHT_MASTER_OFF_PRESSED); this->sendStopBytes(); for (uint8_t i = 1; i <= 4; i++) { u_int8_t state = getLightLevel(i); switch (state) { case 0: this->displayAdapter->print("light_row"); this->displayAdapter->print(i); this->displayAdapter->print(".pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_LIGHT_ROW_LEVEL_0); this->sendStopBytes(); break; case 1: this->displayAdapter->print("light_row"); this->displayAdapter->print(i); this->displayAdapter->print(".pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_LIGHT_ROW_LEVEL_1); this->sendStopBytes(); break; case 2: this->displayAdapter->print("light_row"); this->displayAdapter->print(i); this->displayAdapter->print(".pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_LIGHT_ROW_LEVEL_2); this->sendStopBytes(); break; case 3: this->displayAdapter->print("light_row"); this->displayAdapter->print(i); this->displayAdapter->print(".pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_LIGHT_ROW_LEVEL_3); this->sendStopBytes(); break; default: break; } } this->giveSerialMutex(); } bool ISEDisplay::calculateLightGroupState() { // Check if all lights are on bool lightOn = false; // uint_8 first_pin = *(light_array); // uint_8 last_pin = *(light_array + 7); for (uint8_t i = 1; i <= 4; i++) { if (getLightLevel(i) != 0) { lightOn = true; break; } } return lightOn; } bool ISEDisplay::calculateAllState() { bool lightState = calculateLightGroupState(); bool pmState = strcmp(pm_switch->getValue(), "on") == 0; bool acState = false; if (ac_mode != 0) { acState = true; } return lightState || pmState || acState; } void ISEDisplay::toggleSystem() { toggleLightGroupState(); //check for ac lock and pm lock, if lock is on do nothing if (strcmp(ac_lock->getValue(), "on") == 0) { ESP_LOGI("ISEDisplay", "AC lock is on, do nothing"); } else { toggleAC(); } if (strcmp(pm_lock->getValue(), "on") == 0) { ESP_LOGI("ISEDisplay", "PM lock is on, do nothing"); } else { togglePM(); } } void ISEDisplay::allOn() { setLightGroupState(3); setPMstate(true, pm_fan_speed); setACstate(ac_mode, ac_fan_speed, ac_temperature); } void ISEDisplay::toggleLightIndividual(uint8_t row) { // Get the current state uint8_t state = getLightLevel(row); if (state != 0) { state = 0; } else { state = 3; } // Set the state setLightLevel(row, state); } void ISEDisplay::updateSystemtoggle() { bool state = calculateAllState(); if (!this->takeSerialMutex()) return; this->displayAdapter->print("system_toggle.pic="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_SYSTEM_TOGGLE_ON : COMPONENT_DASHBOARD_PIC_SYSTEM_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("system_toggle.pic2="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_SYSTEM_TOGGLE_ON_PRESSED : COMPONENT_DASHBOARD_PIC_SYSTEM_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void ISEDisplay::updateAirPurifierStateStandby() { // Get the state bool state = strcmp(pm_switch->getValue(), "on") == 0; this->pm_lock_state = strcmp(pm_lock->getValue(), "on") == 0; // Send the state to the display if (!this->takeSerialMutex()) return; this->displayAdapter->print("s_pm_toggle.pic="); this->displayAdapter->print(state ? COMPONENT_STANDBY_PIC_AC_TOGGLE_ON : COMPONENT_STANDBY_PIC_AC_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("s_pm_toggle.pic2="); this->displayAdapter->print(state ? COMPONENT_STANDBY_PIC_AC_TOGGLE_ON_PRESSED : COMPONENT_STANDBY_PIC_AC_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } void ISEDisplay::updateAirPurifierState() { // check for page if (currentPage == PAGE_DASHBOARD) { ESP_LOGI("ISEDisplay", "Updating dashboard"); // Get the state bool state = strcmp(pm_switch->getValue(), "on") == 0; this->pm_lock_state = strcmp(pm_lock->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "Updating air purifier state to: %d", state); pm_fan_speed = (int)atof(remote_pm_fan_speed->getValue()); // Send the state to the display if (!this->takeSerialMutex()) return; this->displayAdapter->print("pm_sw.pic="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_PM_TOGGLE_ON : COMPONENT_DASHBOARD_PIC_PM_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("pm_sw.pic2="); this->displayAdapter->print(state ? COMPONENT_DASHBOARD_PIC_PM_TOGGLE_ON_PRESSED : COMPONENT_DASHBOARD_PIC_PM_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->displayAdapter->print("pm_lock.pic="); this->displayAdapter->print(this->pm_lock_state ? COMPONENT_DASHBOARD_PIC_LOCK : COMPONENT_DASHBOARD_PIC_UNLOCK); this->sendStopBytes(); // this->displayAdapter->print("pm_speed.val="); // this->displayAdapter->print(pm_fan_speed); // // this->displayAdapter->print("\""); // this->sendStopBytes(); // this->displayAdapter->print("pm_speed.pco="); // this->displayAdapter->print(state ? 34486 : 33841); // this->sendStopBytes(); this->giveSerialMutex(); } else if (currentPage == PAGE_STANDBY) { ESP_LOGI("ISEDisplay", "Updating standby"); updateAirPurifierStateStandby(); } } void ISEDisplay::handleACChange(uint8_t mode, uint8_t fan_speed, uint8_t temperature) { ESP_LOGI("ISEDisplay", "AC state changed: mode: %d, fan speed: %d, temperature: %d", mode, fan_speed, temperature); updateACState(); } void ISEDisplay::updateuserACmode() { uint8_t mode = this->climateCard_daikin->getMode(); if (!this->takeSerialMutex()) return; ESP_LOGI("ISEDisplay", "updating display user AC mode to: %d", user_mode); switch (user_mode) { case 1: if (mode == 0) { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_FAN_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_FAN_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_FAN_ON); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_FAN_ON_PRESSED); this->sendStopBytes(); } break; case 2: if (mode == 0) { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_COOL_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_COOL_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_COOL_ON); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_COOL_ON_PRESSED); this->sendStopBytes(); } break; case 3: if (mode == 0) { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_DRY_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_DRY_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_mode.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_DRY_ON); this->sendStopBytes(); this->displayAdapter->print("ac_mode.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_MODE_DRY_ON_PRESSED); this->sendStopBytes(); } break; default: break; } this->giveSerialMutex(); } void ISEDisplay::updateACfanSpeed() { uint8_t fan_speed = this->climateCard_daikin->getFanSpeed(); uint8_t mode = this->climateCard_daikin->getMode(); this->ac_lock_state = strcmp(ac_lock->getValue(), "on") == 0; ESP_LOGI("ISEDisplay", "updating display AC fan speed to: %d", fan_speed); if (!this->takeSerialMutex()) return; switch (fan_speed) { case 0: if (mode == 0) { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_AUTO_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_AUTO_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_AUTO_ON); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_AUTO_ON_PRESSED); this->sendStopBytes(); } break; case 1: if (mode == 0) { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_HIGH_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_HIGH_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_HIGH_ON); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_HIGH_ON_PRESSED); this->sendStopBytes(); } break; case 2: if (mode == 0) { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_MID_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_MID_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_MID_ON); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_MID_ON_PRESSED); this->sendStopBytes(); } break; case 3: if (mode == 0) { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_LOW_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_LOW_OFF_PRESSED); this->sendStopBytes(); } else { this->displayAdapter->print("ac_speed.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_LOW_ON); this->sendStopBytes(); this->displayAdapter->print("ac_speed.pic2="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_AC_FAN_LOW_ON_PRESSED); this->sendStopBytes(); } break; default: break; } this->giveSerialMutex(); } void ISEDisplay::updateACState() { // TODOlater : The cognitive complexity here is so high, maybe break up the method a bit? // Get the state uint8_t mode = this->climateCard_daikin->getMode(); uint8_t temperature = this->climateCard_daikin->getTemperature(); this->ac_lock_state = strcmp(ac_lock->getValue(), "on") == 0; if (currentPage != 1) { if (!this->takeSerialMutex()) return; // Send the state to the display if (mode == 0) { this->displayAdapter->print("ac_temp.pco="); this->displayAdapter->print(COMPONENT_COLOR_INACTIVE_GREY); this->sendStopBytes(); this->displayAdapter->print("c_degree.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_DEGREE_C_OFF); this->sendStopBytes(); } else { this->displayAdapter->print("ac_temp.pco="); this->displayAdapter->print(COMPONENT_COLOR_ACTIVE_BLUE); this->sendStopBytes(); this->displayAdapter->print("c_degree.pic="); this->displayAdapter->print(COMPONENT_DASHBOARD_PIC_DEGREE_C_ON); this->sendStopBytes(); user_mode = mode; } this->displayAdapter->print("ac_sw.pic="); this->displayAdapter->print(mode != 0 ? COMPONENT_DASHBOARD_PIC_AC_TOGGLE_ON : COMPONENT_DASHBOARD_PIC_AC_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("ac_sw.pic2="); this->displayAdapter->print(mode != 0 ? COMPONENT_DASHBOARD_PIC_AC_TOGGLE_ON_PRESSED : COMPONENT_DASHBOARD_PIC_AC_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->displayAdapter->print("ac_lock.pic="); this->displayAdapter->print(this->ac_lock_state ? COMPONENT_DASHBOARD_PIC_LOCK : COMPONENT_DASHBOARD_PIC_UNLOCK); this->sendStopBytes(); this->giveSerialMutex(); updateuserACmode(); updateACfanSpeed(); if (!this->takeSerialMutex()) return; this->displayAdapter->print("ac_temp.val="); this->displayAdapter->print(temperature); // this->displayAdapter->print("\""); this->sendStopBytes(); this->giveSerialMutex(); } else if (currentPage == 1) { if (!this->takeSerialMutex()) return; this->displayAdapter->print("s_ac_toggle.pic="); this->displayAdapter->print(mode != 0 ? COMPONENT_STANDBY_PIC_AC_TOGGLE_ON : COMPONENT_STANDBY_PIC_AC_TOGGLE_OFF); this->sendStopBytes(); this->displayAdapter->print("s_ac_toggle.pic2="); this->displayAdapter->print(mode != 0 ? COMPONENT_STANDBY_PIC_AC_TOGGLE_ON_PRESSED : COMPONENT_STANDBY_PIC_AC_TOGGLE_OFF_PRESSED); this->sendStopBytes(); this->giveSerialMutex(); } ESP_LOGI("ISEDisplay", "display AC state updated"); }