Adding support for Sensors with complicated characteristics

I just obtained the Adam Health nighttime erection sensor to try integrating into Buttplug.io for potential creative usecases.
The official app does show that it reports a live sensor measurement, but peeking in the decompiled code and poking with nRF Connect reveals that it has a bad protocol: It interleaves several streams of data through a single characteristic. For the measurement, a client must watch for the string “1335” and then parse the next string as a float, then divide it by 10.
I found the json/yaml device config file, but how would I implement this custom sensor protocol?
Thank you so much!

After digging around some more, I found the protocol directory and added a module there that should work for this device. I updated buttplug-device-config with the expected device name and UUIDs, so I think I’m ready to test it!

How do I add this custom build of the buttplug library to Intiface Central? I’ve cloned Intiface Central and Intiface Engine, set the intiface-engine-flutter-bridge Cargo.toml to point to the local directories for intiface-engine and buttplug, updated intiface-engine’s Cargo.toml to point to the same buttplug checkout, and I see the resulting intiface_engine_flutter_bridge.dll contains the updated device config JSON. However, Intiface Central logs messages like this:

flutter: 🐛 10:45:12.081311 DEBUG    Global Loggy - Found new bluetooth device advertisement: PeripheralInfo { name: Some("Check.ED Sensor"), peripheral_id: PeripheralId(C9:86:57:13:CB:52), manufacturer_data: {}, services: [569a1902-b87f-490c-92cb-11ba5ea5167c] }
flutter: 👻 10:45:12.081311 INFO     Global Loggy - Device Check.ED Sensor (PeripheralId(C9:86:57:13:CB:52)) found.
flutter: 🐛 10:45:12.081311 DEBUG    Global Loggy - Device PeripheralId(C9:86:57:13:CB:52) allowed via configuration file, continuing.
flutter: 🐛 10:45:12.081311 DEBUG    Global Loggy - Looking for protocol that matches specifier: BluetoothLE(BluetoothLESpecifier { names: {"Check.ED Sensor"}, manufacturer_data: [], advertised_services: {569a1902-b87f-490c-92cb-11ba5ea5167c}, services: {} })
flutter: 🐛 10:45:12.081311 DEBUG    Global Loggy - No viable protocols for hardware BluetoothLE(BluetoothLESpecifier { names: {"Check.ED Sensor"}, manufacturer_data: [], advertised_services: {569a1902-b87f-490c-92cb-11ba5ea5167c}, services: {} }), ignoring.

Can someone check my code draft and confirm my approach, or maybe find what I did wrong?

Ok, first off, if you’re going to test with Intiface Central, you’ll have to be careful that we don’t stomp the changes you’re making to config files by hand. I’m working on making this situation better as we speak.

Also if you want to save yourself compile time, I recommend just using Intiface Engine (GitHub - intiface/intiface-engine: Intiface CLI, except now also a library) and building your own little tester client or something for it.

But, nonetheless, congrats on getting a dev chain mostly working for Intiface Central, that’s not the easiest thing. :slight_smile:

Now then, in terms of what’s wrong: No viable protocols means you didn’t full register the protocol (it’s not an obvious process right now). Those have to be hand registered in the codebase. You’ll add it to get_default_protocol_map(): buttplug/buttplug/src/server/device/protocol/mod.rs at master · geekytwink/buttplug · GitHub

That should clear that error message up and let you connect.

Lemme know if you have any other issues, this is exciting work!

This isn’t far off the Lovense sensor readings: one stream of data that you have to parse and split is pretty common.

My general recommendation is to always start by opening an issue on Issues · buttplugio/docs.buttplug.io · GitHub as protocol documentation.

Thank you for the tips! The default protocol map now contains the adamhealth module.
However, it seems my updated buttplug-device-config.json file isn’t taking effect. Even if I clear most of the contents, and observe the change in the intiface_engine_flutter_bridge.dll file, extra logging in the protocol specifier parsing shows that it’s somehow using the original contents. Where else would it be loading the main device configuration file from, if not its internal resources?

If you’re still using intiface central, the config file is in c:\Users\[your user name]\AppData\Roaming\com.nonpolynomial\intiface_central\config.

The config file can be updated without needing to recompile the library. That’s why I was talking about your changes possibly being stomped, though as long as we don’t update the main config ourselves for download, you should be fine.

Oh thank you so much! I was able to manually add my config to that profile config file, and then it connected right away.
And then I fixed up bugs in my implementation and sent over a Pull Request, looking forward to your feedback <3