rbaron / b-parasite

🌱💧 An open source DIY soil moisture sensor
1.85k stars 143 forks source link

Report battery percentage in ble #187

Closed jrhbcn closed 2 months ago

jrhbcn commented 2 months ago

Hi,

Is it possible to report battery percentage in BLE firmware (as zigbee firmware does)? I can only see battery voltage reported in home assistant. I did not find any option in Kconfig so I guess it is intended?

Regards,

rbaron commented 2 months ago

Hey @jrhbcn,

Currently the BLE payload only carries the battery voltage. This info is encoded here.

This uses the BTHome encoding, and it supports encoding the battery percentage just as easily as the voltage. We can't simply append that info though, as we would require more than the number of bytes we have available in the BLE packet. So we have at least three choices:

  1. Send an extra packet with more information. I don't love this because it consumes extra battery
  2. Swap some values for the battery percentage. Fine if for example you don't need illuminance
  3. More tightly pack the existing values and open up space

Solution 3 may actually work. For example, now we use 3 bytes for humidity. BTHome supports using either 3 or 2:

image

Our humidity sensor anyway has 2% accuracy, so it's really no use to use 3 bytes. We can save one byte here.

Similarly for soil moisture. We currently use 3 bytes. Our resolution is definitely over 1%, and we can also save up one byte there:

image

This would free up 2 bytes, which we can use to encode the battery percentage:

image

The batt percentage is already available in the prst_sensors_t value (via prst_batt_t), and so it's already available in the encoding function.

The caveat is that the battery percentage estimation is very rough, but likely a good first approximation.

If you'd like to take a stab at contributing these changes, please do so. Otherwise let me know and I will see if I can get it to work.

jrhbcn commented 2 months ago

Many thanks for the fast answer @rbaron,

Your solution 3 seems indeed perfect, as having so much resolution reported in the humidity or moisture does not make sense if the accuracy is above 1%.

My coding skills are quite rusty, so it might take a while for me to figure out how to modify the protocol. If you find the time to make a quick try in a branch it'll be for sure much quicker 0:) I can surely pick up from there and test/tune the protocol in my end.

Again, thanks for this fantastic little thing.

jrhbcn commented 2 months ago

I am actually trying take the dust out of my coding skills (so long ago :) and I am trying to understand the protocol. It seems actually something I can do. Would something like this work to change the humidity values?

from:

  // Humidity.
  out[6] = 0x03;
  // Value. Factor 0.01, over 100%.
  uint16_t humi_val = 10000 * sensors->shtc3.rel_humi;
  out[7] = humi_val & 0xff;
  out[8] = humi_val >> 8;

to:

  // Humidity.
  out[6] = 0x2E;
  // Value. Factor 1, over 100%.
  uint8_t humi_val = ensors->shtc3.rel_humi;
  out[7] = humi_val;

similar thing the moisture, and then add something like this for battery?

// Battery percentage
  out[17] = 0x01;
  // Value. Factor 1
  uint8_t batt_percentage_val = sensors->batt.percentage; 
  out[18] = batt_percentage_val;

If you think it makes sense, I can update the firmware and check if it works...

jrhbcn commented 2 months ago

OK, after reading a little bit more, I have settled for this:

  // Humidity.
  out[6] = 0x2E;
  // Value. Factor 1 over 100%.
  uint8_t humi_val = (100*sensors->shtc3.rel_humi + 0.5f);
  out[7] = humi_val;

...

  // Soil moisture.
  out[15] = 0x2F;
  // Factor of 1 over 100%
  uint8_t soil_val = sensors->soil.percentage + 0.5f;
  out[16] = soil_val;

  // Battery percentage
  out[17] = 0x01;
  // Value. Factor 1 over 100%
  uint8_t batt_percentage_val = sensors->batt.percentage + 0.5f; 
  out[18] = batt_percentage_val;

Looks good so I am going to try it! :)

jrhbcn commented 2 months ago

OK, first test and humidity seem to report values between 0-100% correctly with 1 byte. However, battery and moisture have both gone to 0%. :?

Is it needed to also multiply by 100* the sensors->soil.percentage and sensors->batt.percentage ??

Sorry for the multiple comments

rbaron commented 2 months ago

Tks for trying your hand at this. I think it's well in the right direction.

I believe the new object IDs and offsets you changed are correct (0x23 for the 1-byte humidity and 0x2f for moisture). But we probably need to update the new 1-byte value.

They seem to be encoded as a percentage in [0, 100]:

// shtc3.rel_humi is a value in [0, 1.0f], so we multiply by 100.
uint8_t humi_val = 100 * sensors->shtc3.rel_humi;
// soil.percentage is a value in [0, 1.0f], so we multiply it by 100.
uint8_t soil_val = 100 * sensors->soil.percentage;

I think this should do the trick.

jrhbcn commented 2 months ago

Yep, it does! ;)

I've got it working correctly here now. Many thanks.

I am happy to make a PR for this if you want. Should I just replace the current protocol for this?

rbaron commented 2 months ago

Awesome!

I would claim this change is backward compatible enough that we can just update it. The only chance of breaking I think is if the receiving end doesn't understand the object ids 0x2e and 0x2f. These seem to be added at a later point than the original ones in the BTHome V2 protocol. But I just checked and they were implemented at least 2y ago, which is pretty close to the introduction of V2 altogether AFAICT. I'm fine updating it.

jrhbcn commented 2 months ago

PR done! Thanks.