Integrating Swisshome Bluetooth Scale with ESPHome in Home Assistant

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:

  1. Decoding the data: The scale broadcasts data packets with type 0xAD for weight and 0xA6 for impedance. Both packets need an XOR operation to decode the data correctly.
  2. 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);
                }
              }
            }

More Info https://jamalbelkacemi.es/domotica/integrando-una-b%C3%A1scula-bluetooth-en-home-assistant-mi-experiencia-y-resultados/

2 Likes