#include // OS Configuration // #define FASTBOOT #define ESPMEGA_REV "ESPMega PRO R3.3b" // Network Connectivity char HOSTNAME[15]; IPAddress IP(0, 0, 0, 0); IPAddress SUBNET(0, 0, 0, 0); IPAddress GATEWAY(0, 0, 0, 0); IPAddress DNS(0, 0, 0, 0); IPAddress MQTT_SERVER(0, 0, 0, 0); uint16_t MQTT_PORT = 0; WebServer otaserver(80); bool standalone = true; // #define MQTT_BASE_TOPIC "/espmega/ProR3" char MQTT_BASE_TOPIC[20]; uint8_t base_topic_length = 0; char STATE_REQUEST_TOPIC[40]; // #define MQTT_USE_AUTH #ifdef MQTT_USE_AUTH const char MQTT_USERNAME[] = "username"; const char MQTT_PASSWORD[] = "password"; #endif uint8_t utc_offset = 7; float current_room_temp = 0; float current_room_humid = 0; // Inputs #define VINT_COUNT 16 const int DEBOUNCE_TIME_MS = 50; const int virtual_interrupt_pins[VINT_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; int virtual_interupt_state[VINT_COUNT]; unsigned long virtual_interupt_timer[VINT_COUNT]; // Outputs #define PWM_COUNT 16 const uint8_t pwm_pins[PWM_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; bool pwm_states[PWM_COUNT]; uint8_t pwm_states_eeprom[PWM_COUNT]; uint16_t pwm_values[PWM_COUNT]; uint8_t pwm_values_eeprom[PWM_COUNT * 2]; // output = m*input+c const float pwm_linear_scaling_m[PWM_COUNT] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; const float pwm_linear_scaling_c[PWM_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #define PWM_CYCLE_VALUES_COUNT 3 const int PWM_CYCLE_VALUES[PWM_CYCLE_VALUES_COUNT] = {50, 125, 255}; char PWM_SET_STATE_TOPIC[70]; char PWM_SET_VALUE_TOPIC[70]; // Infrared Transciever #define IR_RECIEVE_PIN 35 #define IR_SEND_PIN 17 #define MARK_EXCESS_MICROS 20 #define RAW_BUFFER_LENGTH 750 // LCD int lcd_current_page = 1; int lcd_pwmAdj_id = 0; EasyNex panel(Serial); // Air Conditioner Control /* Mode 0: Off, 1: Cool, 2: Fan Fan Speed 0: Auto, 1: High, 2: Mid, 3: Low */ #define DHT22_PIN 32 uint8_t ac_mode = 0; uint8_t ac_fan_speed = 0; uint8_t ac_temperature = 25; #define AC_MAX_TEMPERATURE 30 #define AC_MIN_TEMPERATURE 18 char AC_SET_MODE_TOPIC[75]; char AC_SET_FAN_TOPIC[75]; char AC_SET_TEMPERATURE_TOPIC[75]; char AC_MODE_TOPIC[75]; char AC_FAN_TOPIC[75]; char AC_TEMPERATURE_TOPIC[75]; char AC_ROOM_TEMPERATURE_TOPIC[75]; char AC_HUMIDITY_TOPIC[75]; // EEPROM ADDRESS #define EEPROM_ADDRESS_AC_MODE 0 // 01bytes #define EEPROM_ADDRESS_AC_TEMPERATURE 1 // 01bytes #define EEPROM_ADDRESS_AC_FAN_SPEED 2 // 01bytes #define EEPROM_ADDRESS_PWM_STATE 3 // 16bytes, thru 18 #define EEPROM_ADDRESS_PWM_VALUE 19 // 32bytes, thru 50 #define EEPROM_ADDRESS_HOSTNAME 65 // 15bytes, thru 79 #define EEPROM_ADDRESS_TOPIC 80 // 20bytes, thru 99 #define EEPROM_ADDRESS_IP 100 // 04bytes, thru 103 #define EEPROM_ADDRESS_SUBNET 104 // 04bytes, thru 107 #define EEPROM_ADDRESS_GATEWAY 108 // 04bytes, thru 111 #define EEPROM_ADDRESS_DNS 112 // 04bytes, thru 115 #define EEPROM_ADDRESS_MQTT_SERVER 116 // 04bytes, thru 119 #define EEPROM_ADDRESS_MQTT_PORT 120 // 02bytes, thru 121 char PWM_STATE_TOPIC[75]; char PWM_VALUE_TOPIC[75]; char INPUTS_TOPIC[75]; WiFiClient eth; PubSubClient mqtt_client(MQTT_SERVER, 1883, eth); PubSubClientTools mqtt(mqtt_client); DHTNEW env_sensor(DHT22_PIN); Thread mqtt_reconnector = Thread(); Thread environment_reporter = Thread(); Thread eeprom_pwm_updater = Thread(); Thread user_timer_tick = Thread(); StaticThreadController<4> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick); Thread top_bar_updater = Thread(); Thread page_updater = Thread(); StaticThreadController<2> lcd_thread_controller(&top_bar_updater, &page_updater); void setup() { Serial.begin(115200); #ifdef ENABLE_EXTERNAL_LCD Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2); #endif panel.begin(115200); Serial.println("ESPMega R3 Initializing"); ESPMega_begin(); io_begin(); eeprom_retrieve_init(); user_pre_init(); lcd_send_stop_bit(); lcd_init(); lcd_begin(); #ifdef ENABLE_EXTERNAL_LCD Serial2.print("rest"); Serial2.write(0xFF); Serial2.write(0xFF); Serial2.write(0xFF); #endif lcd_send_command("boot_state.txt=\"Core Initializing . . .\""); Serial.println("Initializing Infrared . . ."); lcd_send_command("boot_state.txt=\"Infrared Initializing . . .\""); IrReceiver.begin(IR_RECIEVE_PIN); IrSender.begin(IR_SEND_PIN); lcd_send_command("boot_state.txt=\"Network Initializing . . .\""); network_begin(); lcd_send_command("boot_state.txt=\"IoT Core Initializing . . .\""); mqtt_connect(); lcd_send_command("boot_state.txt=\"Threads Initializing . . .\""); thread_initialization(); ota_begin(); Serial.println("Initialization Completed."); Serial.println("Jumping to User Code."); user_init(); lcd_send_command("page dashboard"); } void loop() { virtual_interrupt_loop(); mqtt_client.loop(); ESPMega_loop(); ir_loop(); thread_controller.run(); lcd_loop(); user_loop(); otaserver.handleClient(); } void eeprom_retrieve_init() { // EEPROM Data Retrival ac_mode = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_MODE); ac_temperature = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_TEMPERATURE); ac_fan_speed = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_FAN_SPEED); // EEPROM Data Retrival Validation if (ac_mode > 2) { ac_mode = 0; ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_MODE, ac_mode); } if (ac_temperature > AC_MAX_TEMPERATURE || ac_temperature < AC_MIN_TEMPERATURE) { ac_temperature = AC_MAX_TEMPERATURE; ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_temperature); } if (ac_fan_speed > 3) { ac_fan_speed = 0; ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_fan_speed); } ac_set_state(ac_mode, ac_temperature, ac_fan_speed); ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_STATE, pwm_states_eeprom, 16); memcpy(pwm_states, pwm_states_eeprom, 16); ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_VALUE, pwm_values_eeprom, 32); memcpy(pwm_values, pwm_values_eeprom, 32); for (int i = 0; i < 15; i++) { if (pwm_states[i] <= 1) pwm_set_state(i, pwm_states[i]); else pwm_set_state(i, 0); if (pwm_values[i] <= 4095) pwm_set_value(i, pwm_values[i]); else pwm_set_value(i, 0); } IP = eeprom_ip_retrieve(EEPROM_ADDRESS_IP); SUBNET = eeprom_ip_retrieve(EEPROM_ADDRESS_SUBNET); GATEWAY = eeprom_ip_retrieve(EEPROM_ADDRESS_GATEWAY); DNS = eeprom_ip_retrieve(EEPROM_ADDRESS_DNS); MQTT_SERVER = eeprom_ip_retrieve(EEPROM_ADDRESS_MQTT_SERVER); eeprom_hostname_retrieve(); eeprom_mqtt_port_retrieve(); mqtt_client.setServer(MQTT_SERVER, MQTT_PORT); eeprom_basetopic_retrieve(); base_topic_length = strlen(MQTT_BASE_TOPIC) + 1; memcpy(STATE_REQUEST_TOPIC, MQTT_BASE_TOPIC, 20); strcat(STATE_REQUEST_TOPIC, "/requeststate"); memcpy(PWM_SET_STATE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(PWM_SET_STATE_TOPIC, "/pwm/00/set/state"); memcpy(PWM_SET_VALUE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(PWM_SET_VALUE_TOPIC, "/pwm/00/set/value"); memcpy(AC_SET_MODE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_SET_MODE_TOPIC, "/ac/set/mode"); memcpy(AC_SET_FAN_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_SET_FAN_TOPIC, "/ac/set/fan_speed"); memcpy(AC_SET_TEMPERATURE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_SET_TEMPERATURE_TOPIC, "/ac/set/temperature"); memcpy(AC_MODE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_MODE_TOPIC, "/ac/mode"); memcpy(AC_FAN_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_FAN_TOPIC, "/ac/fan_speed"); memcpy(AC_TEMPERATURE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_TEMPERATURE_TOPIC, "/ac/temperature"); memcpy(AC_ROOM_TEMPERATURE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_ROOM_TEMPERATURE_TOPIC, "/ac/room_temperature"); memcpy(AC_HUMIDITY_TOPIC, MQTT_BASE_TOPIC, 20); strcat(AC_HUMIDITY_TOPIC, "/ac/humidity"); memcpy(PWM_STATE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(PWM_STATE_TOPIC, "/pwm/00/state"); memcpy(PWM_VALUE_TOPIC, MQTT_BASE_TOPIC, 20); strcat(PWM_VALUE_TOPIC, "/pwm/00/value"); memcpy(INPUTS_TOPIC, MQTT_BASE_TOPIC, 20); strcat(INPUTS_TOPIC, "/input/00"); } void ota_begin() { otaserver.on("/", HTTP_GET, []() { otaserver.sendHeader("Connection", "close"); String otabuffer = ota_part1+HOSTNAME+ota_part2+IP.toString()+ota_part3+ETH.macAddress()+ota_part4+ESPMEGA_REV+ota_part5+MQTT_SERVER.toString()+ota_part6+String(MQTT_BASE_TOPIC)+ota_part7; if(standalone) otabuffer+=String("No"); else otabuffer+=String("Yes"); otabuffer+=ota_part8; otaserver.send(200, "text/html", otabuffer); }); otaserver.on( "/update", HTTP_POST, []() { otaserver.sendHeader("Connection", "close"); otaserver.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, []() { HTTPUpload &upload = otaserver.upload(); if (upload.status == UPLOAD_FILE_START) { lcd_send_command("page ota"); Serial.println(upload.currentSize); String otafiletxt = "Downloading File : " + upload.filename; lcd_send_stop_bit(); panel.writeStr("otatxt.txt", otafiletxt); Serial.printf("Update: %s\n", upload.filename.c_str()); if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { panel.writeStr("otatxt.txt", "Update Failed, Rebooting . . ."); Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_WRITE) { if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { panel.writeStr("otatxt.txt", "Update Failed, Rebooting . . ."); Update.printError(Serial); } if (upload.currentSize != 0 && upload.totalSize != 0) { lcd_send_stop_bit(); uint32_t totalsize_kb = upload.totalSize / 1000; uint32_t upload_pct = 100 * upload.totalSize / 1000000; String otafiletxt = "Downloading File : " + upload.filename + " (" + String(totalsize_kb) + "KB)"; panel.writeNum("prog.val", upload_pct); panel.writeStr("otatxt.txt", otafiletxt); } } else if (upload.status == UPLOAD_FILE_END) { if (Update.end(true)) { panel.writeStr("otatxt.txt", "Update Completed, Rebooting . . ."); Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { panel.writeStr("otatxt.txt", "Update Failed, Rebooting . . ."); Update.printError(Serial); } } }); otaserver.begin(); } void io_begin() { Serial.println("Initializing I/O . . ."); pinMode(IR_RECIEVE_PIN, INPUT_PULLUP); pinMode(IR_SEND_PIN, OUTPUT); } void network_begin() { Serial.print("Initializing Network "); ETH.begin(); ETH.setHostname(HOSTNAME); ETH.config(IP, GATEWAY, SUBNET, DNS, DNS); #ifndef FASTBOOT delay(1000); lcd_send_command("boot_state.txt=\"Ethernet Core Initializing \""); delay(500); lcd_send_command("boot_state.txt=\"Ethernet Core Initializing . \""); delay(500); lcd_send_command("boot_state.txt=\"Ethernet Core Initializing . . \""); delay(500); lcd_send_command("boot_state.txt=\"Ethernet Core Initializing . . .\""); delay(500); lcd_send_command("boot_state.txt=\"NTP Core Initializing . . .\""); delay(500); #endif char ntp[19]; MQTT_SERVER.toString().toCharArray(ntp, 19); ESPMega_configNTP(utc_offset * 3600, 0, ntp); ESPMega_updateTimeFromNTP(); Serial.println(); } void mqtt_connect() { if (!mqtt_client.connected()) { Serial.print("MQTT not connected, connecting . . .\n"); lcd_send_stop_bit(); #ifdef MQTT_USE_AUTH mqtt_client.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD); #else mqtt_client.connect(HOSTNAME); #endif if (mqtt_client.connected()) { mqtt_subscribe(); Serial.print("MQTT connected\n"); lcd_send_stop_bit(); publish_pwm_states(); publish_input_states(); publish_ac_state(); mqtt_connected_user_callback(); standalone = false; } else { standalone = true; Serial.print("MQTT not connected, continuing in standalone mode\n"); lcd_send_stop_bit(); } lcd_send_stop_bit(); lcd_refresh(); lcd_top_bar_update(); } } void mqtt_subscribe() { for (int i = 0; i < PWM_COUNT; i++) { PWM_SET_VALUE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; PWM_SET_VALUE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; PWM_SET_STATE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; PWM_SET_STATE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; mqtt.subscribe(PWM_SET_STATE_TOPIC, pwm_state_callback); mqtt.subscribe(PWM_SET_VALUE_TOPIC, pwm_value_callback); } mqtt.subscribe(AC_SET_FAN_TOPIC, ac_state_callback); mqtt.subscribe(AC_SET_TEMPERATURE_TOPIC, ac_state_callback); mqtt.subscribe(AC_SET_MODE_TOPIC, ac_state_callback); mqtt.subscribe(STATE_REQUEST_TOPIC, state_request_callback); } void thread_initialization() { Serial.println("Initializing Threads . . ."); Serial.println("Initializing MQTT Thread . . ."); mqtt_reconnector.onRun(mqtt_connect); mqtt_reconnector.setInterval(15000); environment_reporter.onRun(publish_env_state); environment_reporter.setInterval(5000); eeprom_pwm_updater.onRun(eeprom_pwm_update); eeprom_pwm_updater.setInterval(1000); user_timer_tick.onRun(timer_tick_callback); user_timer_tick.setInterval(15000); } void pwm_state_callback(String topic, String message) { int a = topic.charAt(base_topic_length + 4) - '0'; int b = topic.charAt(base_topic_length + 5) - '0'; int id = 10 * a + b; if (message.compareTo("on") == 0) { pwm_set_state(id, true); } else if (message.compareTo("off") == 0) { pwm_set_state(id, false); } } void pwm_value_callback(String topic, String message) { int a = topic.charAt(base_topic_length + 4) - '0'; int b = topic.charAt(base_topic_length + 5) - '0'; int id = 10 * a + b; int value = message.toInt(); pwm_set_value(id, value); } void virtual_interrupt_callback(int pin, int state) { publish_input_state(pin, state); // Serial.printf("Pin %d changed to %d\n", pin, state); if (lcd_current_page == 2) panel.writeNum("I" + String(pin) + ".val", state); virtual_interrupt_user_callback(pin, state); } void virtual_interrupt_loop() { for (int i = 0; i < 16; i++) { int current_pin_value = ESPMega_digitalRead(virtual_interrupt_pins[i]); if (virtual_interupt_state[i] != current_pin_value) { if (millis() - virtual_interupt_timer[i] > DEBOUNCE_TIME_MS) { virtual_interupt_state[i] = current_pin_value; virtual_interrupt_callback(i, current_pin_value); } } else { virtual_interupt_timer[i] = millis(); } yield(); } } void publish_pwm_states() { for (int i = 0; i < PWM_COUNT; i++) { publish_pwm_state(i); } } void publish_pwm_state(int id) { int state = pwm_states[id]; int value = pwm_values[id]; PWM_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0'; PWM_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0'; PWM_VALUE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0'; PWM_VALUE_TOPIC[base_topic_length + 5] = (id % 10) + '0'; if (state == 1) { mqtt_client.publish(PWM_STATE_TOPIC, "on"); } else if (state == 0) { mqtt_client.publish(PWM_STATE_TOPIC, "off"); } mqtt.publish(String(PWM_VALUE_TOPIC), String(value)); } void pwm_set_state(int id, int state) { if (state != pwm_states[id]) { pwm_states[id] = state; int pwm_value = pwm_values[id]; ESPMega_analogWrite(pwm_pins[id], state * (int)(pwm_linear_scaling_m[id] * pwm_value + pwm_linear_scaling_c[id])); if (lcd_current_page == 3) panel.writeNum("j" + String(id) + ".ppic", pwm_states[id] ? 33 : 48); else if (lcd_current_page == 5 && id == lcd_pwmAdj_id) panel.writeStr("pwm_state.txt", pwm_states[lcd_pwmAdj_id] ? "ON" : "OFF"); publish_pwm_state(id); pwm_changed_user_callback(id); } } void pwm_set_value(int id, int value) { pwm_values[id] = value; int pwm_state = pwm_states[id]; ESPMega_analogWrite(pwm_pins[id], pwm_state * (int)(pwm_linear_scaling_m[id] * value + pwm_linear_scaling_c[id])); if (lcd_current_page == 3) panel.writeNum("j" + String(id) + ".val", int(value / 4095.0 * 100.0)); else if (lcd_current_page == 5 && id == lcd_pwmAdj_id) panel.writeNum("pwm_value.val", pwm_values[lcd_pwmAdj_id]); publish_pwm_state(id); pwm_changed_user_callback(id); } void pwm_toggle(int id) { int state = !pwm_states[id]; pwm_set_state(id, state); } void pwm_toggle(int id1, int id2) { boolean state = pwm_group_state(id1, id2); if (state) { pwm_set_state(id1, 0); pwm_set_state(id2, 0); } else { pwm_set_state(id1, 1); pwm_set_state(id2, 1); } } boolean pwm_group_state(int id1, int id2) { int state1 = pwm_states[id1 - 1], state2 = pwm_states[id2 - 1]; if (state1 || state2) return true; return false; } void pwm_cycle_value(int id) { int state = pwm_states[id]; int value = pwm_values[id]; if (state == 1) for (int i = 0; i < PWM_CYCLE_VALUES_COUNT; i++) { if (PWM_CYCLE_VALUES[i] == value) { if (i > 0) { pwm_set_value(id, PWM_CYCLE_VALUES[i - 1]); return; } else { pwm_set_state(id, 0); return; } } } pwm_set_state(id, 1); pwm_set_value(id, PWM_CYCLE_VALUES[PWM_CYCLE_VALUES_COUNT - 1]); } void publish_input_states() { for (int i = 0; i < VINT_COUNT; i++) { publish_input_state(i); } } void publish_input_state(int id) { int state = ESPMega_digitalRead(virtual_interrupt_pins[id]); publish_input_state(id, state); } void publish_input_state(int id, int state) { INPUTS_TOPIC[base_topic_length + 6] = ((id - id % 10) / 10) + '0'; INPUTS_TOPIC[base_topic_length + 7] = (id % 10) + '0'; mqtt.publish(String(INPUTS_TOPIC), state ? "1" : "0"); } void state_request_callback(String topic, String message) { publish_input_states(); publish_pwm_states(); publish_ac_state(); user_state_request_callback(); } void ir_loop() { if (IrReceiver.decode()) { // Serial.println(); // IrReceiver.compensateAndPrintIRResultAsCArray(&Serial, false); // Serial.println(); // Serial.println(); IrReceiver.resume(); } } void publish_ac_state() { String temp = ""; switch (ac_mode) { case 0: temp = "off"; break; case 1: temp = "cool"; break; case 2: temp = "fan_only"; default: break; } mqtt.publish(String(AC_MODE_TOPIC), temp); mqtt.publish(String(AC_TEMPERATURE_TOPIC), String(ac_temperature)); switch (ac_fan_speed) { case 0: temp = "auto"; break; case 1: temp = "high"; break; case 2: temp = "med"; break; case 3: temp = "low"; break; } mqtt.publish(String(AC_FAN_TOPIC), temp); } void ac_state_callback(String topic, String message) { if (topic.compareTo(String(AC_SET_TEMPERATURE_TOPIC)) == 0) { int new_temp = message.toInt(); if (new_temp >= AC_MIN_TEMPERATURE && new_temp <= AC_MAX_TEMPERATURE) { ac_set_state(ac_mode, new_temp, ac_fan_speed); } } else if (topic.compareTo(String(AC_SET_MODE_TOPIC)) == 0) { if (message.compareTo("off") == 0) { ac_set_state(0, ac_temperature, ac_fan_speed); } else if (message.compareTo("cool") == 0) { ac_set_state(1, ac_temperature, ac_fan_speed); } else if (message.compareTo("fan_only") == 0) { ac_set_state(2, ac_temperature, ac_fan_speed); } } else if (topic.compareTo(String(AC_SET_FAN_TOPIC)) == 0) { if (message.compareTo("auto") == 0) { ac_set_state(ac_mode, ac_temperature, 0); } else if (message.compareTo("low") == 0) { ac_set_state(ac_mode, ac_temperature, 1); } else if (message.compareTo("med") == 0) { ac_set_state(ac_mode, ac_temperature, 2); } else if (message.compareTo("high") == 0) { ac_set_state(ac_mode, ac_temperature, 3); } } } void ac_set_state(int mode, int temperature, int fan_speed) { ac_mode = mode; ac_temperature = temperature; if (ac_temperature < AC_MIN_TEMPERATURE) ac_temperature = AC_MIN_TEMPERATURE; else if (ac_temperature > AC_MAX_TEMPERATURE) ac_temperature = AC_MAX_TEMPERATURE; ac_fan_speed = fan_speed; temperature -= AC_MIN_TEMPERATURE; if (lcd_current_page == 4) { lcd_ac_refresh_fan(); lcd_ac_refresh_mode(); if (ac_mode != 2) panel.writeStr("temp.txt", String(ac_temperature) + "C"); else panel.writeStr("temp.txt", "--C"); } publish_ac_state(); uint8_t ac_datablock[3] = {ac_mode, ac_temperature, ac_fan_speed}; ESPMega_FRAM.write(0, ac_datablock, 3); switch (mode) { case 0: IrSender.sendRaw(ir_code_off, sizeof(ir_code_off) / sizeof(ir_code_off[0]), NEC_KHZ); break; case 1: IrSender.sendRaw(ir_code_cool[fan_speed][temperature], sizeof(ir_code_cool[fan_speed][temperature]) / sizeof(ir_code_cool[fan_speed][0]), NEC_KHZ); break; case 2: IrSender.sendRaw(ir_code_fan[fan_speed], sizeof(ir_code_fan[fan_speed]) / sizeof(ir_code_fan[fan_speed][0]), NEC_KHZ); break; } ac_changed_user_callback(mode, ac_temperature, fan_speed); } void publish_env_state() { int errorCode = env_sensor.read(); yield(); switch (errorCode) { case DHTLIB_OK: current_room_humid = env_sensor.getHumidity(); current_room_temp = env_sensor.getTemperature(); mqtt.publish(String(AC_ROOM_TEMPERATURE_TOPIC), String(current_room_temp)); mqtt_client.loop(); mqtt.publish(String(AC_HUMIDITY_TOPIC), String(current_room_humid)); mqtt_client.loop(); if (lcd_current_page == 4) { Serial.printf("roomtemp.txt=\"%.01fC\"",current_room_temp); lcd_send_stop_bit(); Serial.printf("roomhumid.txt=\"%d%\"",current_room_humid); lcd_send_stop_bit(); } break; default: mqtt.publish(String(AC_ROOM_TEMPERATURE_TOPIC), "ERROR"); mqtt_client.loop(); mqtt.publish(String(AC_HUMIDITY_TOPIC), "ERROR"); mqtt_client.loop(); } } void lcd_begin() { top_bar_updater.onRun(lcd_top_bar_update); top_bar_updater.setInterval(10000); page_updater.onRun(lcd_refresh_pd); page_updater.setInterval(5000); lcd_refresh(); } void lcd_loop() { lcd_thread_controller.run(); panel.NextionListen(); if (panel.currentPageId != lcd_current_page) { lcd_current_page = panel.currentPageId; lcd_refresh(); lcd_top_bar_update(); } } void lcd_refresh_pd() { if (lcd_current_page == 1) { lcd_refresh(); } } void lcd_refresh() { switch (lcd_current_page) { case 1: panel.writeStr("hostname.txt", HOSTNAME); panel.writeStr("server_address.txt", MQTT_SERVER.toString()); panel.writeStr("ip_address.txt", IP.toString()); panel.writeStr("status_txt.txt", standalone ? "Standalone" : "BMS Managed"); break; case 2: for (int i = 0; i <= 15; i++) { panel.writeNum("I" + String(i) + ".val", virtual_interupt_state[i]); } break; case 3: for (int i = 0; i <= 15; i++) { panel.writeNum("j" + String(i) + ".val", int(pwm_values[i] / 4095.0 * 100.0)); panel.writeNum("j" + String(i) + ".ppic", pwm_states[i] ? 33 : 48); } break; case 4: Serial.printf("roomtemp.txt=\"%.01fC\"",current_room_temp); lcd_send_stop_bit(); Serial.printf("roomhumid.txt=\"%.01f%\"",current_room_humid); lcd_send_stop_bit(); if (ac_mode != 2) panel.writeStr("temp.txt", String(ac_temperature) + "C"); else panel.writeStr("temp.txt", "--C"); lcd_ac_refresh_fan(); lcd_ac_refresh_mode(); case 5: panel.writeStr("pwm_id.txt", String("P") + String(lcd_pwmAdj_id)); panel.writeStr("pwm_state.txt", pwm_states[lcd_pwmAdj_id] ? "ON" : "OFF"); panel.writeNum("pwm_value.val", pwm_values[lcd_pwmAdj_id]); break; case 6: panel.writeStr("ip_set.txt", IP.toString()); panel.writeStr("netmask_set.txt", SUBNET.toString()); panel.writeStr("gateway_set.txt", GATEWAY.toString()); panel.writeStr("dns_set.txt", DNS.toString()); panel.writeStr("mqttsv_set.txt", MQTT_SERVER.toString()); panel.writeStr("host_set.txt", HOSTNAME); panel.writeNum("port_set.val", MQTT_PORT); panel.writeStr("topic_set.txt", MQTT_BASE_TOPIC); break; default: break; } } void lcd_top_bar_update() { char time_buffer[15]; rtctime_t time = ESPMega_getTime(); sprintf(time_buffer, "%02d:%02d", time.hours, time.minutes); panel.writeStr("time.txt", time_buffer); panel.writeNum("server.pic", standalone ? 4 : 5); panel.writeNum("lan.pic", ETH.linkUp() ? 3 : 2); } void lcd_ac_refresh_mode() { // auto high mid low panel.writeNum("mode_cool.pic", ac_mode == 1 ? 12 : 13); panel.writeNum("mode_fan.pic", ac_mode == 2 ? 22 : 23); panel.writeNum("mode_off.pic", ac_mode == 0 ? 24 : 25); } void lcd_ac_refresh_fan() { panel.writeNum("fan_auto.pic", ac_fan_speed == 0 ? 14 : 15); panel.writeNum("fan_low.pic", ac_fan_speed == 3 ? 18 : 19); panel.writeNum("fan_mid.pic", ac_fan_speed == 2 ? 20 : 21); panel.writeNum("fan_high.pic", ac_fan_speed == 1 ? 16 : 17); } void trigger0() { if (lcd_pwmAdj_id >= 15) lcd_pwmAdj_id = 0; else lcd_pwmAdj_id++; lcd_refresh(); } void trigger1() { if (lcd_pwmAdj_id <= 0) lcd_pwmAdj_id = 15; else lcd_pwmAdj_id--; lcd_refresh(); } void trigger2() { pwm_toggle(lcd_pwmAdj_id); } void trigger3() { int value = panel.readNumber("pwm_value.val"); lcd_send_stop_bit(); pwm_set_value(lcd_pwmAdj_id, value); } void trigger4() { if (ac_temperature < AC_MAX_TEMPERATURE && ac_mode != 2) ac_set_state(ac_mode, ac_temperature + 1, ac_fan_speed); } void trigger5() { if (ac_temperature > AC_MIN_TEMPERATURE && ac_mode != 2) ac_set_state(ac_mode, ac_temperature - 1, ac_fan_speed); } void trigger6() { ac_set_state(ac_mode, ac_temperature, 0); } void trigger7() { ac_set_state(ac_mode, ac_temperature, 3); } void trigger8() { ac_set_state(ac_mode, ac_temperature, 2); } void trigger9() { ac_set_state(ac_mode, ac_temperature, 1); } void trigger10() { ac_set_state(1, ac_temperature, ac_fan_speed); } void trigger11() { ac_set_state(2, ac_temperature, ac_fan_speed); } void trigger12() { ac_set_state(0, ac_temperature, ac_fan_speed); } void trigger13() { set_ip(panel.readStr("ip_set.txt")); set_netmask(panel.readStr("netmask_set.txt")); set_gw(panel.readStr("gateway_set.txt")); set_dns(panel.readStr("dns_set.txt")); set_mqtt_server(panel.readStr("mqttsv_set.txt")); set_hostname(panel.readStr("host_set.txt")); set_basetopic(panel.readStr("topic_set.txt")); uint16_t port = panel.readNumber("port_set.val"); mqtt_port_set(port); delay(100); ESP.restart(); } void eeprom_pwm_update() { if (memcmp(pwm_states, pwm_states_eeprom, 16)) { memcpy(pwm_states_eeprom, pwm_states, 16); ESPMega_FRAM.write(3, pwm_states_eeprom, 16); lcd_send_stop_bit(); } if (memcmp(pwm_values, pwm_values_eeprom, 32)) { memcpy(pwm_values_eeprom, pwm_values, 32); ESPMega_FRAM.write(19, pwm_values_eeprom, 32); lcd_send_stop_bit(); } } void set_ip(String address) { IP.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); } void set_netmask(String address) { SUBNET.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]); } void set_dns(String address) { DNS.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); } void set_gw(String address) { GATEWAY.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); } void set_mqtt_server(String address) { MQTT_SERVER.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); } void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) { uint8_t addressblock[4] = {byte1, byte2, byte3, byte4}; ESPMega_FRAM.write(rom_address, addressblock, 4); } IPAddress eeprom_ip_retrieve(uint16_t rom_address) { uint8_t addressblock[4]; ESPMega_FRAM.read(rom_address, addressblock, 4); return IPAddress(addressblock[0], addressblock[1], addressblock[2], addressblock[3]); } void set_hostname(String hostname) { hostname.toCharArray(HOSTNAME, 15); ESPMega_FRAM.write(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } void eeprom_hostname_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } void set_basetopic(String topic) { topic.toCharArray(MQTT_BASE_TOPIC, 20); ESPMega_FRAM.write(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } void eeprom_basetopic_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } void mqtt_port_set(uint16_t port) { uint8_t port_arr[2]; memcpy(port_arr, &port, 2); ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); } void eeprom_mqtt_port_retrieve() { uint8_t port_arr[2]; ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); memcpy(&MQTT_PORT, port_arr, 2); } boolean pwm_get_state(int id) { return pwm_states[id]; } uint16_t pwm_get_value(int id) { return pwm_values[id]; } boolean input_get_state(int id) { return virtual_interupt_state[id]; } uint8_t ac_get_temperature() { return ac_temperature; } uint8_t ac_get_mode() { return ac_mode; } uint8_t ac_get_fan_speed() { return ac_fan_speed; }