Hi everyone!
I wanted to share how I integrated my Swisshome Bluetooth scale with Home Assistant using an ESP32 and ESPHome. This budget-friendly scale doesn’t require any extra apps to integrate with Home Assistant. It uses Bluetooth to broadcast weight and body impedance data.
Key steps:
- Decoding the data: The scale broadcasts data packets with type
0xAD
for weight and0xA6
for impedance. Both packets need an XOR operation to decode the data correctly. - ESP32 with ESPHome: I set up an ESP32 with ESPHome to receive the scale data and publish it as sensors in Home Assistant.
Here’s an example of the code to set up the ESP32:
sensor:
- platform: template
name: "Peso Báscula"
id: weight_sensor
unit_of_measurement: "kg"
accuracy_decimals: 2
icon: "mdi:weight-kilogram"
- platform: template
name: "Impedancia (Z)"
id: body_impedancia_sensor
unit_of_measurement: "Ω"
accuracy_decimals: 0
icon: "mdi:scale-bathroom"
esp32_ble_tracker:
scan_parameters:
interval: 1100ms
window: 1100ms
active: true
on_ble_advertise:
- mac_address:
- XX:XX:XX:XX:XX:XX # MAC address de tu báscula
then:
- lambda: |-
// Variables de ejemplo
const uint16_t company_id = 0xA0AC; // ID del fabricante
int xor_key = company_id >> 8; // Byte XOR para decodificación
// Procesar los datos del fabricante
for (auto data : x.get_manufacturer_datas()) {
if (data.data.size() >= 12) {
// Extraer y decodificar los últimos 6 bytes usando XOR
std::vector<uint8_t> buf(6);
for (int i = 0; i < 6; i++) {
buf[i] = data.data[i + 6] ^ xor_key;
}
// Validar checksum (sumando los primeros 5 bytes)
int chk = 0;
for (int i = 0; i < 5; i++) {
chk += buf[i];
}
if ((chk & 0x1F) != (buf[5] & 0x1F)) {
ESP_LOGD("ble_adv", "Checksum error");
return;
}
// Procesar el paquete de peso
uint8_t packet_type = buf[4];
if (packet_type == 0xAD) {
int32_t value = (buf[3] | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24));
uint8_t state = (value >> 31) & 0x1;
int grams = value & 0x3FFFF;
float weight_kg = grams / 1000.0;
ESP_LOGD("ble_adv", "Peso: %.2f kg, state: %d", weight_kg, state);
if (state != 0) {
ESP_LOGD("ble_adv", "Medición completada,");
// Guardar el valor de peso en una variable de ESPHome para uso posterior
id(weight_sensor).publish_state(weight_kg);
}
// Obtener Impedancia
}else if (packet_type == 0xA6) {
int fat_raw = ((buf[1]) << 8) | buf[0];
ESP_LOGD("ble_adv", "Impedancia: %d", fat_raw);
float impedancia = fat_raw / 10; // Ejemplo: dividir entre 10
ESP_LOGD("ble_adv", "Impedancia (Z): %.2f Ω", impedancia);
// Publicar Impedancia (Z) en un sensor de ESPHome
id(body_impedancia_sensor).publish_state(impedancia);
} else {
ESP_LOGD("ble_adv", "Tipo de paquete no admitido: 0x%02X", packet_type);
}
}
}