# 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