buttplugio / buttplug

Rust Implementation of the Buttplug Sex Toy Control Protocol
https://buttplug.io
Other
894 stars 65 forks source link

Discussion regarding the Handy and somewhat about connecting to devices via Wi-Fi/Web API's #606

Open Gremious opened 10 months ago

Gremious commented 10 months ago

I raise this discussion from having spent an evening reading the implementation for the Handy, and it's bluetooth interface handyplug. At first, I thought "haha @qdot left angry comments, that's funny to read". As I spent time familiarizing myself with the code, that feeling has since grown into a deep understanding. I am so sorry.

The handy is a stroker. The handyplug protocol is a little chunk of code (?) that hasn't been touched in two years, and implements a single useful control command: move to point X and take Y ms doing it. A linear movement, not an oscillation, for an oscillating toy.

The dev team for the handy does not care for developing this further:

We have limited developer resources, and our main focus is on our online platform. If you want to create a project using BLE, we recommend using buttplug.io. -- the handy team

Through great difficulty, handyplug was used and buttplug now supports a linear movement for the handy.

Intiface has a button to oscillate said linear movement so that's cool.

The handy, however, remains an oscillating piece of hardware.


This sucks lmao. I want to hack on existing code and update it to oscillate the handy, but I have to write manual back and forth motions with timings and sleeps between them, instead of ideally just translating a vibration call to an oscillation call.

On the other hand, the web API for this toy looks actually reasonable, as it implements alternating motions - start, stop, intensity, etc.

My questions then are the following:

Is connecting over Wi-Fi/implementing web API's for toys in scope for this project? Would it be reasonable to open a request for that? If it happens I probably wouldn't mind doing a PR the Handy API, at the very least for the alternating motions part.

Alternatively idk, can I communicate with intiface somehow and tell it to do whatever it does when I press the oscillation button?

Is there a magical third way?

Maybe I can write some sort of compatibility layer that handles looping movement, that also connects to intiface somehow someway...


Basically, it should not be my job to manually oscillate a toy, I should just tell buttplug to do it. It should not be buttplug's job to do it manually ether, it should just relay to the toy to do it. The toys suck and doesn't do it - so I'm just kinda looking for alternate solutions here.

qdot commented 10 months ago

Yeah, welcome to the fun of trying to maintain a generic API for a set of devices that are in no way generic.

So, first off: Hadn't seen Handy's new API. Main issue I see here (and I'm making big assumptions about architecture) is that it still requires talking to their server for every command, so you're network round-tripping off their endpoints, versus local control. That was mainly what we were trying to avoid when we said no wifi/web APIs in Buttplug: I don't want to debug everyone's individual network latency in a platform that should really not require it in the first place, but we're forced into these weird control models and local network discovery is the w o r s t (I just had a bad time with mDNS last month).

Now, that said, if you want a build a system where you take a vibration and turn that into an oscillation through Handy's Wifi system, that's completely possible through our poorly documented "Websocket Device Manager". Turning this on pops open yet another websocket server port that you can connect to and receive buttplug commands either as the raw JSON that they come in as, or formatted to the values of any other protocol our system handles. It does require setup via it's own simple protocol, and setting up the configuration part is still hellish (I'm working on integrating configuration of this into Intiface now, but it's requiring a ton of ground-up reworking), but once all the setup is done, it's pretty simple. There's documentation on this at https://docs.buttplug.io/docs/dev-guide/inflating-buttplug/devices/websocket-device-manager, or just poke me on here/discord/etc if you have other questions.

Gremious commented 10 months ago

That was mainly what we were trying to avoid when we said no wifi/web APIs in Buttplug ...

100% understandandable


"Websocket Device Manager" looks, at least in principle, like the right solution so far - thank you very much!

I think it wouldn't be far fetched to write some software that actually handles oscilation and ether translates vibrations or just immidates a handy more properly. I can probably still directly communicate with a BLE connected handy and do looping movements manually too, so I don't need to ask for wifi keys everywhere.

Thanks again, I'll look into it more properly and pop around if I have any questions!

Gremious commented 10 months ago

Heya! I set it up and it was honestly not that bad! And hey intiface seems to have GUI buttons to add user configs for websocket devices now, so that's nice.

My thoughts are that I can emulate a vibrating device/accept vibration messages, since most applications expect that, and simply route those to a connected handy appropriately.

However, it's a lil lame to show up as a "lovense hush" or something - I was wondering if buttplug has a "Generic/Software Device" that supports all types of signals? Or perhaps I can extend the handy user config with a linear message somehow?

I tried some random funky things e.g. :

Spoiler warning ```json { "version": { "major": 2, "minor": 6 }, "user-configs": { "specifiers": { "thehandy": { "websocket": { "names": [ "HandyCoordinator" ] }, "configurations": [ { "name": "The Handy Coordinator", "messages": { "LinearCmd": [ { "StepRange": [ 0, 100 ], "ActuatorType": "Position" } ], "ScalarCmd": [ { "StepRange": [ 0, 100 ], "ActuatorType": "Oscillate", "FeatureDescriptor": "Handy Oscillation Speed" } ] } } ] } } } } ```

But that didn't really change anything, no nice oscillation/vibration buttons in intiface.

qdot commented 10 months ago

Ok, so this is going to delve a bit into how protocols and configurations work internally.

You do not want to use thehandy as your basis. That's referring to OUR implementation of the Handy Protocol, which means a buttplug message gets turned into Handy's protocol format, THEN gets sent to you. That conversion from buttplug -> proprietary protocol is lossy; if a toy using that protocol does not provide a feature type, we don't implement it. The Handy (at the moment, disregarding CES news) does not currently have a vibrator, so we don't implement there, meaning even if you add new configurations, we'll just toss it because you're routing through our implementation of the protocol.

On top of that, setting new configuration on The Handy would require an identification step that does not exist on that protocol. Identification steps happen on some brands like Lovense or Satisfyer, where we have to use some extra data like response to a certain command or advertising manufacturer data to figure out what kind of toy under that brand we're talking to and specialize for it. For The Handy, there's just... The Handy. So we didn't create identification logic and I don't think there's the ability to do that otherwise.

What you probably want to do is choose either the "buttplug-passthru" protocol and parse raw buttplug messages yourself, or choose the protocol of something that already supports vibration, make a separate configuration, take the output of that, and translate the vibration/output to the corresponding handy web commands.

Gremious commented 10 months ago

Yep, that all makes perfect sense from what what I've seen working with this.

buttplug-passthru is what I am looking for - thank you very much! My only reference was the buttplug-device-config.json and passthru was not there, so I didn't see it.

Though, using it and sending a handshake immediately gives me a Close message and then a 10053: ConnectionAborted - unlike when e.g emulating a lovense device. I can't find it in the docs so I'd like to ask how this thing behaves differently from a regular device, please, do I need to configure/do anything special?

Spoiler log ``` 55.969 : [I] : Got connection 55.969 : [D] : Server handshake done. 55.969 : [I] : Device Websocket Device HandyCoordinator (6B201307C45C) found. 55.969 : [D] : Device 6B201307C45C allowed via configuration file, continuing. 55.969 : [I] : Starting websocket server connection event loop. 55.969 : [D] : Looking for protocol that matches specifier: Websocket(WebsocketSpecifier { names: {"HandyCoordinator"} }) 55.969 : [D] : No viable protocols for hardware Websocket(WebsocketSpecifier { names: {"HandyCoordinator"} }), ignoring. 55.969 : [I] : Websocket server connector owner dropped, disconnecting websocket connection. 55.969 : [D] : Exiting Websocket Server Device control loop. ```
qdot commented 10 months ago

Ok, so the important error message here is:

No viable protocols for hardware Websocket(WebsocketSpecifier { names: {"HandyCoordinator"} }), ignoring.

That means the system isn't matching your specifier to a protocol. Can you post what your current config file looks like?

(I am currently replacing this device config mess with a sqlite based DB mess, so this is a temporary thing)

Gremious commented 10 months ago

Knew I should have included that, here you go:

{
  "version": {
    "major": 2,
    "minor": 0
  },
  "user-configs": {
    "specifiers": {
      "buttplug-passthru": {
        "websocket": {
          "names": [
            "HandyCoordinator"
          ]
        },
        "configurations": []
      }
    },
    "devices": [
      {
        "identifier": {
          "address": "PeripheralId(80:64:6F:27:B0:C6)",
          "protocol": "thehandy",
          "identifier": "The Handy"
        },
        "config": {
          "index": 0
        }
      }
    ]
  }
}
qdot commented 10 months ago

Ok, I think you need to set up a default in the buttplug-passthru specifier, where configurations currently is. That's how we say "if I can't identify a device, just use this". Just copy something simple out of the main device config, that has a vibrator with 100 steps or something. I usually use the aneros one, it's fairly simple.

Gremious commented 10 months ago

I tried both

"buttplug-passthru": {
    "websocket": {
        "names": [
            "HandyCoordinator"
        ]
    },
    "defaults": {
        "name": "HandyCoordinator",
        "messages": {
            "ScalarCmd": [
                {
                    "StepRange": [
                        0,
                        127
                    ],
                    "FeatureDescriptor": "Perineum Vibrator",
                    "ActuatorType": "Vibrate"
                },
                {
                    "StepRange": [
                        0,
                        127
                    ],
                    "FeatureDescriptor": "Internal Vibrator",
                    "ActuatorType": "Vibrate"
                }
            ]
        }
    }
}

and

"buttplug-passthru": {
    "websocket": {
        "names": [
            "HandyCoordinator"
        ]
    },
    "configurations": [
        {
            "defaults": {
                "name": "HandyCoordinator",
                "messages": {
                    "ScalarCmd": [
                        {
                            "StepRange": [
                                0,
                                127
                            ],
                            "FeatureDescriptor": "Perineum Vibrator",
                            "ActuatorType": "Vibrate"
                        },
                        {
                            "StepRange": [
                                0,
                                127
                            ],
                            "FeatureDescriptor": "Internal Vibrator",
                            "ActuatorType": "Vibrate"
                        }
                    ]
                }
            }
        }
    ]
}

and it did not lead to any changes, unless I misunderstood the assignment.

p.s. idk if u prefer discord so i joined just in case, u can ping me if you want, same name. I don't mind ether, though I will be dropping out in like 30 min tops for the night

sorry to put you on debug duty, I appreciate the help <3

update: yep it broken just emulate a real toy for now

qdot commented 3 months ago

Ok, so, thanks to the Lovense Solace Pro, this just got weird.

The Solace Pro implements exactly what The Handy's WiFi API does, except over bluetooth. You can load funscripts to the device, and control them via pattern timing updates, but it's all local.

I don't foresee us getting this into buttplug in the message spec v4 update, but this may influence how we handle patterns in v5.