diff --git a/Thermostat/src/main.cpp b/Thermostat/src/main.cpp index eb0e81f..d686239 100644 --- a/Thermostat/src/main.cpp +++ b/Thermostat/src/main.cpp @@ -12,11 +12,33 @@ Thermostat thermostat; float currentTemp = 0.0; +/** + * Initialize serial, load configuration and presets, connect to WiFi and MQTT, and set up the thermostat. + * + */ void setup() { Serial.begin(115200); + // Retrieve config from EEPROM, connect to WiFi and MQTT, and set up thermostat presets load_config(); + // Debug: print current config and actions + Serial.println("--- Thermostat Unit Startup ---"); + Serial.print("WiFi SSID: "); Serial.println(wifi_ssid); + Serial.print("MQTT Server: "); Serial.println(mqtt_server); + Serial.print("MQTT Port: "); Serial.println(mqtt_port); + Serial.print("MQTT User: "); Serial.println(mqtt_user); + Serial.print("MQTT Device ID: "); Serial.println(mqtt_device_id); + Serial.print("MQTT Temp Topic: "); Serial.println(mqtt_temp_topic); + Serial.print("Temp Sensor ID: "); Serial.println(temp_sensor_id); + Serial.print("Preset Confort: "); Serial.println(preset_confort); + Serial.print("Preset Eco: "); Serial.println(preset_eco); + Serial.print("Preset Boost: "); Serial.println(preset_boost); + Serial.print("Preset Hors Gel: "); Serial.println(preset_hors_gel); + + Serial.println("Connecting to WiFi..."); + // setup wifi and mqtt, and load presets into thermostat setup_web_config(); WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str()); + Serial.println("Connecting to MQTT..."); mqttClient.setServer(mqtt_server.c_str(), mqtt_port); setup_mqtt(mqttClient); load_presets(); @@ -24,13 +46,19 @@ void setup() { thermostat.setPresetTemp(MODE_ECO, preset_eco); thermostat.setPresetTemp(MODE_BOOST, preset_boost); thermostat.setPresetTemp(MODE_HORS_GEL, preset_hors_gel); + // Retreive current temp from MQTT (if available) and set initial mode to lastvalue (stored in EEPROM) or MODE_OFF if not available thermostat.setMode(MODE_OFF); } void loop() { handle_web_config(); + // Ask Mqtt to process incoming messages and maintain connection mqtt_loop(mqttClient); + // Update thermostat state based on current temp and publish state to MQTT thermostat.update(currentTemp); + // Publish state to MQTT every second (or on state change, if you want to optimize) mqtt_publish_state(mqttClient, thermostat.getMode(), thermostat.getTargetTemp(), thermostat.isHeating()); + // Delay to avoid flooding MQTT with messages. Adjust as needed for your use case (e.g., publish on state change + // instead of every loop). delay(1000); } diff --git a/Thermostat/src/web_config.cpp b/Thermostat/src/web_config.cpp index 975cf6b..2bef3d4 100644 --- a/Thermostat/src/web_config.cpp +++ b/Thermostat/src/web_config.cpp @@ -15,22 +15,32 @@ bool shouldSaveConfigFlag = false; #define CFG_EEPROM_SIZE 512 #define CFG_STRLEN 32 +/** + * Config struct for EEPROM storage. + */ struct ConfigData { - char wifi_ssid[CFG_STRLEN]; - char wifi_pass[CFG_STRLEN]; - char mqtt_server[CFG_STRLEN]; - char mqtt_user[CFG_STRLEN]; - char mqtt_pass[CFG_STRLEN]; - char temp_sensor_id[CFG_STRLEN]; - char mqtt_device_id[CFG_STRLEN]; - char mqtt_temp_topic[CFG_STRLEN]; - int mqtt_port; - float preset_confort; - float preset_eco; - float preset_boost; - float preset_hors_gel; + char wifi_ssid[CFG_STRLEN]; // Wifi SSID + char wifi_pass[CFG_STRLEN]; // Wifi Password + char mqtt_server[CFG_STRLEN]; // MQTT Server + char mqtt_user[CFG_STRLEN]; // MQTT User + char mqtt_pass[CFG_STRLEN]; // MQTT Password + char temp_sensor_id[CFG_STRLEN]; // Temperature Sensor ID + char mqtt_device_id[CFG_STRLEN]; // MQTT Device ID + char mqtt_temp_topic[CFG_STRLEN]; // MQTT Temperature Topic + int mqtt_port; // MQTT Port + float preset_confort; // Confort Mode Temperature + float preset_eco; // Eco Mode Temperature + float preset_boost; // Boost Mode Temperature + float preset_hors_gel; // Hors Gel Mode Temperature }; + +/** + * Config saving. In a production system, consider adding error handling and validation (e.g., check string lengths, + * valid port range, etc.). + * NB: config is stored as a struct for simplicity, but this means that any change to the struct layout will + * break existing configs. In a production system, consider using a more robust format ( + */ void save_config() { ConfigData cfg; memset(&cfg, 0, sizeof(cfg)); @@ -52,6 +62,12 @@ void save_config() { EEPROM.commit(); } +/** + * Config loading with basic validation. If invalid, defaults will be used and saved on next web config save. + * NB: config is stored as a struct for simplicity, but this means that any change to the struct layout will break + * existing configs. In a production system, consider using a more robust format (e.g., JSON with versioning). + * + */ void load_config() { ConfigData cfg; EEPROM.begin(CFG_EEPROM_START + sizeof(ConfigData)); @@ -74,12 +90,68 @@ void load_config() { } } +/** + * Web config setup. This will block until WiFi is configured, which is fine for initial setup but may not be ideal + * for all use cases. + * + * If config parameters are defined in EEPROm, try to connect to WiFi. If connection fails, start config portal. + * If parameters are not defined, start config portal directly. + * On config save, set shouldSaveConfigFlag to true so that main loop can save the config to EEPROM. + * This is a bit of a hack, but it allows us to avoid blocking the main loop while waiting for user input. + */ void setup_web_config() { WiFiManager wm; - // Add custom parameters for MQTT, presets, sensor id - // On save, set shouldSaveConfigFlag = true - wm.autoConnect("ThermostatConfig"); - if (shouldSaveConfigFlag) save_config(); + + // WiFiManagerParameter: id, placeholder, default, length + WiFiManagerParameter custom_mqtt_server("mqtt_server", "MQTT Server", mqtt_server.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_mqtt_port("mqtt_port", "MQTT Port", String(mqtt_port).c_str(), 6); + WiFiManagerParameter custom_mqtt_user("mqtt_user", "MQTT User", mqtt_user.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_mqtt_pass("mqtt_pass", "MQTT Password", mqtt_pass.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_temp_sensor_id("temp_sensor_id", "Temp Sensor ID", temp_sensor_id.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_mqtt_device_id("mqtt_device_id", "MQTT Device ID", mqtt_device_id.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_mqtt_temp_topic("mqtt_temp_topic", "MQTT Temp Topic", mqtt_temp_topic.c_str(), CFG_STRLEN); + WiFiManagerParameter custom_preset_confort("preset_confort", "Preset Confort", String(preset_confort).c_str(), 8); + WiFiManagerParameter custom_preset_eco("preset_eco", "Preset Eco", String(preset_eco).c_str(), 8); + WiFiManagerParameter custom_preset_boost("preset_boost", "Preset Boost", String(preset_boost).c_str(), 8); + WiFiManagerParameter custom_preset_hors_gel("preset_hors_gel", "Preset Hors Gel", String(preset_hors_gel).c_str(), 8); + + wm.addParameter(&custom_mqtt_server); + wm.addParameter(&custom_mqtt_port); + wm.addParameter(&custom_mqtt_user); + wm.addParameter(&custom_mqtt_pass); + wm.addParameter(&custom_temp_sensor_id); + wm.addParameter(&custom_mqtt_device_id); + wm.addParameter(&custom_mqtt_temp_topic); + wm.addParameter(&custom_preset_confort); + wm.addParameter(&custom_preset_eco); + wm.addParameter(&custom_preset_boost); + wm.addParameter(&custom_preset_hors_gel); + + wm.setSaveConfigCallback([]() { + shouldSaveConfigFlag = true; + }); + + if (!wm.autoConnect("ThermostatConfig")) { + // If failed to connect or configure, restart or handle error + ESP.restart(); + } + + // If config was changed, update variables and save + if (shouldSaveConfigFlag) { + mqtt_server = custom_mqtt_server.getValue(); + mqtt_port = String(custom_mqtt_port.getValue()).toInt(); + mqtt_user = custom_mqtt_user.getValue(); + mqtt_pass = custom_mqtt_pass.getValue(); + temp_sensor_id = custom_temp_sensor_id.getValue(); + mqtt_device_id = custom_mqtt_device_id.getValue(); + mqtt_temp_topic = custom_mqtt_temp_topic.getValue(); + preset_confort = String(custom_preset_confort.getValue()).toFloat(); + preset_eco = String(custom_preset_eco.getValue()).toFloat(); + preset_boost = String(custom_preset_boost.getValue()).toFloat(); + preset_hors_gel = String(custom_preset_hors_gel.getValue()).toFloat(); + save_config(); + shouldSaveConfigFlag = false; + } } void handle_web_config() {