Pool Monitor Device Yieryi BLE-YC01

I pushed this to git.infradead.org Git - users/dwmw2/esp32-pool.git/summary

3 Likes

This is awesome. I just ordered one from Aliexpress. With your research, I can try to make a native BLE integration which works with ESPHome proxies when mine arrives. I have made a couple integrations and it is not too hard. My coding is super bad, but also super simple so should be easy to learn if anyone else wants to try themselves. A good one to modify is: https://github.com/jdeath/Opal_NuggetIce_ble/ as it seems all you need to do is a read_gatt_char to get the values. Should be straight forward to replace the config_flow.py line that finds the device on the network and change the sensors in the parser. The nice thing about proxy is it automatically connects, reads, then disconnects based on a timer. Seems @anasm2010 bleak script has everything you need to start with for the proxy code

1 Like

Hello everyone,
I don’t use HomeAssistant, but maybe you can still help me.

I also bought the BLE-YC01 pool meter and wrote an ESP32 Arduino sketch.

I read the value of the characteristic, but cannot decode it.
I used the code snipps from the forum, also read the positions from the string. However, the correct data is not displayed to me.

greeting
think

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLEClient.h>

static BLEAddress serverAddress("c0:00:00:01:da:1e");
static BLEUUID serviceUUID("0000ff01-0000-1000-8000-00805f9b34fb");
static BLEUUID charUUID("0000ff02-0000-1000-8000-00805f9b34fb");

BLEClient* pClient;
boolean doConnect = false;
boolean connected = false;
BLERemoteCharacteristic* pRemoteCharacteristic;

class MyClientCallbacks : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
    Serial.println("Verbunden mit BLE-YC01...");
  }

  void onDisconnect(BLEClient* pclient) {
    Serial.println("Verbindung zum BLE-YC01 getrennt...");
    connected = false;
    pRemoteCharacteristic = nullptr;
  }
};

// Dekodierungsfunktion für Temperatur
float decodeTemperature(uint8_t highByte, uint8_t lowByte) {
  int16_t rawTemp = (highByte << 8) | lowByte;
  float temperature = rawTemp / 100.0; // Beispielhafte Dekodierung (angenommen, die Temperatur wird in Hundertsteln von Grad übertragen)
  return temperature;
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starte Verbindung mit BLE YC01...");

  BLEDevice::init("");
  pClient = BLEDevice::createClient();
  pClient->setClientCallbacks(new MyClientCallbacks());

  doConnect = true;
}

void loop() {
  if (connected) {
    if (!pRemoteCharacteristic) {
      pRemoteCharacteristic = pClient->getService(serviceUUID)->getCharacteristic(charUUID);
    }
    if (pRemoteCharacteristic->canRead()) {

      std::string value = pRemoteCharacteristic->readValue();
      String hexValue = "";

      uint8_t tempHighByte = value[13];
      uint8_t tempLowByte = value[14];
      float Temperatur = decodeTemperature(tempHighByte, tempLowByte);
      Serial.print("Temperatur: ");
      Serial.println(Temperatur);

      // ... (Dekodierung und Anzeige von pH, ORP, Batteriestatus)

      //int ph = ((value[3] << 8) + value[4]);
      //float pHWert = (ph);
      //Serial.print("pH-Wert: ");
      //Serial.println(pHWert);

      //int orp = ((value[7] << 8) + value[8]);
      //Serial.print("ORP-Wert: ");
      //Serial.println(orp);

      //int battery = ((value[5] << 8) + value[6]);
      //float battStatus = (battery / 45);
      //Serial.print("Batterie: ");
      //Serial.println(battStatus);

      for (size_t i = 0; i < value.length(); i++) {
        if (i > 0) hexValue += ":";
        hexValue += String(value[i], HEX);
      }
      Serial.print("Charakteristik Wert (Hex): ");
      Serial.println(hexValue);
      delay(20000);
    }
  }
  if (!connected && doConnect) {
    if (pClient->connect(serverAddress)) {
      connected = true;
    } else {
      connected = false;
      doConnect = false;
    }
  }
}

It looks like you may have forgotten to do the ‘decode’ step?

See git.infradead.org Git - users/dwmw2/esp32-pool.git/blob - pool.yaml :

      std::string rawmsg;
      for (int i = 0; i < x.size(); i++) {
         char buf[7];
         snprintf(buf, 7, " 0x%02x", (unsigned char) x[i]);
         rawmsg = rawmsg + buf;
      }
      ESP_LOGD("ble_client.receive", "raw value received with %d bytes: [%s]", x.size(), rawmsg.c_str()); // ####  Useful for debugging ####

      // ### DECODING ###
      uint8_t tmp = 0;
      uint8_t hibit = 0;
      uint8_t lobit = 0;
      uint8_t hibit1 = 0;
      uint8_t lobit1 = 0;
      auto message = x;

      for (int i = x.size() -1 ; i > 0; i--) {
        tmp=message[i];
        hibit1=(tmp&0x55)<<1;
        lobit1=(tmp&0xAA)>>1;
        tmp=message[i-1];
        hibit=(tmp&0x55)<<1;
        lobit=(tmp&0xAA)>>1;

        message[i]=~(hibit1|lobit);
        message[i-1]=~(hibit|lobit1);

      }

      rawmsg = "";
      for (int i = 0; i < message.size(); i++) {
         char buf[7];
         snprintf(buf, 7, " 0x%02x", (unsigned char) message[i]);
         rawmsg = rawmsg + buf;
      }
      ESP_LOGD("ble_client.receive", "value received with %d bytes: [%s]", message.size(), rawmsg.c_str()); // #### For debug ####


Sample logs:

Jul 31 19:25:31 pool ble_client.receive [D][ble_client.receive:374]: raw value received with 29 bytes: [ 0xff 0xa1 0xfc 0xf2 0xfd 0x0f 0xfc 0xc3 0xfd 0x2b 0x55 0x14 0xaa 0x22 0xfd 0x31 0xfa 0xa9 0x7f 0xfc 0x2b 0xff 0xbe 0xff 0xff 0xff 0xff 0xf7 0x00]
Jul 31 19:25:31 pool ble_client.receive [D][ble_client.receive:403]: value received with 29 bytes: [ 0x01 0x02 0x0f 0x01 0xa4 0x03 0x78 0x01 0xbc 0x01 0xc2 0xff 0xff 0x00 0xcc 0x0b 0xed 0x00 0x03 0xe8 0x01 0xc2 0x00 0x00 0x00 0x00 0x00 0x00 0xae]
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 Temperature': Sending state 20.40000 °C with 2 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 pH': Sending state 4.20000 pH with 2 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 ORP': Sending state 450.00000 mV with 0 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 battery': Sending state 95.70533 % with 0 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 EC': Sending state 888.00000 µS/cm with 0 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 TDS': Sending state 444.00000 ppm with 0 decimals of accuracy
Jul 31 19:25:31 pool sensor [D][sensor:094]: 'BLE-YC01 CL': Sending state nan ppm with 1 decimals of accuracy

Please show the bytes you’re receiving, and the values you are extracting from them?

Thank you David!
Now it works for me too.
I modified and pasted your code.
Thank you very much for your note.


21:28:25.365 -> Temperatur: 28.3 °C
21:28:25.365 -> pH - Wert: 3.7 pH
21:28:25.365 -> orp - Wert: 120 mV
21:28:25.365 -> Batterie - Status: 92.5 %
21:28:25.365 -> ec - Wert: 0 µS/cm
21:28:25.410 -> tds - Wert: 0 ppm
21:28:25.410 -> Chlor - Wert: 65535 (Fehler, Wert nicht lesbar!)

1 Like

hello,
I’m facing a new problem with the device but not the code.
Actual temperature is 20.2°C but a classic meter indicate 25.5°C
Also battery is 58% in the esp sensor, but 0% on the Yinmik app
I’d like to know if any of you have seen this problem ?

I haven’t seen a problem with the temperature reporting. The pH and other values seem very inaccurate but the temperature is the only thing I did trust.

The above recipes have different multipliers for the battery, and I’ve used 31.9 which seemed about right, but it’s a bit weird. Doesn’t explain the app reporting zero though. Do you believe it? Is the battery almost flat?

Hi,
this is exactly the behavior I’m seeing. When the battery approaches 60%, it can’t sustain enough voltage anymore and the temperature reading drops dramatically. You need to replace the battery.
This means that the battery reading is not really a percentage of the full charge, but it’s related to the voltage. One would have to check at what voltage it usually breaks down, and the renormalize the percentage to that range…

On another note: my device suddenly started to report a pH of around 8.5 out of nowhere (the water is still at 7.4 or so with other test equipment). I wonder whether there is a way to reset it to the previous calibration values…

Thanks for this feedback. I will go change my battery and measure it.
For the Ph, I’m afraid the only option is to recalibrate with the special pouder you received with it.

That I already did initially. Now I need to get a new one somewhere. I should have stored the solutions, but I don’t know how long they remain stable…

i think you can use it only for some minutes/hours. I’ve just bought some more at aliexpress. Here is the link if you want : https://www.aliexpress.com/item/1005004659424588.html

Thanks. meanwhile ordered it from amz since I wanted it soon. As they also sell these solutions in bottles, I guess they must be good for some more time once mixed…
I also got an orp solution, but couldn’t find an affordable TDS one yet (although that’s probably not too important)…

I wonder whether it’s sufficient to just turn off the ble_switch to preserve device battery…

Just wondering if I need to remove the plastic cap at the bottom, I saw a video on YouTube where the person removes it for calibration and I left it without. Readings are weird sometimes, mainly chlorine. Does anyone have the same?

I think the cap is just transport protection and needs to stay off so that water can get to the sensors…

1 Like

So this is weird. I now set it to enable the ble_switch every 30min, and upon reading it turns it off immediately. Still, battery goes down like crazy, like 1% every hour… But the device isn’t even connected, and no attempts at connection are made by the ESP32 (only the regular scans). Also, the display is off, as it always is when there is no active connection…

Made a basic native homeassistant integration here:
https://github.com/jdeath/BLE-YC01

I only made the native integration, I copied all the parsing and hard work posted in this thread!

Mine has not been calibrated or even in the pool yet, but at least temperature and pH match the display. Please post a github issue with any changes needed (PRs are appreciated). There is no error checking for invalid lines and I used a simple EC * .55 to get Salt. Not sure if that is correct.

This updates every 30 minutes, but that can be changed. Supports native bluetooth and ESPHome proxies. No need for manual setup, it will find the device automatically. Only supports branded BLE-YC01 for now.

3 Likes

Great work.

Installed, no icon here

Cood idea indeed, do the code can be improved and all managed in one place!!

I still sometimes have issues connecting to it, I need to turn on manually the meter and turn on then the switch, then it works… Untill a few hours later… It happened even that there was a freeze on the device, had to remove battery

I have my schedule on 60 min, instead of 30, could that be the reason?

The icon has to be submitted to homeassistant and approved to show up. I may do it eventually, but it is a pain: https://developers.home-assistant.io/blog/2020/05/08/logos-custom-integrations/