Reading off the shelf BLE Moisture Sensor w/ Boron?


I am attempting to read an off the shelf bluetooth moisture sensor with a gen3 Particle device (Boron). I am comfortable with microcontrollers but have never setup bluetooth before. I have read the Particle BLE tutorial, but still feeling a bit overwhelmed.

There are a lot of fragments of code in the above tutorial, and I’m not sure how to actually put them together into a working example.

The second major problem I have is I don’t see any docs for the moisture sensor I’m using. It is intended to connect to a proprietary phone app and doesn’t tell me what services or characteristics it uses. Looking over the Services list and Characteristics list from the BLE site (the one linked in the tutorial) I don’t see anything that would be used for moisture.

The sensor I’m using is an HHCC brand sensor that measures sunlight, moisture, temperature, and fertilizer. I believe this is a link to it:

I’m hoping someone can help me piece together a quick example. I’ve been at this for hours digging around the internet and still don’t really know where to begin on this.

Also if anyone has suggestions on the Service or Characteristic I may try to poll to discover useful data from this thing. Other than writing a block of code to poll all the known UUIDs, I’m not sure where to go.

I’m sure this is super easy to do once I’ve seen it done, I’m just not finding something that explicitly spells it out.

Thank you.

Quick google brought me here which I think provides info of the vendor specific services and characteristics.

1 Like

Thanks!!! That’s it. Man I’ve been digging for a while on the various UUID codes I sniffed with a scanner and didn’t find this. Very much appreciated. :facepunch:

I’ll also add this for anyone finding this later… sniffing data from BLE, this video was very helpful, and his first video he mentions is also very good primer knowledge of how the packets actually work. Good stuff.

I ended up ordering the sniffer board for about $40 here:

Thanks again!

1 Like

Hey @kkeng

The important thing is to get the documentation for the device itself. If it has no documentation, you can connect to it using an app like nRF Connect ( or Light Blue Explorer ( (Android links and respectively)

In your case, you can copy the UUID and use them to connect as a Central device. I recently posted some code for Thingy52 + Particle Mesh. You should be able to modify and re-use for your purposes.

Here are some of my write ups on the subject. The first using Central mode. The second using Peripheral mode.

Happy to answer any questions you have. :slight_smile: Hope it helps!


Hi @kkeng. Did you get your project running? I am also attempting to read a Xiaomi sensor from an Argon and am having trouble converting the linked-to github example into Particle code. Specifically I’m unsure how to connect to the correct characteristic(s), send the commands to get the realtime measurements, and then retrieve them.


Not sure if this relates to what you are looking for, but after I provided this code here (at the end of that long post)
I haven’t really heard anything back from @kkeng anmore.

But since then the issue UUID-issue I was refering to in that thread may have been dealt with and we should be able to simplify that a bit.
I haven’t tested the new implementation against my found edge-cases tho’, so I’m not yet convinced the issue was fully addressed.

Thanks, @ScruffR.

I managed to get my project working. Your and @jaredwolff’s examples were incredibly helpful. I am able to connect to a sensor and read its realtime sensor values.

Now I’m working on connecting to several sensors at once and have a new question: When I receive sensor data in the onDataReceived callback, I want to know which sensor it came from. Do I need to have different callback functions for each sensor (each Peer object), or can I do it with one? If one, how do I know which sensor called it? I’m guessing it has to do with the Context parameter but I can’t figure out how to use it.



Hey @dperrigan

Your intuition is correct! When you set up the callback, the context is how you can recycle that function call for multiple events.

Depending on what you’re doing, you can either feed a unique constant for each event type or use pointers to an object or struct. Typically a context will be a void pointer so you need to cast it that way when you enter it:


Hopefully that makes sense. I’m writing this on my phone so if you need more details I’ll get back to you next week.

Thanks, Jared. I got it working by comparing addresses but now I can try the context pass method.

1 Like