/** * @file main.cpp * @brief Test firmware for the ESPMegaPRO OOP library */ #include #include #include #include #include #include #include #include #include // #define FRAM_DEBUG // #define MQTT_DEBUG #define WRITE_DEFAULT_NETCONF //#define CLIMATE_CARD_ENABLE #define MQTT_CARD_REGISTER //#define DISPLAY_ENABLE #define WEB_SERVER_ENABLE //#define LCD_OTA_ENABLE //#define REMOTE_VARIABLE_ENABLE //#define CT_ENABLE #define SMART_VARIABLE_ENABLE // Demo PLC firmware using the ESPMegaPRO OOP library ESPMegaPRO espmega = ESPMegaPRO(); // Remote Variable #ifdef REMOTE_VARIABLE_ENABLE RemoteVariable testVar = RemoteVariable(); #endif #ifdef LCD_OTA_ENABLE ESPMegaDisplayOTA internalDisplayOTA = ESPMegaDisplayOTA(); #endif #ifdef CT_ENABLE float adc2current(uint16_t adcValue) { return (adcValue - 2048) * 0.0005; } AnalogCard analogCard = AnalogCard(); float voltage = 220.0; CurrentTransformerCard ct = CurrentTransformerCard(&analogCard, 0, &voltage, adc2current, 1000); #endif #ifdef SMART_VARIABLE_ENABLE SmartVariable smartVar = SmartVariable(); #endif #ifdef CLIMATE_CARD_ENABLE // Climate Card const char *mode_names[] = {"off", "fan_only", "cool"}; const char *fan_speed_names[] = {"auto"}; const uint16_t code_off[] = {3478, 1717, 452, 418, 452, 1285, 452, 418, 452, 424, 452, 419, 451, 420, 452, 419, 451, 424, 451, 420, 451, 420, 452, 419, 451, 424, 451, 419, 451, 1285, 452, 419, 452, 424, 451, 419, 452, 419, 452, 419, 452, 423, 452, 418, 451, 1284, 452, 1284, 451, 1289, 452, 419, 452, 418, 452, 1285, 452, 423, 451, 420, 451, 420, 452, 419, 452, 423, 451, 420, 452, 420, 451, 419, 452, 423, 452, 419, 452, 419, 452, 419, 452, 423, 452, 420, 451, 420, 451, 420, 451, 423, 452, 419, 452, 419, 452, 420, 451, 423, 452, 419, 452, 420, 451, 419, 452, 423, 452, 419, 452, 419, 452, 420, 451, 423, 452, 418, 452, 1283, 452, 1285, 452, 424, 451, 420, 451, 420, 451, 420, 451, 419, 451, 9924, 3478, 1716, 452, 419, 451, 1284, 453, 420, 450, 425, 450, 420, 452, 419, 452, 419, 452, 423, 452, 420, 451, 420, 451, 420, 451, 423, 452, 418, 451, 1286, 451, 420, 451, 423, 452, 420, 451, 420, 451, 420, 451, 424, 451, 418, 451, 1285, 503, 1232, 451, 1289, 452, 420, 451, 418, 452, 1285, 451, 424, 451, 421, 450, 420, 451, 421, 450, 424, 451, 420, 451, 421, 450, 420, 451, 424, 451, 420, 451, 420, 451, 419, 452, 424, 451, 420, 451, 420, 451, 419, 450, 1290, 451, 419, 450, 1287, 504, 367, 451, 423, 451, 419, 450, 1285, 451, 1286, 450, 423, 451, 1284, 451, 1286, 506, 365, 506, 369, 451, 420, 451, 419, 506, 366, 505, 369, 505, 367, 450, 420, 506, 364, 506, 1236, 508, 1227, 506, 1230, 508, 1228, 506, 1234, 511, 358, 506, 1231, 505, 365, 504, 1235, 507, 1230, 505, 364, 508, 1228, 505, 1236, 507, 364, 505, 366, 506, 365, 507, 368, 506, 366, 505, 365, 451, 420, 506, 369, 506, 365, 506, 365, 506, 364, 507, 368, 506, 365, 505, 1229, 508, 1228, 451, 1289, 507, 364, 507, 365, 506, 365, 504, 370, 451, 421, 506, 366, 504, 366, 450, 425, 504, 365, 450, 1285, 451, 1285, 450, 1291, 504, 366, 505, 367, 504, 367, 450, 425, 506, 365, 450, 421, 450, 421, 510, 366, 449, 421, 450, 421, 506, 365, 504, 371, 506, 364, 506, 366, 505, 366, 506, 367, 451, 1286, 506, 366, 449, 422, 532, 342, 451, 420, 507, 364, 507, 363, 504, 1238, 506, 365, 504, 367, 505, 366, 506, 370, 508, 364, 450, 422, 449, 421, 506, 372, 506, 364, 506, 366, 450, 421, 450, 427, 450, 421, 450, 421, 532, 339, 450, 425, 507, 1229, 450, 1285, 506, 1229, 451, 1292, 507, 364, 507, 365, 535, 336, 450, 422, 506}; const uint16_t code_cool_auto[3][439] = { {3477, 1718, 451, 419, 451, 1286, 450, 421, 451, 425, 449, 421, 451, 421, 450, 420, 451, 424, 451, 420, 451, 421, 450, 421, 450, 424, 451, 419, 451, 1286, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 419, 451, 1285, 450, 1285, 451, 1289, 452, 420, 450, 420, 450, 1287, 450, 424, 451, 421, 450, 420, 451, 420, 451, 424, 451, 421, 450, 421, 450, 421, 450, 425, 450, 421, 450, 421, 450, 421, 451, 424, 451, 420, 450, 421, 451, 420, 451, 424, 451, 420, 450, 421, 451, 421, 450, 424, 451, 421, 450, 420, 451, 421, 450, 424, 451, 421, 450, 421, 450, 421, 451, 423, 451, 419, 451, 1285, 450, 1286, 451, 424, 451, 420, 451, 420, 451, 421, 451, 418, 451, 9926, 3477, 1717, 451, 419, 451, 1286, 450, 421, 451, 423, 452, 421, 450, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 421, 450, 424, 451, 419, 451, 1285, 452, 420, 451, 424, 450, 421, 451, 420, 451, 420, 451, 424, 451, 419, 450, 1285, 451, 1285, 451, 1289, 451, 421, 450, 419, 451, 1286, 451, 424, 451, 420, 451, 420, 451, 420, 451, 425, 450, 421, 450, 420, 451, 421, 450, 424, 451, 420, 451, 421, 450, 421, 450, 425, 451, 420, 451, 420, 451, 418, 451, 1290, 451, 419, 450, 1286, 452, 420, 450, 425, 451, 420, 451, 420, 451, 420, 451, 422, 451, 1285, 451, 1286, 450, 420, 452, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 418, 451, 1292, 451, 1284, 452, 1285, 450, 1285, 451, 1290, 451, 419, 450, 1287, 450, 419, 451, 1289, 450, 1287, 450, 419, 451, 1284, 451, 1290, 451, 420, 451, 421, 450, 421, 450, 424, 451, 421, 450, 421, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 419, 450, 1284, 452, 1285, 451, 1289, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 452, 420, 450, 421, 450, 425, 451, 418, 451, 1285, 451, 1284, 451, 1290, 450, 421, 451, 420, 451, 421, 450, 424, 451, 421, 450, 420, 451, 421, 450, 424, 451, 420, 451, 421, 450, 421, 450, 424, 451, 420, 452, 419, 451, 421, 451, 423, 450, 1286, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 419, 451, 1290, 451, 420, 451, 421, 451, 420, 451, 426, 451, 420, 451, 420, 451, 420, 451, 426, 452, 420, 451, 419, 451, 421, 451, 425, 452, 420, 451, 420, 451, 420, 451, 425, 451, 1286, 450, 421, 451, 418, 451, 1292, 451, 420, 452, 419, 452, 420, 451, 420, 451}, // 24 {3478, 1717, 452, 417, 452, 1285, 452, 420, 451, 424, 451, 420, 451, 419, 452, 420, 451, 424, 451, 420, 452, 419, 451, 420, 452, 423, 452, 418, 451, 1286, 451, 420, 452, 423, 451, 420, 451, 419, 452, 420, 452, 423, 451, 419, 451, 1284, 452, 1283, 452, 1289, 452, 419, 452, 418, 452, 1285, 452, 423, 452, 419, 452, 419, 452, 420, 451, 423, 452, 418, 453, 419, 452, 419, 452, 423, 452, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 452, 423, 451, 420, 451, 420, 452, 419, 452, 423, 452, 419, 452, 420, 451, 419, 452, 423, 452, 419, 452, 419, 452, 420, 456, 419, 451, 418, 452, 1283, 452, 1286, 451, 423, 452, 420, 451, 419, 452, 420, 451, 418, 452, 9925, 3477, 1718, 451, 418, 451, 1286, 451, 420, 452, 423, 452, 419, 452, 419, 452, 420, 451, 423, 452, 419, 452, 420, 451, 420, 451, 423, 452, 418, 452, 1285, 452, 419, 452, 423, 451, 420, 452, 419, 452, 420, 502, 372, 452, 417, 452, 1284, 452, 1284, 451, 1289, 452, 420, 451, 418, 452, 1285, 452, 422, 453, 418, 453, 419, 452, 420, 451, 423, 452, 420, 451, 419, 452, 420, 452, 422, 452, 419, 452, 420, 452, 419, 452, 424, 450, 420, 452, 419, 452, 418, 451, 1289, 452, 418, 452, 1285, 452, 419, 452, 423, 451, 419, 451, 1285, 452, 419, 452, 422, 452, 1284, 451, 1285, 452, 420, 451, 424, 451, 420, 451, 420, 451, 419, 453, 423, 451, 420, 452, 419, 451, 419, 451, 1292, 451, 1284, 452, 1284, 451, 1284, 452, 1289, 452, 417, 452, 1285, 452, 418, 452, 1287, 452, 1285, 452, 418, 452, 1283, 452, 1290, 451, 419, 452, 419, 452, 420, 451, 423, 452, 419, 452, 420, 451, 420, 451, 423, 452, 420, 452, 419, 452, 419, 452, 423, 452, 417, 452, 1284, 452, 1283, 452, 1289, 452, 419, 452, 419, 452, 420, 451, 423, 452, 420, 451, 420, 451, 420, 452, 423, 452, 417, 452, 1284, 452, 1283, 452, 1289, 452, 420, 451, 419, 452, 420, 451, 423, 452, 419, 452, 420, 451, 420, 451, 423, 452, 419, 452, 420, 451, 420, 451, 424, 451, 419, 452, 420, 452, 419, 452, 422, 451, 1286, 451, 420, 451, 420, 451, 424, 451, 420, 452, 418, 453, 417, 452, 1291, 451, 419, 452, 419, 452, 422, 449, 426, 451, 420, 451, 420, 451, 420, 452, 425, 451, 420, 452, 419, 452, 420, 451, 424, 453, 419, 452, 419, 452, 420, 452, 424, 451, 1284, 451, 1285, 453, 418, 451, 1291, 452, 420, 451, 420, 451, 420, 451, 421, 451}, // 25 {3478, 1717, 451, 419, 451, 1286, 451, 420, 451, 424, 451, 421, 450, 421, 450, 421, 451, 423, 451, 420, 452, 420, 451, 420, 451, 424, 451, 418, 451, 1286, 451, 420, 452, 423, 451, 421, 450, 421, 451, 420, 451, 424, 450, 419, 451, 1285, 451, 1284, 451, 1290, 451, 420, 451, 419, 451, 1286, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 421, 450, 420, 451, 424, 451, 420, 451, 421, 450, 420, 451, 425, 450, 421, 450, 421, 450, 421, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 419, 451, 1285, 450, 1287, 451, 424, 450, 420, 451, 420, 452, 420, 451, 418, 451, 9926, 3477, 1717, 451, 419, 451, 1286, 451, 420, 451, 424, 451, 421, 450, 420, 451, 420, 451, 424, 451, 420, 451, 420, 452, 419, 452, 424, 450, 419, 451, 1286, 451, 420, 451, 424, 451, 420, 451, 420, 451, 421, 450, 424, 451, 419, 451, 1285, 450, 1285, 451, 1290, 450, 421, 451, 418, 451, 1287, 451, 423, 451, 420, 451, 421, 450, 421, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 424, 451, 421, 450, 420, 451, 419, 451, 1290, 450, 420, 450, 1286, 451, 421, 451, 423, 451, 421, 451, 418, 451, 1286, 451, 423, 451, 1284, 451, 1286, 451, 420, 451, 424, 451, 420, 451, 420, 451, 420, 451, 425, 450, 420, 451, 421, 450, 419, 451, 1292, 451, 1284, 451, 1286, 450, 1285, 451, 1290, 450, 419, 451, 1286, 451, 419, 451, 1288, 451, 1286, 456, 414, 450, 1285, 451, 1290, 450, 421, 451, 420, 451, 420, 451, 424, 451, 420, 451, 421, 450, 421, 450, 425, 450, 421, 450, 421, 451, 420, 451, 424, 451, 419, 450, 1285, 450, 1286, 450, 1290, 451, 420, 451, 420, 451, 420, 451, 424, 451, 420, 451, 421, 450, 421, 451, 424, 450, 419, 451, 1285, 450, 1285, 451, 1290, 450, 421, 451, 420, 451, 420, 451, 425, 450, 421, 450, 421, 450, 420, 451, 425, 450, 420, 451, 421, 451, 420, 451, 424, 450, 421, 450, 421, 451, 421, 450, 423, 450, 1286, 451, 421, 450, 421, 450, 425, 451, 419, 452, 420, 450, 420, 450, 1291, 451, 420, 451, 420, 451, 421, 450, 426, 451, 421, 450, 421, 451, 420, 451, 426, 451, 420, 451, 420, 451, 420, 451, 427, 450, 420, 452, 420, 450, 421, 451, 425, 450, 1287, 450, 419, 451, 1285, 450, 1293, 450, 421, 451, 420, 451, 420, 451, 421, 451} // 26 }; size_t getInfraredCode(uint8_t mode, uint8_t fan_speed, uint8_t temperature_index, const uint16_t **codePtr) { if (mode == 0) { // Off *codePtr = &(code_off[0]); return sizeof(code_off) / sizeof(uint16_t); } else if (mode == 1) { *codePtr = &(code_off[0]); return sizeof(code_off) / sizeof(uint16_t); } else if (mode == 2) { // Cool if (fan_speed == 0) { // Auto Serial.printf("Returning cool auto code at temperature index %d\n", temperature_index); *codePtr = &(code_cool_auto[temperature_index][0]); return sizeof(code_cool_auto[temperature_index]) / sizeof(uint16_t); } else { // Didn't capture the other fan speeds yet // Will do that later *codePtr = &(code_off[0]); return sizeof(code_off) / sizeof(uint16_t); } } return 0; } AirConditioner ac = { .max_temperature = 26, .min_temperature = 24, .modes = 3, .mode_names = mode_names, .fan_speeds = 4, .fan_speed_names = fan_speed_names, .getInfraredCode = &getInfraredCode}; ClimateCard climateCard = ClimateCard(4, ac, RMT_CHANNEL_1); #endif void input_change_callback(uint8_t pin, uint8_t value) { Serial.print("Input change callback: "); Serial.print(pin); Serial.print(" "); Serial.println(value); } void mqtt_callback(char *topic, char *payload) { Serial.print("MQTT Callback: "); Serial.print(topic); Serial.print(" "); Serial.println(payload); } #ifdef WRITE_DEFAULT_NETCONF void setNetworkConfig() { NetworkConfig config = { .ip = {192, 168, 0, 249}, .gateway = {192, 168, 0, 1}, .subnet = {255, 255, 255, 0}, .dns1 = {10, 192, 1, 1}, .dns2 = {10, 192, 1, 1}, .useStaticIp = true, .useWifi = false, .wifiUseAuth = false, }; strcpy(config.ssid, "ssid"); strcpy(config.password, "password"); strcpy(config.hostname, "espmega"); Serial.println("Setting network config"); espmega.iot->setNetworkConfig(config); espmega.iot->saveNetworkConfig(); } void setMqttConfig() { MqttConfig config = { .mqtt_port = 1883, .mqtt_useauth = false}; strcpy(config.mqtt_server, "192.168.0.26"); strcpy(config.base_topic, "/espmegacud"); espmega.iot->setMqttConfig(config); espmega.iot->saveMqttConfig(); } #endif void setup() { ESP_LOGI("Initializer", "Starting ESPMegaPRO OOP demo"); espmega.begin(); ESP_LOGI("Initializer", "Enabling IOT module"); espmega.enableIotModule(); ESP_LOGI("Initializer", "Enabling Ethernet"); ETH.begin(); ESP_LOGI("Initializer", "Binding Ethernet to IOT module"); espmega.iot->bindEthernetInterface(Ð); #ifdef WRITE_DEFAULT_NETCONF setNetworkConfig(); #else ESP_LOGI("Initializer", "Loading network config"); espmega.iot->loadNetworkConfig(); #endif ESP_LOGI("Initializer", "Connecting to network"); espmega.iot->connectNetwork(); #ifdef WRITE_DEFAULT_NETCONF setMqttConfig(); #else ESP_LOGI("Initializer", "Loading MQTT config"); espmega.iot->loadMqttConfig(); #endif ESP_LOGI("Initializer", "Connecting to MQTT"); espmega.iot->connectToMqtt(); espmega.iot->registerMqttCallback(mqtt_callback); #ifdef MQTT_CARD_REGISTER ESP_LOGI("Initializer", "Registering cards 0"); espmega.iot->registerCard(0); ESP_LOGI("Initializer", "Registering cards 1"); espmega.iot->registerCard(1); #endif ESP_LOGI("Initializer", "Registering Input change callback"); espmega.inputs.registerCallback(input_change_callback); #ifdef CLIMATE_CARD_ENABLE ESP_LOGI("Initializer", "Installing climate card"); espmega.installCard(2, &climateCard); ESP_LOGI("Initializer", "Binding climate card to FRAM"); climateCard.bindFRAM(&espmega.fram, 1001); ESP_LOGI("Initializer", "Loading climate card state from FRAM"); climateCard.loadStateFromFRAM(); ESP_LOGI("Initializer", "Enabling climate card FRAM autosave"); climateCard.setFRAMAutoSave(true); ESP_LOGI("Initializer", "Registering cards 2"); espmega.iot->registerCard(2); #endif #ifdef DISPLAY_ENABLE ESP_LOGI("Initializer", "Enabling internal display"); espmega.enableInternalDisplay(&Serial); ESP_LOGI("Initializer", "Binding climate card to internal display"); #ifdef CLIMATE_CARD_ENABLE espmega.display->bindClimateCard(&climateCard); #endif #endif #ifdef WEB_SERVER_ENABLE ESP_LOGI("Initializer", "Enabling web server"); espmega.enableWebServer(80); espmega.webServer->setWebUsername("admin"); espmega.webServer->setWebPassword("Passw0rd"); espmega.webServer->saveCredentialsToFRAM(); #endif #ifdef LCD_OTA_ENABLE internalDisplayOTA.begin("/display", espmega.display, espmega.webServer); #endif #ifdef REMOTE_VARIABLE_ENABLE ESP_LOGI("Initializer", "Initializing testvar"); testVar.begin(32, "/xm/fan_speed", espmega.iot, true,"/pm/request_fan_speed"); testVar.enableSetValue("/pm/request_switch_state"); #endif #ifdef CT_ENABLE ESP_LOGI("Initializer", "Initializing analog card"); analogCard.begin(); ESP_LOGI("Initializer", "Initializing current transformer"); ct.begin(); ct.bindFRAM(&espmega.fram, 7000); ct.loadEnergy(); ct.setEnergyAutoSave(true); #endif #ifdef SMART_VARIABLE_ENABLE ESP_LOGI("Initializer", "Initializing smart variable"); smartVar.begin(16); ESP_LOGI("Initializer", "Binding smart variable to FRAM"); smartVar.bindFRAM(&espmega.fram, 8000); ESP_LOGI("Initializer", "Enabling smart variable autosave"); smartVar.setValueAutoSave(true); ESP_LOGI("Initializer", "Enabling IoT for smart variable"); smartVar.enableIoT(espmega.iot, "/smartvar"); ESP_LOGI("Initializer", "Enabling smart variable set value"); smartVar.enableSetValue("/smartvar/set"); ESP_LOGI("Initializer", "Enabling smart variable value request"); smartVar.enableValueRequest("/smartvar/request"); #endif ESP_LOGI("Initializer", "Setup complete"); } void loop() { espmega.loop(); #ifdef FRAM_DEBUG // Every 20 seconds, dump FRAM 0-500 to serial static uint32_t last_fram_dump = 0; if (millis() - last_fram_dump >= 20000) { last_fram_dump = millis(); Serial.println("Dumping FRAM"); espmega.dumpFRAMtoSerial(0, 500); Serial.println("Dumping FRAM ASCII"); espmega.dumpFRAMtoSerialASCII(0, 500); } #endif // Every 5 seconds, publish "I'm alive" to MQTT #ifdef MQTT_DEBUG static uint32_t last_mqtt_publish = 0; if (millis() - last_mqtt_publish >= 5000) { last_mqtt_publish = millis(); espmega.iot->publish("/espmegai/alive", "true"); } static uint32_t last_mqtt_status = 0; if (millis() - last_mqtt_status >= 1000) { last_mqtt_status = millis(); Serial.print("MQTT Status: "); Serial.println(espmega.iot->mqttConnected() ? "Connected" : "Disconnected"); } #endif #ifdef REMOTE_VARIABLE_ENABLE // Print out testvar value every 5 seconds static uint32_t last_testvar_print = 0; if (millis() - last_testvar_print >= 5000) { last_testvar_print = millis(); if (testVar.getValue() != nullptr) ESP_LOGI("TestVar", "Value: %s", testVar.getValue()); testVar.setValue("Hello World"); } #endif #ifdef CT_ENABLE ct.loop(); static uint32_t last_ct_print = 0; if (millis() - last_ct_print >= 1000) { last_ct_print = millis(); Serial.print("Current: "); Serial.println(ct.getCurrent()); } #endif #ifdef SMART_VARIABLE_ENABLE static uint32_t last_smartvar_print = 0; if (millis() - last_smartvar_print >= 1000) { last_smartvar_print = millis(); Serial.print("SmartVar: "); Serial.println(smartVar.getValue()); } static bool last_smartvar_state = false; static uint32_t last_smartvar_state_change = 0; if (millis() - last_smartvar_state_change >= 5000) { last_smartvar_state_change = millis(); last_smartvar_state = !last_smartvar_state; smartVar.setValue(last_smartvar_state ? "true" : "false"); } #endif }