9.5 KiB
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 logicinclude/: Header filesdata/: Static files for web configuration portalplatformio.ini: PlatformIO project configurationREADME.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
- Clone this repository or copy the folder to your PlatformIO workspace.
- Edit
platformio.iniif needed (WiFi/MQTT credentials can be set via the web portal after first boot). - 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/<SENSOR_MAC_ADDRESS>
- 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
tempcfield is required
Thermostat State (Publish):
home/thermostat/<DEVICE_ID>/state
- The device publishes its current state
- Payload format:
{"mode": 1, "target": 21.0, "heating": true}
Thermostat Commands (Subscribe):
home/thermostat/<DEVICE_ID>/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:
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:
A4C1389ADA64with your Xiaomi sensor's MAC address (without colons)sonoff_thermo_01with your device ID configured in the web portal
Using the Thermostat in Home Assistant
After configuration and restart, you can:
- Set Temperature: Use the climate card to adjust target temperature
- Change Modes:
- Off: Heating disabled
- Heat: Heating enabled with current preset
- 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
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
type: thermostat
entity: climate.living_room_thermostat
features:
- type: climate-preset-modes
preset_modes:
- comfort
- eco
- boost
- away
Troubleshooting
No temperature updates:
- Check MQTT broker logs:
mosquitto_sub -h localhost -t "home/OMG_ESP32_BLE/BTtoMQTT/#" -v - Verify sensor MAC address matches configuration (use uppercase without colons)
- Check sensor battery level
- Ensure sensor is in range of BLE gateway
Thermostat not responding to commands:
- Verify MQTT topics match your device ID
- Check MQTT broker connection from Home Assistant
- Monitor device serial output for errors
- 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 pointsrc/thermostat.cpp/include/thermostat.h: Thermostat logicsrc/mqtt_handler.cpp/include/mqtt_handler.h: MQTT communicationsrc/web_config.cpp/include/web_config.h: WiFi/MQTT/web config portalsrc/preset.cpp/include/preset.h: Preset managementdata/: HTML/CSS/JS for configuration portal
Example MQTT Topics
- Temperature:
home/room/temperature/<device_id> - State:
home/thermostat/<device_id>/state - Command:
home/thermostat/<device_id>/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
-
Ensure the device is connected to WiFi and note its IP address from the serial monitor
-
Configure OTA upload in platformio.ini (optional - for easier uploads):
upload_protocol = espota upload_port = <DEVICE_IP_ADDRESS> -
Upload via OTA:
# Using PlatformIO CLI platformio run --target upload --upload-port <DEVICE_IP_ADDRESS> # Or use the PlatformIO IDE upload button after setting upload_protocol
Using OTA with Arduino IDE
- Open Tools > Port and select the network port (shows as
<device_hostname> at <IP>) - 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:
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