Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for the device BTH01 #14

Open
duelago opened this issue Nov 8, 2024 · 6 comments
Open

Support for the device BTH01 #14

duelago opened this issue Nov 8, 2024 · 6 comments
Labels
enhancement New feature or request

Comments

@duelago
Copy link

duelago commented Nov 8, 2024

Hello!

I successfully flashed pvvx firmware on my bluetooth device.
Model: BTH01
Firmware: github.com /pvvx
Hardware: 0014
Software: V1.9

My goal is to use your software on an esp32 to change color on an LED depending on the temperature. Your code is picking up my device but it returns 0 degrees. I'm using your basic example code (The non blocking version is crashing my device)

17:16:48.005 -> Sensor 0: 34:EC:B6:65:18:3E
17:16:48.005 -> Name: BTH01-David
17:16:48.005 -> 0.00°C
17:16:48.005 -> 0.00%
17:16:48.005 -> 0.000V
17:16:48.005 -> 0%
17:16:48.005 -> -75dBm
17:16:48.005 -> Measurement Count: 0
17:16:48.062 -> Reed Switch State: Closed
17:16:48.062 -> GPIO TRG Output: Low
17:16:48.062 -> Control Parameters: Not Set
17:16:48.062 -> Temperature Trigger Event: Not Triggered
17:16:48.062 -> Humidity Trigger Event: Not Triggered
17:16:48.062 ->
17:16:48.062 -> BLE Devices found (total): 5
17:16:48.062 -> Iteration 2 - Free heap is 228720
17:16:48.062 -> ---

I get my temperature when using the web site on my computer:
https://pvvx.github.io/THB2/web/PHY62x2BTHome.html

Any ideas how I can solve this?

/David

@matthias-bs
Copy link
Owner

Hello David,

I suppose the data for this sensor is placed and/or encoded differently in the BLE advertising message as compared to the Xiaomi Mijia (LYWSD03MMC).
Have you checked https://github.com/pvvx/THB2/blob/ba0601e1db3e640ad0377c9b7d1f5f6aff52bb95/bthome_phy6222/source/thservice.c#L31?

Cheers,
Matthias

@matthias-bs
Copy link
Owner

Ah, it seems you don't have check the source code!

@matthias-bs matthias-bs added the enhancement New feature or request label Nov 9, 2024
@matthias-bs
Copy link
Owner

@duelago
Copy link
Author

duelago commented Nov 9, 2024

Ah, it seems you don't have check the source code!

Thank you! I am not much of a programmer but my friend ChatGPT and the documentation helped me. This code works for me now :)

#include <NimBLEDevice.h>

// BLE Scan settings
NimBLEScan* pBLEScan;
const int scanTime = 5;  // Scan duration in seconds

// Target MAC address of the specific device
const std::string targetMacAddress = "34:ec:b6:65:18:3e";

// Helper function to decode a little-endian 16-bit unsigned integer
uint16_t decodeLittleEndianU16(uint8_t lowByte, uint8_t highByte) {
  return (uint16_t)((highByte << 8) | lowByte);
}

// Helper function to print the raw service data
void printRawServiceData(const std::string& payload) {
  Serial.print("Raw Service Data: ");
  for (size_t i = 0; i < payload.length(); ++i) {
    Serial.printf("%02X ", static_cast<uint8_t>(payload[i]));
  }
  Serial.println();
}

// Function to parse and decode the raw service data
void decodeServiceData(const std::string& payload) {
  // Print the raw service data for debugging
  printRawServiceData(payload);

  // Ensure we have at least 14 bytes for the expected data
  if (payload.length() >= 14) {
    // Check if the first byte indicates a valid service data format
    if (payload[0] == 0x40) {
      // Parse BTHome device info (flags and version)
      uint8_t flags = payload[0];  // First byte (flag byte)
      uint8_t bthomeVersion = (flags >> 5) & 0x07;  // BTHome Version is in bits 5-7
      Serial.print("BTHome Version: ");
      Serial.println(bthomeVersion);

      // Decode temperature (bytes 6 and 7) in little-endian format
      int16_t temp_int = (payload[6] & 0xff) | ((payload[7] & 0xff) << 8);
      float temperature = temp_int / 100.0;
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" °C");

      // Decode humidity (bytes 9 and 10) in little-endian format
      float humidity = ((payload[9] & 0xff) | ((payload[10] & 0xff) << 8)) / 100.0;
      Serial.print("Humidity: ");
      Serial.print(humidity);
      Serial.println(" %");

      // Decode voltage (bytes 12 and 13) in little-endian format
      float voltage = ((payload[12] & 0xff) | ((payload[13] & 0xff) << 8)) / 1000.0;
      Serial.print("Voltage: ");
      Serial.print(voltage);
      Serial.println(" V");

      // Check validity of decoded values based on ESPHome's conditions
      if (payload[5] == 0x02 && payload[8] == 0x03 && payload[11] == 0x0C &&
          temperature > -40 && temperature < 100 && humidity > 0 && humidity < 101 && voltage > 0 && voltage < 4) {
        
        // Publish the values (you can replace these with your actual publish method)
        Serial.print("Publishing Data: ");
        Serial.print("Temperature: ");
        Serial.print(temperature);
        Serial.print(" Humidity: ");
        Serial.print(humidity);
        Serial.print(" Voltage: ");
        Serial.println(voltage);
        
        // Here, replace with your own logic to publish the data
        // id(BTH01_temperature_).publish_state(temperature);
        // id(BTH01_humidity_).publish_state(humidity);
        // id(BTH01_volt_).publish_state(voltage);
      }
    } else {
      Serial.println("Invalid Service Data format.");
    }
  } else {
    Serial.println("Unexpected payload length or structure.");
  }
}

// Callback to handle BLE Advertisements
class MyAdvertisedDeviceCallbacks : public NimBLEAdvertisedDeviceCallbacks {
  void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
    // Check if the device's MAC address matches the target address
    if (advertisedDevice->getAddress().toString() == targetMacAddress) {
      Serial.print("Found target device: ");
      Serial.println(advertisedDevice->getAddress().toString().c_str());

      // Check if the device has service data
      if (advertisedDevice->haveServiceData()) {
        std::string serviceData = advertisedDevice->getServiceData();
        Serial.print("Service Data Length: ");
        Serial.println(serviceData.length());
        decodeServiceData(serviceData);
      } else {
        Serial.println("No service data available.");
      }
    }
  }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE Scanner...");

  // Initialize BLE
  NimBLEDevice::init("");
  pBLEScan = NimBLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true);
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
  pBLEScan->setActiveScan(true);
}

void loop() {
  Serial.println("Scanning for BLE devices...");
  pBLEScan->start(scanTime, false);  // Scan for `scanTime` seconds
  delay(2000);  // Wait before the next scan
}

@matthias-bs
Copy link
Owner

Nice!

@olivluca
Copy link

I seriously doubt that your code works (it doesn't here 😉) , it's just another chatgpt hallucination: according to the specification, the payload isn't necessarily 14 bytes and the values aren't in a fixed location, but each byte, after the initial 0x40, specifies what comes after it, e.g. I'm getting

Raw Service Data: 40 00 60 01 5F 02 EC 07 03 C3 1B (11 bytes)

and it means:

00 -> packet id (60)
01 -> battery (5F, 95%)
02 -> temperature (07EC, 20.28)
03 -> humidity (1BC3, 71.07%)

Then for the same thermometer I get

Raw Service Data: 40 00 61 0C 2A 0B 10 01 (8 bytes)

00 -> packet id (61)
0C -> voltage (0B2A, 2.858V)
10 -> power (01, true)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants