2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00
2026-03-16 11:20:10 +01:00

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/<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 tempc field 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:

  • 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

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:

  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/<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

  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):

    upload_protocol = espota
    upload_port = <DEVICE_IP_ADDRESS>
    
  3. 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

  1. Open Tools > Port and select the network port (shows as <device_hostname> at <IP>)
  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:

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

Description
No description provided
Readme 40 KiB
Languages
C++ 87.9%
C 6.9%
HTML 5.2%