Integrando una Báscula Bluetooth en Home Assistant: Mi Experiencia y Resultados


bascula swisshome home assistant

Contenido

Cómo integrar una báscula Bluetooth Swisshome en Home Assistant con ESPHome

¡Hola a todos!

Hace unos meses, compré una báscula de baño marca Swisshome, una opción económica y genérica que me costó apenas 10 €. Aunque al principio solo la usaba para pesarnos ocasionalmente, un día revisé el manual (algo que admito no suelo hacer) y me di cuenta de que esta báscula tenía Bluetooth integrado.

Esto despertó mi curiosidad, ya que no me gusta instalar muchas aplicaciones en mi móvil, y pensé: ¿por qué no integrarla directamente con Home Assistant? De esta forma podría llevar un seguimiento del peso de toda mi familia sin depender de aplicaciones de terceros. Además, como entusiasta de la automatización y la tecnología, me pareció un desafío interesante.

En este artículo te mostraré cómo logré esta integración utilizando un ESP32 y ESPHome. También compartiré los pasos para procesar los datos emitidos por la báscula, que incluyen tanto el peso como la impedancia corporal. Si tienes una báscula Bluetooth similar, este tutorial puede ser útil para ti.

¿Por qué integrar una báscula Bluetooth con Home Assistant?

Si estás familiarizado con Home Assistant, sabes lo poderosa que es esta plataforma de automatización del hogar. Integrar dispositivos como una báscula Bluetooth tiene varias ventajas:

  1. Seguimiento a largo plazo: Puedes registrar el peso e incluso métricas corporales como la impedancia (útil para calcular la composición corporal).
  2. Notificaciones: Configura alertas para mantenerte al tanto de los cambios en tu peso o el de tu familia.
  3. Independencia de aplicaciones externas: Muchas básculas Bluetooth requieren apps específicas que recopilan tus datos. Con esta integración, tienes control total sobre tu información.
  4. Automatizaciones personalizadas: Por ejemplo, enviar un resumen semanal de tus progresos o activar recordatorios si detecta un cambio drástico en el peso.

Paso 1: Descubriendo las capacidades de la báscula Swisshome

Al analizar las emisiones Bluetooth de la báscula, descubrí que funcionaba mediante broadcast, lo que significa que no es necesario establecer una conexión activa. En cambio, los datos se transmiten de forma abierta para que cualquier dispositivo pueda capturarlos, siempre que sepa cómo decodificarlos.

Esta báscula emite dos tipos de datos:

  1. Peso: Se transmite en paquetes identificados por el tipo 0xAD. Incluye el peso en gramos y un estado que confirma si la medición está lista.
  2. Impedancia corporal: Se transmite en un paquete diferente (0xA6) y aparece solo después de que el peso ha sido confirmado. La impedancia es clave para calcular métricas como el porcentaje de grasa corporal.

Para obtener esta información, utilicé herramientas como nRF Connect (en mi móvil) para capturar los paquetes Bluetooth y Wireshark para analizarlos en detalle. Fue fascinante ver cómo los datos crudos cobraban sentido tras un poco de decodificación.

Paso 2: Decodificar los datos Bluetooth

Los datos transmitidos por la báscula están cifrados mediante un byte XOR basado en el ID del fabricante. Esto significa que para interpretarlos correctamente, primero debemos aplicar una operación XOR a los bytes relevantes y luego validar el checksum.

Peso

El peso se encuentra codificado en los primeros cuatro bytes del paquete 0xAD. Después de decodificarlo, se convierte a kilogramos dividiendo el valor por 1000.

Impedancia

La impedancia se transmite en los dos primeros bytes del paquete 0xA6. Este valor se procesa para obtener el dato en ohmios, que es esencial para estimar la composición corporal.

Paso 3: Configuración del ESP32 con ESPHome

El ESP32, gracias a su capacidad de manejar Bluetooth Low Energy (BLE), es ideal para proyectos de este tipo. Para integrarlo con Home Assistant usando ESPHome, primero debemos configurar un código que permita decodificar y procesar los datos transmitidos por la báscula.

Antes de compartir el código, hay un detalle importante: debes conocer el ID del fabricante de tu báscula. Este valor es único para cada modelo y se utiliza como clave en la decodificación XOR. Puedes obtenerlo con herramientas como nRF Connect o mediante la funcionalidad BLE Tracker del ESP32.

Código completo para ESPHome

Aquí está el código adaptado para integrar una báscula genérica con ESPHome.

ESPHOME

    

     #codigo en Esphome 
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);
                }
              }
            }
    
Cómo integrar una báscula en Home Assistant con ESPHome