Receive data from BTHome sensor to ESP32 without HA

Hello,

Don’t know if this is the right place to ask it, but maybe someone can guide me up.
I’m new using BLE, but long programmer for microcontrollers.
I want to read the Temperature and Humidity from the new Shelly Blu HT and also Mija sensors (converted to BTHome).
Anyone can point me the right way of doing it?
I use ESP32 and arduino.
Thanks!

Maybe you can look into ESPHome — ESPHome
This can be used in combination with HomeAssistant, but can also provide data without HA.

I see a lot of examples using BT Proxy, and them using HA to decode data from the sensors.
I want to receive data on the ESP and display locally on a I2C screen, all locally not going to HA…
I’m using arduino and the display part I got it working, just need to receive the data from the sensor…

Thanks.

Maybe this component can get you started?

If your Mijas had the ATC or PVVX native format firmware OpenMQTTGateway should be able to already do what you want, and depending on which I2C screen you want to use it might also be already implemented with SSD1306 support, or easily adjustable to any other screen.

With the new Shelly Blu HT we’d have to look into it’s advertising format.

I have changed to ATC firmware that advertises BTHome.

I just realised that they finally support BTHome v2, so for these specific devices the BTHome v2 format can be easily added to Theengs Decoder, as with some Shelly devices.

Also saw your NimBLE post about examples, so the Decoder examples might be helpful if you want to go the library way, or just implement the advertising data decoding separately if you don’t require all the different device model checking.

I’ve managed to receive data from the advertise when searching for devices.
What I do is search for devices with whitelist of the MAC I want, and then decode the advertise message.
But this way I’m asking the devices the data, and I want to listen to when the device send data, I need to dig further…

Thanks all for your help.

Have a look at the OpenMQTTGateway source, which does exactly that using NimBLE-Arduino, passively scanning the BLE advertising data, with the option to also set it to active scanning when required, desired or needed for certain devices with a separate interval.

Here’s a post from someone who does similar things for an oral b toothbrush. If you know what the advertisement contains, you could do something similar:

EDIT: sorry, I took the wrong link. This is the one I meant, much simpler and I can confirm that worked for me before I switched to the proxy.

this is how I decode raw bthome directly on a esp32 with esphome,
you can probably use esphome over commandline on windows and just not connect it to homeassistant and skip arduino just a thought. anyway here are the code.

esphome:
  name: ble-32-tst
  platformio_options:
     board_build.f_cpu: 80000000L   
preferences:
  flash_write_interval: 999min
wifi:
  fast_connect: true 
  ssid: "xxxxxxxxx"
  password: "xxxxxxxxxxx"
  output_power: 10
  power_save_mode: HIGH #HIGH NONE LIGHT 
  #use_address: ble-32-nrf.local

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    version: recommended


# Enable logging
logger:
  baud_rate: 0 
  #level:  NONE # DEBUG # NONE
# Enable Home Assistant API
api:

ota:



esp32_ble_tracker:
  scan_parameters:
    active: false
    duration: 33s
    interval: 100ms #161ms #1100ms
    window:   99ms #160ms #1090ms       






  on_ble_service_data_advertise:




      - mac_address: 38:1F:8D:FD:91:5A #BTH01- 915A
        service_uuid: FCD2
        then:
          - lambda: |-          
              ESP_LOGD("ble_adv", "ble data: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x ", x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16]);
              int16_t temp_int = ((((x[6] & 0xff) | (x[7] & 0xff) << 8)));
              float temp = temp_int/100.0;                            
              float hum = ((((x[9] & 0xff) | (x[10] & 0xff) << 8)))/100.0;
              float volt = ((((x[12] & 0xff) | (x[13] & 0xff) << 8)))/1000.0;
              //ESP_LOGD("ble_BTH01", "temp %.2f hum %.2f volt %.3f",temp,hum,volt);
              
              if(x[5]==0x02&&x[8]==0x03&&x[11]==0x0C&&temp>(-40)&&temp<100&&hum>0&&hum<101&&volt>0&&volt<4)
              {
              id(BTH01_temperature_).publish_state(temp);
              id(BTH01_humidity_).publish_state(hum);      
              id(BTH01_volt_).publish_state(volt);
              }              
      

      - mac_address: 38:1F:8D:ED:D8:4A #TH05- D84A
        service_uuid: FCD2
        then:
          - lambda: |-          
              ESP_LOGD("ble_adv", "ble data: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x ", x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16]);
              int16_t temp_int = ((((x[6] & 0xff) | (x[7] & 0xff) << 8)));
              float temp = temp_int/100.0;  
              float hum = ((((x[9] & 0xff) | (x[10] & 0xff) << 8)))/100.0;
              float volt = ((((x[12] & 0xff) | (x[13] & 0xff) << 8)))/1000.0;
              //ESP_LOGD("ble_TH05", "temp %.2f hum %.2f volt %.3f",temp,hum,volt);
              if(x[5]==0x02&&x[8]==0x03&&x[11]==0x0C&&temp>(-20)&&temp<100&&hum>0&&hum<101&&volt>0&&volt<4)
              {              
              id(TH05_temperature_).publish_state(temp);      
              id(TH05_humidity_).publish_state(hum);      
              id(TH05_volt_).publish_state(volt);
              }              






sensor:




- platform: ble_rssi
  mac_address: '38:1F:8D:ED:D8:4A'
  name: "rssi TH05"
  filters:
    - filter_out: nan   # <-- Processing will stop here on unknown values.
    - median:
        window_size: 10 


- platform: template
  name: "TH05 humidity"
  unit_of_measurement: '%'
  accuracy_decimals: 2
  device_class: "humidity"
  state_class: "measurement"    
  id: TH05_humidity_
  filters:
    - median:
        window_size: 7
        send_every: 6
    #- delta: 0.05        
- platform: template          
  name: "TH05 temperature"
  unit_of_measurement: °C
  accuracy_decimals: 2
  device_class: "temperature"
  state_class: "measurement"      
  id: TH05_temperature_
  filters:
    - median:
        window_size: 7
        send_every: 6
   # - delta: 0.05
 
- platform: template
  name: "TH05 volt"
  accuracy_decimals: 3
  unit_of_measurement: V
  device_class: "voltage"
  state_class: "measurement"    
  id: TH05_volt_
  filters:
    - median:
        window_size: 7 
        send_every: 6






##-------------------------------------------------------------------------------


##-----------------------------------------------------------------------------



- platform: ble_rssi
  mac_address: '38:1F:8D:FD:91:5A'
  name: "rssi BTH01"
  filters:
    - filter_out: nan   # <-- Processing will stop here on unknown values.
    - median:
        window_size: 10 

- platform: template
  name: "BTH01 humidity"
  unit_of_measurement: '%'
  accuracy_decimals: 2
  device_class: "humidity"
  state_class: "measurement"    
  id: BTH01_humidity_
  filters:
    - median:
        window_size: 7 
        send_every: 6
    #- delta: 0.05        
- platform: template          
  name: "BTH01 temperature"
  unit_of_measurement: °C
  accuracy_decimals: 2
  device_class: "temperature"
  state_class: "measurement"      
  id: BTH01_temperature_
  filters:
    - median:
        window_size: 7 
        send_every: 6
   # - delta: 0.05
 
- platform: template
  name: "BTH01 volt"
  accuracy_decimals: 3
  unit_of_measurement: V
  device_class: "voltage"
  state_class: "measurement"    
  id: BTH01_volt_
  filters:
    - median:
        window_size: 7 
        send_every: 6


just look at https://bthome.io/format/
to identify in what order it sends the sensor data

the code above is to decode data from Tuya sensor updated with https://github.com/pvvx/THB2