What Do Devices Do?
We now know that devices are connected to the client, but how do we figure out what we can do with them? In this section, we'll discover what inputs and ouputs a device has, and how we can use them.
Example Device
We'll be presenting a fairly standard, simple device here just to get things going. As of this writing, buttplug supports something like 750 devices with myriad outputs and inputs. We'll cover the full picture of everything the library supports and specific usecases in the Device Outputs portion of the Winning Ways Section later, once the basics are understood.
The device we'll be discussing here has the following features:
- 2 vibration motors, individually controllable, each with 50 steps of vibration speed.
- A battery that we can query for how much power it has left
This is vaguely similar to something like a Lovense Edge, but form factor isn't really an issue here. We just want an example of something we can control.
As an app developer, this is really all you need to know about the device. Buttplug hides most information about how things are connected (bluetooth, usb, etc) so you don't have to worry about them.
What even is a Buttplug Device?
Whenever we get a DeviceAdded() event, it'll usually come with some sort of structure representing the device. This will include:
- The Device Index
- A unique 32-bit unsigned integer that identifies the device to the server. As long as the user does not clear their server configuration, these indexes can be considered to be stable and usable for saving configuration options across sessions of your application.
- The Device Name, in 2 forms
- The canonical device name, as set in the Buttplug Device Config
- The user/display device name, which is a name users can set for a device so they can differentiate it from other devices.
- A message gap duration, in milliseconds
- This refers to the amount of time that the Buttplug Server will put between two messages, so that we don't end up with queued messages. This will be discussed more in the device control section.
- A set of features
- This denotes what a device actually does, we'll spend the rest of this section talking about these.
Device Features
Devices in Buttplug are made up of features.
Features contain:
- The Feature Index
- Similar to the Device Index. Unique (in the scope of the device) 32-bit unsigned integer that specifies which feature is which. A combination of Device Index and Feature Index are used to write command messages, outlined in the next section.
- A feature description
- Describes what the feature does, in English. Useful for showing in UI.
- A feature type
- This is the main function of the feature, though it may support multiple ways of doing things (i.e. a stroker that can work with positions or can just oscillate between two positions, a motor with an encoder so position can be both set and read, etc...). Feature types are only for getting a general idea of what a feature does, and are not used in commands.
- Outputs
- Things that the device does. Vibration, rotation, stroking, etc..., are all outputs.
- Output information will contain the OutputTypes a feature exposes, as well as the amount of steps an output can handle. For instance, with the device example we laid out above, steps would be 50 by default. However, servers like Intiface Central allow users to set upper limits that may be lower than the maximum a device can handle, so steps may be listed as lower than 50.
- Inputs
- Things a device can sense and relay information to us about. Battery levels, RSSI for radio connections, button presses, pressure sensors, are all types of inputs.
- Like Outputs, Input information will contain the InputTypes a feature exposes, and will also contain information about the possible values they can return. For instance, batteries will always return a number between 0-100, representing the percentage of power they have left. Other input types, like various pressure sensors, may vary in their output range.
They did! In prior versions of the library, we had MessageAttributes because each message denoted a sort of output type, which was horrible and complicated and very difficult to talk about, much less write useful documentation for. Parts of the v3 api moved us to using the actuator/sensor terminology. This was kept through the early parts of v4 api development.
Then I realized that the project is mostly referred to as buttplug dot io these days, thanks to the shitpost of a domain I got when I started all this. So why not name them Outputs and Inputs?
Is it less clear? Possibly. Is it both more on brand and hilarious? ABSOLUTELY.
Thus, Outputs and Inputs it is.
Will it be any easier to write documentation for? I refer you to the previous point about hilarity, which will hopefully hide any issues with documentation complexity from here on out.
Here's a few examples of what a device feature can look like:
- A single vibrator with 20 steps of vibration
- This will be a feature with a single Output, of type Vibrate, with steps set to 20. Pretty easy.
- A stroker
- This will be a feature with two output types: One that allows us to send the device to a position over the duration of time (PositionWithDuration), and another type that allows us to set the speed of oscillation between two points (Oscillate)
- A motor with an encoder
- This will be a feature with 1 output type of PositionWithDuration, and 1 input type of Position where we can read the current position of the motor at any time for setting up our own control loops.
- Note: The Position input type is just a handy example for the reason a feature might have both outputs and inputs. It does not actually exist in the library yet. Buttplug does not support any toys that actually tell us their current position, speed, or anything else. Not because we just haven't had time to support them, but because no toys exposing that information exist that we know of. I hate working with sex toys so fucking much. Why am I writing this library.
For our example above, we should expect:
- A single device, with 3 Features
- A feature for the first vibrator, exposing one Output of type Vibrate with 50 steps
- A feature for the second vibrator, exposing one Output of type Vibrate with 50 steps
- A feature for the battery, exposing one Input of type Battery. The battery type is implicitly assumed to have a range of 0 <= x <= 100, so no range information is sent.
Querying Device Feature Information
We'll start from where we left off in the last section. You've established a connection to a
Buttplug Server, you've set up your event handlers, and you've just gotten a DeviceAdded()
event.
We know there's a new device, but how can we tell what it does?
This code block shows how we can query the device and see what's available.