From aa06085f5ba9bf90dfac67779144e4c5bf9d07d8 Mon Sep 17 00:00:00 2001 From: Serge NOEL Date: Mon, 16 Mar 2026 11:20:10 +0100 Subject: [PATCH] Version OK avec Mqtt --- README.md | 296 +++++++++++++++++++++++++++ data/index.html | 32 +++ include/main.h | 7 + include/mqtt_handler.h | 12 ++ include/preset.h | 8 + include/thermostat.h | 21 ++ include/web_config.h | 32 +++ include/web_routes.h | 2 + include/web_server_instance.h | 4 + monitor.log | 367 ++++++++++++++++++++++++++++++++++ platformio.ini | 16 ++ src/main.cpp | 151 ++++++++++++++ src/mqtt_handler.cpp | 103 ++++++++++ src/preset.cpp | 39 ++++ src/thermostat.cpp | 50 +++++ src/web_config.cpp | 126 ++++++++++++ src/web_routes.cpp | 126 ++++++++++++ src/web_server_instance.cpp | 3 + 18 files changed, 1395 insertions(+) create mode 100644 README.md create mode 100644 data/index.html create mode 100644 include/main.h create mode 100644 include/mqtt_handler.h create mode 100644 include/preset.h create mode 100644 include/thermostat.h create mode 100644 include/web_config.h create mode 100644 include/web_routes.h create mode 100644 include/web_server_instance.h create mode 100644 monitor.log create mode 100644 platformio.ini create mode 100644 src/main.cpp create mode 100644 src/mqtt_handler.cpp create mode 100644 src/preset.cpp create mode 100644 src/thermostat.cpp create mode 100644 src/web_config.cpp create mode 100644 src/web_routes.cpp create mode 100644 src/web_server_instance.cpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..24affba --- /dev/null +++ b/README.md @@ -0,0 +1,296 @@ +# Thermostat Project for Sonoff Basic R2 + +This project implements a WiFi thermostat using a Sonoff Basic R2, designed for integration with Home Assistant via MQTT. It supports preset modes (confort, eco, off, boost), receives room temperature from an MQTT gateway, and provides a fallback WiFi configuration portal for setup. + +## Features +- MQTT-based Home Assistant integration as a thermostat device (with preset modes) +- Receives room temperature from an external MQTT sensor (e.g., Xiaomi) +- Fallback WiFi configuration page for setting WiFi, MQTT server, preset temperatures, and device ID +- Configurable preset temperatures (confort, eco, boost, hors gel) +- Clean code structure for maintainability + +## Project Structure +- `src/` : Main application logic +- `include/` : Header files +- `data/` : Static files for web configuration portal +- `platformio.ini` : PlatformIO project configuration +- `README.md` : This documentation + +## Getting Started + +### 1. Prerequisites +- PlatformIO extension for VS Code +- Sonoff Basic R2 device +- MQTT broker (e.g., Mosquitto) +- Home Assistant instance + +### 2. Build & Upload +1. Clone this repository or copy the folder to your PlatformIO workspace. +2. Edit `platformio.ini` if needed (WiFi/MQTT credentials can be set via the web portal after first boot). +3. Build and upload the firmware to your Sonoff Basic R2. + +### 3. First Boot & Configuration +- On first boot (or if WiFi/MQTT fails), the device starts a WiFi AP for configuration. +- Connect to the AP and open the captive portal to set: + - WiFi SSID/password + - MQTT server/port/credentials + - Preset temperatures (confort, eco, boost, hors gel) + - Device ID for temperature sensor + +### 4. Home Assistant Integration +- The device publishes/receives via MQTT using the Home Assistant climate platform. +- Preset modes (confort, eco, off, boost) are supported and can be set from Home Assistant. +- The device subscribes to a temperature topic (e.g., from a Xiaomi sensor via Zigbee2MQTT). + +## Home Assistant Integration + +### MQTT Topics + +The thermostat uses the following MQTT topics: + +**Temperature Input (Subscribe):** +``` +home/OMG_ESP32_BLE/BTtoMQTT/ +``` +- The device subscribes to receive temperature updates from your sensor +- Example: `home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64` +- Payload format: `{"tempc": 21.5, "hum": 45.2, "batt": 85, ...}` +- Only the `tempc` field is required + +**Thermostat State (Publish):** +``` +home/thermostat//state +``` +- The device publishes its current state +- Payload format: `{"mode": 1, "target": 21.0, "heating": true}` + +**Thermostat Commands (Subscribe):** +``` +home/thermostat//set +``` +- Home Assistant sends commands to control the thermostat +- Payload format: `{"mode": 1, "target": 22.0}` + +### Manual Configuration in Home Assistant + +Add the following to your Home Assistant `configuration.yaml`: + +```yaml +mqtt: + climate: + - name: "Living Room Thermostat" + unique_id: "thermostat_living_room" + + # Current temperature from sensor + current_temperature_topic: "home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64" + current_temperature_template: "{{ value_json.tempc }}" + + # Temperature control + temperature_command_topic: "home/thermostat/sonoff_thermo_01/set" + temperature_state_topic: "home/thermostat/sonoff_thermo_01/state" + temperature_state_template: "{{ value_json.target }}" + + # Mode control + mode_command_topic: "home/thermostat/sonoff_thermo_01/set" + mode_command_template: '{"mode": {% if value == "off" %}0{% elif value == "heat" %}1{% endif %}}' + mode_state_topic: "home/thermostat/sonoff_thermo_01/state" + mode_state_template: > + {% if value_json.mode == 0 %}off + {% elif value_json.mode == 1 %}heat + {% else %}off{% endif %} + modes: + - "off" + - "heat" + + # Preset modes (confort, eco, boost, hors gel) + preset_mode_command_topic: "home/thermostat/sonoff_thermo_01/set" + preset_mode_command_template: > + {"mode": {% if value == "comfort" %}1 + {% elif value == "eco" %}2 + {% elif value == "boost" %}3 + {% elif value == "away" %}4 + {% else %}0{% endif %}} + preset_mode_state_topic: "home/thermostat/sonoff_thermo_01/state" + preset_mode_value_template: > + {% if value_json.mode == 1 %}comfort + {% elif value_json.mode == 2 %}eco + {% elif value_json.mode == 3 %}boost + {% elif value_json.mode == 4 %}away + {% else %}none{% endif %} + preset_modes: + - "comfort" + - "eco" + - "boost" + - "away" + + # Temperature settings + min_temp: 5 + max_temp: 30 + temp_step: 0.5 + precision: 0.1 + +sensor: + - platform: mqtt + name: "Living Room Temperature" + state_topic: "home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64" + value_template: "{{ value_json.tempc }}" + unit_of_measurement: "°C" + device_class: temperature + + - platform: mqtt + name: "Living Room Humidity" + state_topic: "home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64" + value_template: "{{ value_json.hum }}" + unit_of_measurement: "%" + device_class: humidity + +binary_sensor: + - platform: mqtt + name: "Living Room Thermostat Heating" + state_topic: "home/thermostat/sonoff_thermo_01/state" + value_template: "{{ value_json.heating }}" + payload_on: true + payload_off: false + device_class: heat +``` + +**Important:** Replace: +- `A4C1389ADA64` with your Xiaomi sensor's MAC address (without colons) +- `sonoff_thermo_01` with your device ID configured in the web portal + +### Using the Thermostat in Home Assistant + +After configuration and restart, you can: + +1. **Set Temperature:** Use the climate card to adjust target temperature +2. **Change Modes:** + - **Off:** Heating disabled + - **Heat:** Heating enabled with current preset +3. **Select Presets:** + - **Comfort:** Standard comfort temperature (e.g., 21°C) + - **Eco:** Energy-saving mode (e.g., 19°C) + - **Boost:** Maximum heating (e.g., 24°C) + - **Away (Hors Gel):** Frost protection (e.g., 7°C) + +### Automation Example + +```yaml +automation: + - alias: "Thermostat Night Mode" + trigger: + - platform: time + at: "22:00:00" + action: + - service: climate.set_preset_mode + target: + entity_id: climate.living_room_thermostat + data: + preset_mode: "eco" + + - alias: "Thermostat Morning Mode" + trigger: + - platform: time + at: "06:30:00" + condition: + - condition: state + entity_id: binary_sensor.workday + state: "on" + action: + - service: climate.set_preset_mode + target: + entity_id: climate.living_room_thermostat + data: + preset_mode: "comfort" +``` + +### Lovelace Card Example + +```yaml +type: thermostat +entity: climate.living_room_thermostat +features: + - type: climate-preset-modes + preset_modes: + - comfort + - eco + - boost + - away +``` + +### Troubleshooting + +**No temperature updates:** +1. Check MQTT broker logs: `mosquitto_sub -h localhost -t "home/OMG_ESP32_BLE/BTtoMQTT/#" -v` +2. Verify sensor MAC address matches configuration (use uppercase without colons) +3. Check sensor battery level +4. Ensure sensor is in range of BLE gateway + +**Thermostat not responding to commands:** +1. Verify MQTT topics match your device ID +2. Check MQTT broker connection from Home Assistant +3. Monitor device serial output for errors +4. Ensure MQTT buffer size is set to 512 bytes (see `platformio.ini`) + +**Important Note:** The default MQTT buffer size for PubSubClient is 128 bytes, which is too small for Xiaomi sensor payloads (~317 bytes). This project increases it to 512 bytes via the build flag `-DMQTT_MAX_PACKET_SIZE=512` in `platformio.ini`. + +### 5. File Overview +- `src/main.cpp` : Main application entry point +- `src/thermostat.cpp` / `include/thermostat.h` : Thermostat logic +- `src/mqtt_handler.cpp` / `include/mqtt_handler.h` : MQTT communication +- `src/web_config.cpp` / `include/web_config.h` : WiFi/MQTT/web config portal +- `src/preset.cpp` / `include/preset.h` : Preset management +- `data/` : HTML/CSS/JS for configuration portal + +## Example MQTT Topics +- Temperature: `home/room/temperature/` +- State: `home/thermostat//state` +- Command: `home/thermostat//set` + +## Over-The-Air (OTA) Updates + +The thermostat supports OTA updates, allowing you to upload new firmware wirelessly without physical access to the device. + +### Using OTA with PlatformIO + +1. **Ensure the device is connected to WiFi** and note its IP address from the serial monitor + +2. **Configure OTA upload in platformio.ini** (optional - for easier uploads): + ```ini + upload_protocol = espota + upload_port = + ``` + +3. **Upload via OTA**: + ```bash + # Using PlatformIO CLI + platformio run --target upload --upload-port + + # Or use the PlatformIO IDE upload button after setting upload_protocol + ``` + +### Using OTA with Arduino IDE + +1. Open **Tools > Port** and select the network port (shows as ` at `) +2. Click **Upload** as normal + +### OTA Behavior + +- During OTA update, the LED stays solid ON +- Progress is shown in the serial monitor +- Device automatically reboots after successful update +- If OTA fails, the device continues running the existing firmware + +### Security Note + +By default, OTA has no password protection. For production use, add a password: +```cpp +ArduinoOTA.setPassword("your-password-here"); +``` + +## Advanced +- Fallback to AP mode if WiFi or MQTT fails +- All configuration is stored in flash and can be reset via the web portal +- OTA updates for remote firmware deployment + +## License +MIT diff --git a/data/index.html b/data/index.html new file mode 100644 index 0000000..50395af --- /dev/null +++ b/data/index.html @@ -0,0 +1,32 @@ + + + + + Thermostat Config + + + + +

Thermostat WiFi & MQTT Config

+
+ + + + + + + + + + + + + +
+ + diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..4d675d5 --- /dev/null +++ b/include/main.h @@ -0,0 +1,7 @@ + + +//GPIO12 // Relay +//GPIO13 // LED + +#define LED_PIN 13 +#define RELAY_PIN 12 \ No newline at end of file diff --git a/include/mqtt_handler.h b/include/mqtt_handler.h new file mode 100644 index 0000000..1235ad4 --- /dev/null +++ b/include/mqtt_handler.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include "thermostat.h" + +extern float currentTemp; // Global temperature variable updated by MQTT callback + +bool mqtt_connect(PubSubClient& client); +void mqtt_loop(PubSubClient& client); +void mqtt_publish_state(PubSubClient& client, ThermostatMode mode, float targetTemp, bool heating); +void mqtt_callback(char* topic, byte* payload, unsigned int length); + diff --git a/include/preset.h b/include/preset.h new file mode 100644 index 0000000..6553dc1 --- /dev/null +++ b/include/preset.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include "thermostat.h" + +void load_presets(); +void save_presets(); +float get_preset_temp(ThermostatMode mode); +void set_preset_temp(ThermostatMode mode, float temp); diff --git a/include/thermostat.h b/include/thermostat.h new file mode 100644 index 0000000..921fa3e --- /dev/null +++ b/include/thermostat.h @@ -0,0 +1,21 @@ +#pragma once +#include + +enum ThermostatMode { MODE_OFF, MODE_CONFORT, MODE_ECO, MODE_BOOST, MODE_HORS_GEL }; + +class Thermostat { +public: + Thermostat(); + void setMode(ThermostatMode mode); + void setTemperature(float temp); + void setPresetTemp(ThermostatMode mode, float temp); + void update(float currentTemp); + bool isHeating() const; + ThermostatMode getMode() const; + float getTargetTemp() const; +private: + ThermostatMode mode; + float presetTemps[5]; + float targetTemp; + bool heating; +}; diff --git a/include/web_config.h b/include/web_config.h new file mode 100644 index 0000000..2e0ffd4 --- /dev/null +++ b/include/web_config.h @@ -0,0 +1,32 @@ +#pragma once +#include + +void setup_web_config(); +void handle_web_config(); +bool should_save_config(); +void save_config(); +void load_config(); + +#define CFG_STRLEN 64 + +/** + * Config struct for EEPROM storage. + */ +struct ConfigData +{ + 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 +}; + +extern ConfigData config; diff --git a/include/web_routes.h b/include/web_routes.h new file mode 100644 index 0000000..c9b074a --- /dev/null +++ b/include/web_routes.h @@ -0,0 +1,2 @@ +#pragma once +void setup_web_routes(); diff --git a/include/web_server_instance.h b/include/web_server_instance.h new file mode 100644 index 0000000..31b6eb2 --- /dev/null +++ b/include/web_server_instance.h @@ -0,0 +1,4 @@ +#include + +// Declare a global server instance on port 80 +extern AsyncWebServer server; diff --git a/monitor.log b/monitor.log new file mode 100644 index 0000000..8ce12e4 --- /dev/null +++ b/monitor.log @@ -0,0 +1,367 @@ +--- Terminal on /dev/ttyUSB0 | 115200 8-N-1 +--- Available filters and text transformations: debug, default, direct, esp8266_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time +--- More details at https://bit.ly/pio-monitor-filters +--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H +␀ +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1388F5F89 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:8F:5F:89","mac_type":0,"adv_type":0,"rssi":-80,"servicedata":"895f8f38c1a462074d16e20a536b0e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-88} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-86} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-87} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-88,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1388F5F89 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:8F:5F:89","mac_type":0,"adv_type":0,"rssi":-84,"servicedata":"895f8f38c1a465074d16e20a536c0e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-91} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-84,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-90} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-87} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:9A:DA:64","mac_type":0,"adv_type":0,"rssi":-63,"servicedata":"64da9a38c1a45907a316580a40e60e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> OK! MQTT topic matches temp sensor ID. Processing message... + -> SUCCESS! Received tempc from MQTT: 18.81 °C +Current temperature (polled): 18.81 +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C138CF2D7E + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:CF:2D:7E","mac_type":0,"adv_type":0,"rssi":-84,"servicedata":"7e2dcf38c1a43208d812970a49f60e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-89,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-73} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-81,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-90} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1388F5F89 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:8F:5F:89","mac_type":0,"adv_type":0,"rssi":-81,"servicedata":"895f8f38c1a461074e16e20a536e0e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-66} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-84} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C138CF2D7E + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:CF:2D:7E","mac_type":0,"adv_type":0,"rssi":-78,"servicedata":"7e2dcf38c1a43208d812970a49f60e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-88} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-98} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-84} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"name":"[TV] Samsung AU7095 65 TV","manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-72} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-86} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"name":"ATC_41E067","rssi":-88,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id" + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:9A:DA:64","mac_type":0,"adv_type":0,"rssi":-68,"servicedata":"64da9a38c1a45a079a16580a40e70e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> OK! MQTT topic matches temp sensor ID. Processing message... + -> SUCCESS! Received tempc from MQTT: 18.82 °C +Current temperature (polled): 18.82 +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-67} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-94} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-72} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-83} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-86,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-96} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-93} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-72} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1388F5F89 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:8F:5F:89","mac_type":0,"adv_type":0,"rssi":-80,"servicedata":"895f8f38c1a466074e16e30a53700e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-84,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-83} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-67} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-94} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:9A:DA:64","mac_type":0,"adv_type":0,"rssi":-69,"servicedata":"64da9a38c1a45b078f16590a40e90e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> OK! MQTT topic matches temp sensor ID. Processing message... + -> SUCCESS! Received tempc from MQTT: 18.83 °C +Current temperature (polled): 18.83 +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-86} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204012066210f0002014101010001000000000000000006","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-82} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-84,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-67} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-87} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-87,"servicedata":"a4c13841e067009542550b9bdd","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-94} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-81} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C138CF2D7E + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:CF:2D:7E","mac_type":0,"adv_type":0,"rssi":-84,"servicedata":"7e2dcf38c1a42e08d712970a49f90e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C1388F5F89 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:8F:5F:89","mac_type":0,"adv_type":0,"rssi":-80,"servicedata":"895f8f38c1a462074d16e30a53710e","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJW + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-67} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/66FC2A8FC38F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"66:FC:2A:8F:C3:8F","mac_type":1,"adv_type":0,"rssi":-87} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/A4C13841E067 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"A4:C1:38:41:E0:67","mac_type":0,"adv_type":0,"rssi":-85,"servicedata":"a4c13841e067009642550b9bde","servicedatauuid":"0x181a","brand":"Xiaomi","model":"TH Sensor","model_id":"LYWSD03MMC/MJWSD05 + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-84} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/43A69133165F + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"43:A6:91:33:16:5F","mac_type":1,"adv_type":0,"rssi":-83,"servicedata":"0000000000000000000000000000000000000000","servicedatauuid":"0xfe9f"} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/E0036BF020BF + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"E0:03:6B:F0:20:BF","mac_type":0,"adv_type":0,"manufacturerdata":"75004204010166e0036bf020bfe2036bf020be01580000000000","rssi":-74} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. +Topic: home/OMG_ESP32_BLE/BTtoMQTT/6FF06B19BD96 + Searching for: 'A4C1389ADA64' in topic + Payload: {"id":"6F:F0:6B:19:BD:96","mac_type":1,"adv_type":0,"rssi":-84} + -> MQTT topic does not match expected temp sensor ID. Ignoring message. diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..ac951bd --- /dev/null +++ b/platformio.ini @@ -0,0 +1,16 @@ +[env:sonoff_basic] +platform = espressif8266 +board = sonoff_basic +framework = arduino +monitor_speed = 115200 +; upload_protocol = espota +; upload_port = 192.168.1.95 +upload_speed = 115200 +build_flags = + -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY + -DMQTT_MAX_PACKET_SIZE=512 +lib_deps = + knolleary/PubSubClient + tzapu/WiFiManager + bblanchon/ArduinoJson + me-no-dev/ESPAsyncWebServer diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..73a49fb --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include "thermostat.h" +#include "mqtt_handler.h" +#include "web_config.h" +#include "preset.h" +#include "web_routes.h" +#include "main.h" + +#include "web_server_instance.h" + +WiFiClient espClient; +PubSubClient mqttClient(espClient); +Thermostat thermostat; +Ticker ledTicker; + +float currentTemp = 0.0; +float oldTemp = 0.0; + +#define LED_PIN 13 // Sonoff Basic LED pin + +// Toggle LED state +void toggleLED() { + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); +} + +/** + * Initialize serial, load configuration and presets, connect to WiFi and MQTT, and set up the thermostat. + * + */ +void setup() { + int i; + // Turn on LED to indicate startup (will turn off when setup is complete) + pinMode(LED_PIN, OUTPUT); + pinMode(RELAY_PIN, OUTPUT); + // Start with LED ON to indicate startup + digitalWrite(LED_PIN, LOW); + digitalWrite(RELAY_PIN, HIGH); // Ensure relay is off at startup + ledTicker.attach(0.2, toggleLED); + + Serial.begin(115200); + i=0; + + // 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 - Version 1.0"); + // Serial.print("WiFi SSID: "); Serial.println(config.wifi_ssid); + // Serial.print("MQTT Server: "); Serial.println(config.mqtt_server); + // Serial.print("MQTT Port: "); Serial.println(config.mqtt_port); + // Serial.print("MQTT User: "); Serial.println(config.mqtt_user); + // Serial.print("MQTT Device ID: "); Serial.println(config.mqtt_device_id); + // Serial.print("MQTT Temp Topic: "); Serial.println(config.mqtt_temp_topic); + // Serial.print("Temp Sensor ID: "); Serial.println(config.temp_sensor_id); + // Serial.print("Preset Confort: "); Serial.println(config.preset_confort); + // Serial.print("Preset Eco: "); Serial.println(config.preset_eco); + // Serial.print("Preset Boost: "); Serial.println(config.preset_boost); + // Serial.print("Preset Hors Gel: "); Serial.println(config.preset_hors_gel); + + Serial.println("Connecting to WiFi..."); + // setup wifi and mqtt, and load presets into thermostat + WiFi.begin(config.wifi_ssid, config.wifi_pass); + // Display wifi config + i=0; + while (WiFi.status() != WL_CONNECTED) { + + Serial.print("."); + i++; + if (i > 30) { // After 30 seconds of trying to connect, start config portal + Serial.println("\nFailed to connect to WiFi. Starting config portal..."); + ledTicker.attach(0.5, toggleLED); + setup_web_config(); + break; + } + delay(1000); + } + Serial.println("\nConnected to WiFi!"); + ledTicker.detach(); + digitalWrite(LED_PIN, LOW); + // Display IP + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); + setup_web_routes(); + server.begin(); + Serial.println("Connecting to MQTT..."); + mqttClient.setServer(config.mqtt_server, config.mqtt_port); + mqttClient.setCallback(mqtt_callback); + + // Display MQTT buffer size + Serial.print("MQTT buffer size: "); + Serial.print(mqttClient.getBufferSize()); + Serial.println(" bytes"); + + Serial.print("MQTT Client configured. Attempting to connect..."); + mqttClient.connect(config.mqtt_device_id, config.mqtt_user, config.mqtt_pass); + + if (mqttClient.connected()) { + Serial.println("MQTT Connected!"); + // Subscribe with wildcard to get all sensors + String topic = String(config.mqtt_temp_topic) + "/#"; + Serial.print("Subscribing to topic: "); + Serial.println(topic); + bool subResult = mqttClient.subscribe(topic.c_str()); + Serial.print("Subscription result: "); + Serial.println(subResult ? "SUCCESS" : "FAILED"); + } else { + Serial.print("MQTT Connection FAILED, state: "); + Serial.println(mqttClient.state()); + } + + // Start LED blinking to indicate normal operation (blink every 2 seconds) + ledTicker.attach(2.0, toggleLED); + + Serial.println("Setup complete. Entering main loop..."); + + delay(1000); // Short delay to ensure LED state is visible before turning off + digitalWrite(RELAY_PIN, HIGH); // Ensure relay is on + delay(1000); // Short delay to ensure relay state is stable before turning off LED + digitalWrite(RELAY_PIN, LOW); + // Publsh initial state to MQTT to inform Home Assistant of current thermostat status on startup + + mqtt_publish_state(mqttClient, thermostat.getMode(), thermostat.getTargetTemp(), thermostat.isHeating()); +} + +int j = 0; +void loop() +{ + // Handle OTA updates + ArduinoOTA.handle(); + + // Ask Mqtt to process incoming messages and maintain connection + mqtt_loop(mqttClient); + + // Poll the current temperature (updated asynchronously by MQTT callback) + if (currentTemp != oldTemp) { + Serial.print("Temperature change detected: "); + Serial.println(currentTemp); + oldTemp = currentTemp; + } + + // // 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(10); +} diff --git a/src/mqtt_handler.cpp b/src/mqtt_handler.cpp new file mode 100644 index 0000000..9d24662 --- /dev/null +++ b/src/mqtt_handler.cpp @@ -0,0 +1,103 @@ + +#include "mqtt_handler.h" +#include "thermostat.h" +#include +#include "web_config.h" + +// Helper function to normalize MAC address (remove colons, convert to uppercase) +String normalizeMac(const char* mac) { + String normalized = ""; + for (int i = 0; mac[i] != '\0'; i++) { + if (mac[i] != ':') { + normalized += (char)toupper(mac[i]); + } + } + return normalized; +} + +// Variables now defined in web_config.cpp + +// Process incoming MQTT messages asynchronously +// The callback (mqtt_callback) is invoked automatically when messages arrive +void mqtt_loop(PubSubClient& client) { + client.loop(); +} + + +void mqtt_publish_state(PubSubClient& client, ThermostatMode mode, float targetTemp, bool heating) { + JsonDocument doc; + doc["mode"] = mode; + doc["target"] = targetTemp; + doc["heating"] = heating; + char buf[128]; + size_t n = serializeJson(doc, buf); + String topic = String("home/thermostat/") + String(config.mqtt_device_id) + String("/state"); + client.publish(topic.c_str(), buf, n); +} + +void mqtt_callback(char* topic, byte* payload, unsigned int length) +{ + static bool first_call = true; + static String normalized_sensor_id; + + if (first_call) { + // Serial.print("Looking for sensor ID: "); + // Serial.println(config.temp_sensor_id); + + // FIX: Normalize the sensor ID to match topic format + // Topics come as: home/OMG_ESP32_BLE/BTtoMQTT/A4C1389ADA64 (no colons, uppercase) + // Config may have: A4:C1:38:9A:DA:64 (with colons) + // Solution: Remove colons and convert to uppercase for comparison + normalized_sensor_id = normalizeMac(config.temp_sensor_id); + + // TESTING: Uncomment to test with a sensor that's actually broadcasting + // normalized_sensor_id = "A4C1389ADA64"; // Your Xiaomi (NOT broadcasting) + // normalized_sensor_id = "E0036BF020BF"; // Test with active sensor + // normalized_sensor_id = "74CBD1F131B6"; // Test with active sensor + + // Serial.print("Normalized sensor ID: "); + // Serial.println(normalized_sensor_id); + first_call = false; + } + + // Serial.print("Topic: "); + // Serial.println(topic); + + // Debug: Print what we're comparing + // Serial.print(" Searching for: '"); + // Serial.print(normalized_sensor_id); + // Serial.println("' in topic"); + + // Print payload for debugging (first 200 chars) + // Serial.print(" Payload: "); + // for (unsigned int i = 0; i < length && i < 200; i++) { + // Serial.write(payload[i]); + // } + // Serial.println(); + + // Check if topic contains the normalized sensor ID + if(strstr(topic, normalized_sensor_id.c_str()) == nullptr) { + // Serial.println(" -> MQTT topic does not match expected temp sensor ID. Ignoring message."); + return; + } + + // Parse JSON payload from subscribed topic + JsonDocument doc; + // Serial.println(" -> OK! MQTT topic matches temp sensor ID. Processing message..."); + DeserializationError err = deserializeJson(doc, payload, length); + if (err) { + Serial.print(" -> MQTT JSON parse error: "); + Serial.println(err.c_str()); + return; + } + + // Check for temperature field + if (doc["tempc"].is()) { + currentTemp = doc["tempc"].as(); + // Serial.print(" -> SUCCESS! Received tempc from MQTT: "); + // Serial.print(currentTemp); + // Serial.println(" °C"); + } else { + Serial.println(" -> WARNING: No 'tempc' field found in JSON payload"); + } +} diff --git a/src/preset.cpp b/src/preset.cpp new file mode 100644 index 0000000..d59a10b --- /dev/null +++ b/src/preset.cpp @@ -0,0 +1,39 @@ +#include "preset.h" +#include + +static float presets[5] = {0, 20.0, 17.0, 22.0, 7.0}; +#define PRESET_EEPROM_START 0 +#define PRESET_COUNT 5 +#define PRESET_EEPROM_SIZE (PRESET_COUNT * sizeof(float)) + +void load_presets() { + EEPROM.begin(PRESET_EEPROM_SIZE); + bool valid = true; + for (int i = 0; i < PRESET_COUNT; ++i) { + float value = 0; + EEPROM.get(PRESET_EEPROM_START + i * sizeof(float), value); + // Check for uninitialized EEPROM (NaN or out of range) + if (isnan(value) || value < 0 || value > 50) { + valid = false; + break; + } + presets[i] = value; + } + if (!valid) { + // If invalid, write defaults + save_presets(); + } +} +void save_presets() { + for (int i = 0; i < PRESET_COUNT; ++i) { + EEPROM.put(PRESET_EEPROM_START + i * sizeof(float), presets[i]); + } + EEPROM.commit(); +} +float get_preset_temp(ThermostatMode mode) { + return presets[mode]; +} +void set_preset_temp(ThermostatMode mode, float temp) { + presets[mode] = temp; + save_presets(); +} diff --git a/src/thermostat.cpp b/src/thermostat.cpp new file mode 100644 index 0000000..a9df4fe --- /dev/null +++ b/src/thermostat.cpp @@ -0,0 +1,50 @@ +#include "thermostat.h" + +Thermostat::Thermostat() : mode(MODE_OFF), targetTemp(0), heating(false) { + presetTemps[MODE_CONFORT] = 20.0; + presetTemps[MODE_ECO] = 17.0; + presetTemps[MODE_BOOST] = 22.0; + presetTemps[MODE_HORS_GEL] = 7.0; + presetTemps[MODE_OFF] = 0.0; +} + +/** + * Set the thermostat mode. This will automatically update the target temperature to the preset for that mode. + */ +void Thermostat::setMode(ThermostatMode m) { + mode = m; + targetTemp = presetTemps[mode]; +} + +/** + * Manually set the target temperature. This does not change the mode or presets, but will override the preset for the + * current mode until the mode is changed again. + */ +void Thermostat::setTemperature(float temp) { + targetTemp = temp; +} + +/** + * Set the preset temperature for a specific mode. If the current mode is the one being updated, also update the + * target temperature. + */ +void Thermostat::setPresetTemp(ThermostatMode m, float temp) { + presetTemps[m] = temp; + if (mode == m) targetTemp = temp; +} + +/** + * Update the heating state based on the current temperature and target temperature. + * this is real simple logic: if current temp is below target, turn on heating, otherwise turn it off. In a real system, you would want to add some hysteresis to prevent rapid on/off cycling. + */ +void Thermostat::update(float currentTemp) { + if (mode == MODE_OFF) { + heating = false; + } else { + heating = (currentTemp < targetTemp); + } +} + +bool Thermostat::isHeating() const { return heating; } +ThermostatMode Thermostat::getMode() const { return mode; } +float Thermostat::getTargetTemp() const { return targetTemp; } diff --git a/src/web_config.cpp b/src/web_config.cpp new file mode 100644 index 0000000..299ca09 --- /dev/null +++ b/src/web_config.cpp @@ -0,0 +1,126 @@ + +#include "web_config.h" +#include +#include + + +// String wifi_ssid, wifi_pass, mqtt_server, mqtt_user, mqtt_pass, temp_sensor_id; +// String mqtt_device_id = "thermo1"; +// String mqtt_temp_topic = "home/room/temperature/thermo1"; +// int mqtt_port = 1883; +// float preset_confort = 21.0, preset_eco = 18.0, preset_boost = 23.0, preset_hors_gel = 7.0; +bool shouldSaveConfigFlag = false; + +#define CFG_EEPROM_START 100 +#define CFG_EEPROM_SIZE 512 + + + + +ConfigData config; // Global config variable to hold current config in memory. + // This is what is read/written to EEPROM, and used by the rest of the code. +/** + * 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, + */ +void save_config() { + // Save config to EEPROM + EEPROM.begin(CFG_EEPROM_START + sizeof(ConfigData)); + EEPROM.put(CFG_EEPROM_START, config); + EEPROM.commit(); + // Reboot device to apply new config (e.g., reconnect to WiFi with new credentials) + ESP.restart(); +} + +/** + * Config loading from EEPROM. + * NB: config is stored as a struct for simplicity. + * + */ +void load_config() { + EEPROM.begin(CFG_EEPROM_START + sizeof(ConfigData)); + EEPROM.get(CFG_EEPROM_START, 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; + + // WiFiManagerParameter: id, placeholder, default, length + WiFiManagerParameter custom_mqtt_server("mqtt_server", "MQTT Server", config.mqtt_server, CFG_STRLEN); + WiFiManagerParameter custom_mqtt_port("mqtt_port", "MQTT Port", String(config.mqtt_port).c_str(), 6); + WiFiManagerParameter custom_mqtt_user("mqtt_user", "MQTT User", config.mqtt_user, CFG_STRLEN); + WiFiManagerParameter custom_mqtt_pass("mqtt_pass", "MQTT Password", config.mqtt_pass, CFG_STRLEN); + WiFiManagerParameter custom_temp_sensor_id("temp_sensor_id", "Temp Sensor ID", config.temp_sensor_id, CFG_STRLEN); + WiFiManagerParameter custom_mqtt_device_id("mqtt_device_id", "MQTT Device ID", config.mqtt_device_id, CFG_STRLEN); + WiFiManagerParameter custom_mqtt_temp_topic("mqtt_temp_topic", "MQTT Temp Topic", config.mqtt_temp_topic, CFG_STRLEN); + WiFiManagerParameter custom_preset_confort("preset_confort", "Preset Confort", String(config.preset_confort).c_str(), 8); + WiFiManagerParameter custom_preset_eco("preset_eco", "Preset Eco", String(config.preset_eco).c_str(), 8); + WiFiManagerParameter custom_preset_boost("preset_boost", "Preset Boost", String(config.preset_boost).c_str(), 8); + WiFiManagerParameter custom_preset_hors_gel("preset_hors_gel", "Preset Hors Gel", String(config.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(); + } + + // Always update WiFi credentials after connection + String ssid = WiFi.SSID(); + String pass = WiFi.psk(); + ssid.toCharArray(config.wifi_ssid, CFG_STRLEN); + pass.toCharArray(config.wifi_pass, CFG_STRLEN); + + // If config was changed, update variables and save + if (shouldSaveConfigFlag) { + strncpy(config.mqtt_server, custom_mqtt_server.getValue(), CFG_STRLEN); + config.mqtt_server[CFG_STRLEN-1] = '\0'; + config.mqtt_port = String(custom_mqtt_port.getValue()).toInt(); + strncpy(config.mqtt_user, custom_mqtt_user.getValue(), CFG_STRLEN); + config.mqtt_user[CFG_STRLEN-1] = '\0'; + strncpy(config.mqtt_pass, custom_mqtt_pass.getValue(), CFG_STRLEN); + config.mqtt_pass[CFG_STRLEN-1] = '\0'; + strncpy(config.temp_sensor_id, custom_temp_sensor_id.getValue(), CFG_STRLEN); + config.temp_sensor_id[CFG_STRLEN-1] = '\0'; + strncpy(config.mqtt_device_id, custom_mqtt_device_id.getValue(), CFG_STRLEN); + config.mqtt_device_id[CFG_STRLEN-1] = '\0'; + strncpy(config.mqtt_temp_topic, custom_mqtt_temp_topic.getValue(), CFG_STRLEN); + config.mqtt_temp_topic[CFG_STRLEN-1] = '\0'; + config.preset_confort = String(custom_preset_confort.getValue()).toFloat(); + config.preset_eco = String(custom_preset_eco.getValue()).toFloat(); + config.preset_boost = String(custom_preset_boost.getValue()).toFloat(); + config.preset_hors_gel = String(custom_preset_hors_gel.getValue()).toFloat(); + save_config(); + shouldSaveConfigFlag = false; + } +} + +void handle_web_config() { + // No-op: all web server logic moved to web_routes.cpp +} + +bool should_save_config() { return shouldSaveConfigFlag; } diff --git a/src/web_routes.cpp b/src/web_routes.cpp new file mode 100644 index 0000000..aa9384b --- /dev/null +++ b/src/web_routes.cpp @@ -0,0 +1,126 @@ +#include +#include "web_server_instance.h" +#include "web_config.h" +#include + +const char* config_html_template = R"HTML( + + + + + + +
+

Thermostat Config

+
+ + + + + + + + + + + + + + +
+
+ + +)HTML"; + +String render_config_html() { + String html(config_html_template); + html.replace("%WIFI_SSID%", String(config.wifi_ssid)); + html.replace("%WIFI_PASS%", String(config.wifi_pass)); + html.replace("%MQTT_SERVER%", String(config.mqtt_server)); + html.replace("%MQTT_USER%", String(config.mqtt_user)); + html.replace("%MQTT_PASS%", String(config.mqtt_pass)); + html.replace("%TEMP_SENSOR_ID%", String(config.temp_sensor_id)); + html.replace("%MQTT_DEVICE_ID%", String(config.mqtt_device_id)); + html.replace("%MQTT_TEMP_TOPIC%", String(config.mqtt_temp_topic)); + html.replace("%MQTT_PORT%", String(config.mqtt_port)); + html.replace("%PRESET_CONFORT%", String(config.preset_confort)); + html.replace("%PRESET_ECO%", String(config.preset_eco)); + html.replace("%PRESET_BOOST%", String(config.preset_boost)); + html.replace("%PRESET_HORS_GEL%", String(config.preset_hors_gel)); + return html; +} + +void setup_web_routes() { + // Serve config form at / and /config + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + request->send(200, "text/html", render_config_html()); + }); + server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request){ + request->send(200, "text/html", render_config_html()); + }); + server.on("/config", HTTP_POST, [](AsyncWebServerRequest *request){ + if (request->hasParam("wifi_ssid", true)) { + strncpy(config.wifi_ssid, request->getParam("wifi_ssid", true)->value().c_str(), CFG_STRLEN); + config.wifi_ssid[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("wifi_pass", true)) { + strncpy(config.wifi_pass, request->getParam("wifi_pass", true)->value().c_str(), CFG_STRLEN); + config.wifi_pass[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_server", true)) { + strncpy(config.mqtt_server, request->getParam("mqtt_server", true)->value().c_str(), CFG_STRLEN); + config.mqtt_server[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_user", true)) { + strncpy(config.mqtt_user, request->getParam("mqtt_user", true)->value().c_str(), CFG_STRLEN); + config.mqtt_user[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_pass", true)) { + strncpy(config.mqtt_pass, request->getParam("mqtt_pass", true)->value().c_str(), CFG_STRLEN); + config.mqtt_pass[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("temp_sensor_id", true)) { + strncpy(config.temp_sensor_id, request->getParam("temp_sensor_id", true)->value().c_str(), CFG_STRLEN); + config.temp_sensor_id[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_device_id", true)) { + strncpy(config.mqtt_device_id, request->getParam("mqtt_device_id", true)->value().c_str(), CFG_STRLEN); + config.mqtt_device_id[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_temp_topic", true)) { + strncpy(config.mqtt_temp_topic, request->getParam("mqtt_temp_topic", true)->value().c_str(), CFG_STRLEN); + config.mqtt_temp_topic[CFG_STRLEN-1] = '\0'; + } + if (request->hasParam("mqtt_port", true)) { + config.mqtt_port = request->getParam("mqtt_port", true)->value().toInt(); + } + if (request->hasParam("preset_confort", true)) { + config.preset_confort = request->getParam("preset_confort", true)->value().toFloat(); + } + if (request->hasParam("preset_eco", true)) { + config.preset_eco = request->getParam("preset_eco", true)->value().toFloat(); + } + if (request->hasParam("preset_boost", true)) { + config.preset_boost = request->getParam("preset_boost", true)->value().toFloat(); + } + if (request->hasParam("preset_hors_gel", true)) { + config.preset_hors_gel = request->getParam("preset_hors_gel", true)->value().toFloat(); + } + save_config(); + request->send(200, "text/html", "

Config Saved!

Back"); + }); +} diff --git a/src/web_server_instance.cpp b/src/web_server_instance.cpp new file mode 100644 index 0000000..7459a35 --- /dev/null +++ b/src/web_server_instance.cpp @@ -0,0 +1,3 @@ +#include + +AsyncWebServer server(80); // Global server instance