A few months ago, I published a comprehensive guide on capturing BLE advertisement data from the SwitchBot Outdoor Thermometer using an ESP32 board. The process involved capturing, decoding, and parsing byte-level data in ESPHome, transforming it into functional sensors for Home Assistant.
It’s a detailed and somewhat intricate procedure, heavily reliant on the availability of key information to kickstart the process. If you want to deep dive into the technicalities of BLE decoding, I highly recommend checking out the article. It provides an in-depth look at my thought process and the challenges of decoding one-byte characteristics, a common approach used by SwitchBot and many other manufacturers.
In this article, I won’t be revisiting the entire process in detail. Instead, I’ll highlight the key differences I encountered while integrating the SwitchBot Meter Pro and SwitchBot Meter Pro (CO2) thermometers.
For the complete code, feel free to skip to the end.
Why use an ESP32 to capture BLE data?
In the comment section of the last article, I got asked several times why use an ESP32 board to parse data and not just use the official SwitchBot integration. For reference, the integration works wonderfully by simply using your server’s Bluetooth radio or even using an ESP32 as a Bluetooth Proxy.
I prefer using ESP32s for everything Bluetooth-related, as I have them everywhere throughout my smart home setup in one form or another. Here’s a few key differences I would list as advantages over using built-in Bluetooth radios:
- Extended Range and Reliability: An ESP32 can be strategically placed closer to devices, ensuring stronger BLE signal reception compared to a central system with a fixed Bluetooth radio (e.g RPi).
- Custom Parsing and Control: ESPHome allows for advanced customization and direct parsing of BLE byte data, enabling precise handling of unsupported or locked device features. Additionally, you can configure custom reporting intervals and Bluetooth scanning windows, optimizing performance and saving battery life.
- Active and Passive Connections: With an ESP32, you can choose between active and passive BLE scanning, providing greater flexibility to balance real-time responsiveness with power efficiency and reducing interference with other Bluetooth devices.
- Centralized BLE Hub: With an ESP32, you can manage multiple BLE devices from a single node, consolidating communications and reducing dependency on Home Assistant’s Bluetooth integrations for various vendors. For example, I can capture BLE packets from a SwitchBot thermometer, a Xiaomi temperature sensor or a HHCCJCY10 plant sensor on a single node.
- Scalability: Multiple ESP32 devices can be deployed across your home to cover large areas, ensuring consistent BLE coverage and reducing signal dead zones. I simply reuse other ESP32-based devices I already use in my home to capture data from a random device. For example, I use AirGradient’s ONE sensor to capture data from a temperature sensor in the bedroom.
Understanding BLE Advertisement Bytes for SwitchBot Meter Pro and Meter Pro (CO2)
When integrating the SwitchBot Meter Pro and Meter Pro (CO2) with ESPHome, understanding the structure of their BLE advertisement data is crucial. Each version uses specific bytes within the advertisement packet to represent temperature, humidity, battery level, and—on the CO2 model—carbon dioxide levels.
SwitchBot Meter Pro Byte Structure
The SwitchBot Meter Pro has the following byte structure:
- Temperature: Bytes 8 and 9.
- Byte 8’s lower 4 bits (
0x0F
) represent the decimal part; - Byte 9’s upper 7 bits (
0x7F
) represent the whole number part. - Byte 9’s highest bit (
0x80
) indicates the sign (0 = positive, 1 = negative). - Example: Byte 8 =
0x05
(0.5), Byte 9 =0x98
(24, positive), Temperature =24.5°C
.
- Byte 8’s lower 4 bits (
- Humidity: Byte 10.
- The lower 7 bits (
0x7F
) represent the humidity percentage. - Example: Byte 10 =
0x64
, Humidity =100%
.
- The lower 7 bits (
- Battery: Byte 2.
- The lower 7 bits (
0x7F
) represent the battery percentage. - Example: Byte 2 =
0x50
, Battery =80%
.
- The lower 7 bits (
- Service Data Identifier: Byte 0 (first byte of service data).
- Indicates the device type. Value:
0x34
(52).
- Indicates the device type. Value:
SwitchBot Meter Pro (CO2) Byte Structure
The SwitchBot Meter Pro (CO2) has the following byte structure:
- Temperature: Bytes 8 and 9.
- Byte 8’s lower 4 bits (
0x0F
) represent the decimal part; - Byte 9’s upper 7 bits (
0x7F
) represent the whole number part. - Byte 9’s highest bit (
0x80
) indicates the sign (0 = positive, 1 = negative). - Example: Byte 8 =
0x05
(0.5), Byte 9 =0x98
(24, positive), Temperature =24.5°C
.
- Byte 8’s lower 4 bits (
- Humidity: Byte 10.
- The lower 7 bits (
0x7F
) represent the humidity percentage. - Example: Byte 10 =
0x64
, Humidity =100%
.
- The lower 7 bits (
- Battery: Byte 2.
- The lower 7 bits (
0x7F
) represent the battery percentage. - Example: Byte 2 =
0x50
, Battery =80%
.
- The lower 7 bits (
- CO2: Bytes 13 and 14.
- Combined as a 16-bit big-endian integer. Byte 13 = High byte, Byte 14 = Low byte.
- Example: Byte 13 =
0x03
, Byte 14 =0xE8
, CO2 =(0x03 << 8) | 0xE8 = 1000 ppm
.
- Service Data Identifier: Byte 0 (first byte of service data).
- Indicates the device type. Value:
0x35
(53).
- Indicates the device type. Value:
Flashing the ESP32 Board
For capturing BLE characteristics from the SwitchBot Meter Pro and Meter Pro (CO2), any ESP32 will do the job. I recently talked about a tiny ESP board that can be used as a Bluetooth proxy, which will serve as an esp32_ble_tracker
for this purpose.
My base code for this board looks like this:
esphome:
name: esp32-c3-super-mini
friendly_name: ESP32-C3 Super Mini
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "XXXXX"
ota:
- platform: esphome
password: "XXXXX"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esp32-C3-Super-Mini"
password: "XXXXX"
captive_portal:
You will notice I’m using the arduino
framework instead of esp-idf
. When the bluetooth_proxy
configuration is enabled, the esp-idf
framework is recommended because it uses less memory and is more stable. For capturing packets with a passive esp32_ble_tracker
component, the arduino
framework works better.
Meter Pro Full Code
Here’s the full code for capturing SwitchBot Meter Pro BLE data with a generic ESP32 board. Replace the MAC address and adapt the config to your ESP32 board:
SwitchBot Meter Pro ESPHome (click to expand)
esphome:
name: switchbot-meter-pro
friendly_name: SwitchBot Meter Pro
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "XXXXXXXX"
ota:
- platform: esphome
password: "XXXXXXXX"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Switchbot-Meter-Pro"
password: "XXXXXXXX"
captive_portal:
esp32_ble_tracker:
on_ble_advertise:
- mac_address: "XX:XX:XX:XX:XX:XX" # Meter Pro (Basic)
then:
- lambda: |-
for (auto data : x.get_manufacturer_datas()) {
if (data.data.size() >= 11) { // Ensure sufficient length for Basic version
// Parse temperature from Bytes 8-9
float temperature = (float(data.data[8] & 0x0F) * 0.1) + float(data.data[9] & 0x7F);
if (!(data.data[9] & 0x80)) {
temperature = -temperature;
}
id(meter_pro_temperature).publish_state(temperature);
// Parse humidity from Byte 10
uint8_t humidity = data.data[10] & 0x7F;
id(meter_pro_humidity).publish_state(humidity);
}
}
for (auto data : x.get_service_datas()) {
if (data.data.size() == 3) {
// Parse battery percentage from Byte 2
int8_t battery_pct = data.data[2] & 0x7F;
id(meter_pro_battery).publish_state(battery_pct);
}
}
sensor:
- platform: template
name: "Meter Pro Temperature"
id: meter_pro_temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
- platform: template
name: "Meter Pro Humidity"
id: meter_pro_humidity
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:water-percent"
- platform: template
name: "Meter Pro Battery"
id: meter_pro_battery
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:battery"
Meter Pro (CO2) Full Code
Here’s the full code for capturing SwitchBot Meter Pro (CO2) BLE data with a generic ESP32 board. Replace the MAC address and adapt the config to your ESP32 board.
SwitchBot Meter Pro (CO2) ESPHome (click to expand)
esphome:
name: switchbot-meter-pro
friendly_name: SwitchBot Meter Pro (CO2)
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "XXXXXXXX"
ota:
- platform: esphome
password: "XXXXXXXX"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Switchbot-Meter-Pro"
password: "XXXXXXXX"
captive_portal:
esp32_ble_tracker:
on_ble_advertise:
- mac_address: "XX:XX:XX:XX:XX:XX" # Meter Pro (CO2)
then:
- lambda: |-
for (auto data : x.get_manufacturer_datas()) {
if (data.data.size() >= 15) { // Ensure sufficient length for CO2 version
// Parse temperature from Bytes 8-9
float temperature = (float(data.data[8] & 0x0F) * 0.1) + float(data.data[9] & 0x7F);
if (!(data.data[9] & 0x80)) {
temperature = -temperature;
}
id(meter_pro_co2_temperature).publish_state(temperature);
// Parse humidity from Byte 10
uint8_t humidity = data.data[10] & 0x7F;
id(meter_pro_co2_humidity).publish_state(humidity);
// Parse CO2 from Bytes 13-14
uint16_t co2 = (data.data[13] << 8) | data.data[14];
id(meter_pro_co2).publish_state(co2);
}
}
for (auto data : x.get_service_datas()) {
if (data.data.size() == 3) {
// Parse battery percentage from Byte 2
int8_t battery_pct = data.data[2] & 0x7F;
id(meter_pro_co2_battery).publish_state(battery_pct);
}
}
sensor:
- platform: template
name: "Meter Pro CO2 Temperature"
id: meter_pro_co2_temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
- platform: template
name: "Meter Pro CO2 Humidity"
id: meter_pro_co2_humidity
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:water-percent"
- platform: template
name: "Meter Pro CO2"
id: meter_pro_co2
unit_of_measurement: "ppm"
accuracy_decimals: 0
icon: "mdi:molecule-co2"
- platform: template
name: "Meter Pro CO2 Battery"
id: meter_pro_co2_battery
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:battery"
Combined Code (both devices)
Here’s the full code for capturing BLE data of both devices with a generic ESP32 board. Replace the MAC address and adapt the config to your ESP32 board.
SwitchBot Meter Pro and Meter Pro (CO2) ESPHome (click to expand)
esphome:
name: switchbot-meter-pro
friendly_name: SwitchBot Meter Pro
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "XXXXXXXX"
ota:
- platform: esphome
password: "XXXXXXXX"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Switchbot-Meter-Pro"
password: "XXXXXXXX"
captive_portal:
esp32_ble_tracker:
on_ble_advertise:
- mac_address: "XX:XX:XX:XX:XX:XX" # Meter Pro (Basic)
then:
- lambda: |-
for (auto data : x.get_manufacturer_datas()) {
if (data.data.size() >= 11) { // Ensure sufficient length for Basic version
// Parse temperature from Bytes 8-9
float temperature = (float(data.data[8] & 0x0F) * 0.1) + float(data.data[9] & 0x7F);
if (!(data.data[9] & 0x80)) {
temperature = -temperature;
}
id(meter_pro_temperature).publish_state(temperature);
// Parse humidity from Byte 10
uint8_t humidity = data.data[10] & 0x7F;
id(meter_pro_humidity).publish_state(humidity);
}
}
for (auto data : x.get_service_datas()) {
if (data.data.size() == 3) {
// Parse battery percentage from Byte 2
int8_t battery_pct = data.data[2] & 0x7F;
id(meter_pro_battery).publish_state(battery_pct);
}
}
- mac_address: "XX:XX:XX:XX:XX:XX" # Meter Pro (CO2)
then:
- lambda: |-
for (auto data : x.get_manufacturer_datas()) {
if (data.data.size() >= 15) { // Ensure sufficient length for CO2 version
// Parse temperature from Bytes 8-9
float temperature = (float(data.data[8] & 0x0F) * 0.1) + float(data.data[9] & 0x7F);
if (!(data.data[9] & 0x80)) {
temperature = -temperature;
}
id(meter_pro_co2_temperature).publish_state(temperature);
// Parse humidity from Byte 10
uint8_t humidity = data.data[10] & 0x7F;
id(meter_pro_co2_humidity).publish_state(humidity);
// Parse CO2 from Bytes 13-14
uint16_t co2 = (data.data[13] << 8) | data.data[14];
id(meter_pro_co2).publish_state(co2);
}
}
for (auto data : x.get_service_datas()) {
if (data.data.size() == 3) {
// Parse battery percentage from Byte 2
int8_t battery_pct = data.data[2] & 0x7F;
id(meter_pro_co2_battery).publish_state(battery_pct);
}
}
sensor:
- platform: template
name: "Meter Pro Temperature"
id: meter_pro_temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
- platform: template
name: "Meter Pro Humidity"
id: meter_pro_humidity
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:water-percent"
- platform: template
name: "Meter Pro Battery"
id: meter_pro_battery
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:battery"
- platform: template
name: "Meter Pro CO2 Temperature"
id: meter_pro_co2_temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
- platform: template
name: "Meter Pro CO2 Humidity"
id: meter_pro_co2_humidity
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:water-percent"
- platform: template
name: "Meter Pro CO2"
id: meter_pro_co2
unit_of_measurement: "ppm"
accuracy_decimals: 0
icon: "mdi:molecule-co2"
- platform: template
name: "Meter Pro CO2 Battery"
id: meter_pro_co2_battery
unit_of_measurement: "%"
accuracy_decimals: 0
icon: "mdi:battery"
Device Availability
The SwitchBot Meter Pro and Meter Pro (CO2) are excellent indoor thermometers and air quality sensors. You can get them on the official SwitchBot webstore or various Amazon stores around the world. Here’s where they are available:
SWITCHBOT WEBSTORE
Meter Pro (US) | Meter Pro (EU)
United States | United Kingdom
Germany | Netherlands | France
*If links fail to open, try disabling your AdBlocker.
USE CODE BFCM30
FOR 30% OFF
SWITCHBOT WEBSTORE
Meter Pro CO2 (US) | Meter Pro CO2 (EU)
United States | United Kingdom
Germany | Netherlands | France
*If links fail to open, try disabling your AdBlocker.
USE CODE BFCM30
FOR 30% OFF