ESPHome Bluetooth Thermometer Tracker for Relsib WT50

Complete ESPHome configuration for monitoring Relsib WT50 Bluetooth thermometer with reliable connection management and manual stop functionality.

Features

  • Real-time temperature and battery data transmission to Home Assistant
  • Automatic connection when thermometer is available
  • Manual stop button with 3,5-minute cooldown period
  • Three clear status states: Waiting, Connected, Blocked
  • Reliable connection management without interference with thermometer auto-shutdown

Important Notes

Thermometer Behavior

  • Automatically powers on when heated
  • Transmits data every 1 second via Bluetooth
  • Auto-shutdown : Powers off after 180 seconds (3 minutes) if no device is connected
  • Manual shutdown available via mobile app “Disconnect” button

ESP32 Tracker Logic

  • Always attempts to connect when thermometer is advertising
  • Real-time data publishing to Home Assistant
  • Manual stop button : Forces disconnection and blocks reconnection for 3,5 minutes
  • Blocking period : Ensures thermometer has time to auto-shutdown completely
  • Status indicators :
    • Connected : Connected and receiving data
    • Waiting : Ready to connect, thermometer likely off
    • Blocked : Manual stop active, waiting for thermometer shutdown

Configuration

substitutions:
  thermo_mac: "54:6C:0E:59:53:0B"

esphome:
  name: thermometer
  friendly_name: Thermometer

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf

logger:
  level: INFO

api:
  encryption:
    key: "your_encryption_key_here"

ota:
  - platform: esphome
    password: "your_ota_password"

wifi:
  ssid: "Your_WiFi_SSID"
  password: "Your_WiFi_Password"
  min_auth_mode: WPA2
  manual_ip:
    static_ip: 192.168.1.100
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    dns1: 192.168.1.1

globals:
  - id: current_temperature
    type: float
    restore_value: yes
    initial_value: '0.0'
  - id: battery_level
    type: int
    restore_value: yes
    initial_value: '0'
  - id: block_until
    type: int64_t
    restore_value: no
    initial_value: '0'
  - id: last_connect_attempt
    type: int64_t
    restore_value: no
    initial_value: '0'

esp32_ble_tracker:
  scan_parameters:
    interval: 1280ms
    window: 320ms
    active: true

ble_client:
  - mac_address: "${thermo_mac}"
    id: thermometer_ble
    auto_connect: false

sensor:
  - platform: ble_client
    type: characteristic
    ble_client_id: thermometer_ble
    service_uuid: "00001809-0000-1000-8000-00805f9b34fb"
    characteristic_uuid: "00002a1e-0000-1000-8000-00805f9b34fb"
    name: "Temperature Intermediate"
    id: temp_raw
    internal: true
    notify: true
    lambda: |-
      if (x.size() == 5) {
        uint8_t flags = x[0];
        bool fahrenheit = (flags & 0x01) == 0x01;
        uint32_t mantissa = (uint32_t)x[1] | ((uint32_t)x[2] << 8) | ((uint32_t)x[3] << 16);
        int8_t exponent = x[4];
        float temperature = mantissa * pow(10, exponent);
        if (fahrenheit) {
          temperature = (temperature - 32) * 5.0 / 9.0;
        }
        id(current_temperature) = temperature;
        id(temperature_sensor).publish_state(temperature);
        ESP_LOGI("main", "Temperature: %.2f°C", temperature);
      }
      return {};

  - platform: ble_client
    type: characteristic
    ble_client_id: thermometer_ble
    service_uuid: "0000180f-0000-1000-8000-00805f9b34fb"
    characteristic_uuid: "00002a19-0000-1000-8000-00805f9b34fb"
    name: "Battery Raw"
    id: batt_raw
    internal: true
    notify: true
    lambda: |-
      if (x.size() == 1) {
        id(battery_level) = x[0];
        id(battery_sensor).publish_state(x[0]);
        ESP_LOGI("main", "Battery: %d%%", x[0]);
      }
      return {};

  - platform: template
    name: "Body Temperature"
    id: temperature_sensor
    unit_of_measurement: "°C"
    icon: "mdi:thermometer-probe"
    accuracy_decimals: 2
    device_class: temperature
    state_class: measurement
    filters:
      - delta: 0.05
      - throttle: 2s
    lambda: 'return id(current_temperature);'

  - platform: template
    name: "Thermometer Battery"
    id: battery_sensor
    unit_of_measurement: "%"
    icon: "mdi:battery"
    accuracy_decimals: 0
    device_class: battery
    lambda: 'return id(battery_level);'

text_sensor:
  - platform: template
    name: "Thermometer Status"
    id: status_text
    icon: "mdi:thermometer-bluetooth"
    lambda: |-
      uint64_t now = millis();
      if (now < id(block_until)) {
        return std::string("Blocked");
      } else if (id(thermometer_ble)->connected()) {
        return std::string("Connected");
      } else {
        return std::string("Waiting");
      }
    update_interval: 5s

  - platform: wifi_info
    ip_address:
      name: "IP Address"
    ssid:
      name: "WiFi SSID"
    mac_address:
      name: "MAC Address"

binary_sensor:
  - platform: status
    name: "Status"

button:
  - platform: template
    name: "Stop Thermometer"
    id: stop_button
    icon: "mdi:stop-circle"
    on_press:
      then:
        - lambda: |-
            ESP_LOGI("main", "Manual stop - blocking for 3.5 minutes");
            id(block_until) = millis() + 210000;
            if (id(thermometer_ble)->connected()) {
              id(thermometer_ble)->disconnect();
            }
            id(last_connect_attempt) = 0;
            ESP_LOGI("main", "Thermometer blocked for 3.5 minutes");

interval:
  - interval: 30s
    then:
      - lambda: |-
          uint64_t now = millis();
          if (id(block_until) > 0 && id(block_until) - now > 210000) {
            ESP_LOGI("main", "Resetting block_after reboot");
            id(block_until) = 0;
            return;
          }
          if (now < id(block_until)) {
            int64_t remaining = (id(block_until) - now) / 1000;
            ESP_LOGI("main", "Blocked: %llds", remaining);
            if (id(thermometer_ble)->connected()) {
              ESP_LOGI("main", "Disconnecting due to block");
              id(thermometer_ble)->disconnect();
            }
            return;
          }
          if (id(thermometer_ble)->connected()) {
            ESP_LOGI("main", "Thermometer connected");
          } else if (now - id(last_connect_attempt) > 60000) {
            id(last_connect_attempt) = now;
            ESP_LOGI("main", "Attempting to connect");
            id(thermometer_ble)->connect();
          }

How It Works

Normal Operation Cycle:

  1. Thermometer activation → 20-sec warmup → Starts BLE advertising
  2. ESP32 connection → Detects advertisement → Connects
  3. Data transmission → Sends temperature every second → To Home Assistant
  4. Disconnection:
  • Normal : Remove thermometer → Stops transmitting → ESP disconnects → Thermometer powers off in 180s
  • Manual : Press “Stop” button → ESP disconnects immediately → Thermometer powers off in 180s → ESP blocks reconnection for 210s (180s + 30s buffer)

Manual Stop Operation:

  1. User presses “Stop Measurement” in Home Assistant (useful for terminating measurement early)
  2. ESP32 immediately disconnects
  3. BLE client disabled for 210 seconds (3,5 minutes)
  4. Status shows “Blocked”
  5. Thermometer auto-shutdowns within 180 seconds
  6. After 3,5 minutes, ESP32 resumes normal operation

Thermometer Not Powering Off

  • Important : After pressing “Stop Measurement”, the 3,5-minute cooling period ensures the thermometer can auto-shutdown
  • The thermometer needs 180 seconds of no connections to power off
  • ESP32 blocks all connections for 210 seconds to guarantee shutdown
1 Like