Spec Changelog
Version 4 (2025-07-??)
- Nomenclature change: Standard -> API
- Gonna stop calling this a standard. it's not. There's nothing to standardize here. No one wants to work together in this field. This library is glue between a bunch of devices and manufacturers that either don't recognize or actively hate each other, and trying to pass ourselves off as some unifying piece between these entities has been a fine branding move, but ultimately futile in terms of actually setting anything usable in stone.
- On top of that, Buttplug as a project is operating without a plan. There's no real direction, we're mostly pulling stuff out of our butt, seeing what works, then reorienting around that. Not a particularly good way to standardize anything. The rest of this changelog will bear out that fact in excrusiating detail.
- Also, we're 8 years into this project now and not a single person has tried building a server themselves. Which is good, because doing so requires a level of mental instability that would make quality of life questionable for anyone who tried. The ecosystem exists on top of us, but it is not us. I don't think it's ever going to be, and that's fine.
- From here on out, this will now just be referred to as the Buttplug Protocol Spec.
- Change from Message Attributes to Device Features
- In message specs v0-3, we'd enumerated devices in terms of the messages they could receive. This had multiple problems, including index collisions, difficult figuring out what a device actually does, and building coherent APIs to form messages. In v4, we switch to a Device Feature system, which presents devices as sets of 2 different types of features: Outputs and Inputs. This allows us to state what a device can do, and then define capabilities within each feature. This solves the issue with index collisions (as we now use feature indexes instead of just message enumeration array indexes), and makes it easier for developers using buttplug to create UI representing the capabilities of a connected device.
- This change will be seen in the
DeviceAdded
/DeviceList
messages, as well as in the newOutputCmd
/InputCmd
commands.
- Define
OutputType
, andInputType
in message spec and require spec point updates to add new features- As part of the introduction of
ScalarCmd
in spec v3, we introduced anActuatorType
value, to let developers know what type of value they were setting, as well asSensorType
for sensors. The values ofActuatorType
/SensorType
were never set in the message spec, only in the reference implementations of the Buttplug server. These values should be defined within the message spec to let Client writers know exactly what to expect, and how to handle types they may not know (i.e. a client built for message spec v4.1 receives aOutputType
/InputType
defined in v4.2 should not completely break, but should complain).
- As part of the introduction of
- Remove ability to send multiple commands ("subcommands") in device command messages
- In past versions of Buttplug, we allowed multiple commands to be sent within a command package.
For instance, if a device had multiple vibrators, a single v3
ScalarCmd
could contain commands for both of these devices. Creating a usable API to form these messages was damn near impossible, and just ended up in implementation complexity on the server side that was never really exposed to developers well. From v4 on, command packets take one command for one output, and the server can handle that as it will.
- In past versions of Buttplug, we allowed multiple commands to be sent within a command package.
For instance, if a device had multiple vibrators, a single v3
- Add
FeatureIndex
to commands- As we now refer to features instead of message attribute array positions, we're updating the
Index
field of commands with corresponding commands (what would've been subcommands inScalarCmd
/RotateCmd
/LinearCmd
in v3) to takeFeatureIndex
in v4'sOutputCmd
/InputCmd
instead.
- As we now refer to features instead of message attribute array positions, we're updating the
- Remove
DeviceAdded
andDeviceRemoved
- We will now just send
DeviceList
when a client connects (post handshake), and on any device connection changes. It will be up to the client to implement logic to handle additions/deletions from the device list, but this allows us to simplify protocol implementations.
- We will now just send
- Remove
Raw*Cmd
RawReadCmd
/RawWriteCmd
/Raw[Un]Subscribe
were introduced in the v2 spec to aid development, allowing developers to bypass the protocol system in Buttplug and directly write byte buffers to devices. This was a bad idea, as Buttplug is built to be a protocol translation system, and this routed around the main point of the library. It ended up being about 2000 extra lines of code around the library to support, with almost no use, and the possibility of users turning it on and exposing their devices to bricking.
- Remove
ScalarCmd
/RotateCmd
/LinearCmd
, replace withOutputCmd
andOutputType
variations- We have flipped the context of device command messages. Instead of stating intention by action, we now simply state that we are addressing the output of a device, and give more context with the message. This allows us to only update possible field values within a message versus having to add new messages any time we want to address a new context.
- In ELI5 terms: If a new device comes out that moves or does something in a new way, we don't have to do a major revision to the message spec to add support.
- Remove
Sensor*Cmd
, replace withInputCmd
andInputCommand
variations- Due to index collision issues,
Sensor*Cmd
was never really directly supported or used in Buttplug outside of getting Battery values. These issues have now been fixed, and the same context flip asOutputCmd
has been applied to provide us withInputCmd
. - Why are they named
OutputCmd
andInputCmd
instead of following the nomenclature of v3 and usingActuatorCmd
andSensorCmd
? Because our domain is buttplug.io and now we have io commands. You can never say we do not commit to the bit fully on this project.
- Due to index collision issues,
- Change device commands to use integers instead of floats for control values
- When Buttplug started we decided to use floats instead of integers for command values. This meant that clients had to calculate steps to a value between 0.0-1.0. However, this was also usually exposed to application developers in this way, meaning they had to consider the step difference amounts in order to make device actuators actually do something different (i.e. if a device had 5 steps, the application dev would have to know to round between values of x * 0.2). Moving to integers that are limited by the amount of available steps on a device makes life easier for everyone, as well as optimizing our line protocol as it's one less float to try to translate.
- Rename
MessageVersion
toProtocolMajorVersion
and addProtocolMinorVersion
inRequestServerInfo
/ServerInfo
messages.- This allows us to add features to message versions without having to bump major versions every time.
- Servers return
ProtocolMajorVersion
andProtocolMinorVersion
for connections on >= v4, justMessageMajorVersion
for < v4
StopDeviceCmd
no longer sent as a possible message on a device description- We now let developers assume all devices can take
StopDeviceCmd
, so there is no need to attach it to device descriptors. StopDeviceCmd
will be valid for both actuators (i.e. make a vibrator stop vibrating) and sensors (i.e. cause an unsubscribe from a subscribed endpoint)
- We now let developers assume all devices can take
Imaginary Version ~4 Beta 1 (2025-03-??)
THEN IT HAPPENED AGAIN.
- Rename
LinearCmd
andRotateCmd
toValueWithParameterCmd
- Linear and Rotate were both messages that could be described in an "x with y" way, i.e.
RotationWithDirection
,PositionWithDuration
, etc... This condensing and renaming of commands will hopefully make this idea easier to convey while giving us the extensibility of using ActuatorTypes (and therefore not having to add new messages whenever we want to update).
- Linear and Rotate were both messages that could be described in an "x with y" way, i.e.
- Renamed
Sensor*
fields toFeature*
inSensor*Cmd
Messages- Aligns with new feature system
- Add
EventCmd
(Ed. Note: or maybe BangCmd, not sure yet)- We're seeing devices that require a one-off command to cause an event to happen. For instance, the Hismith lubrication injector, lube injectors for the SR-6/OSR-2, etc... We needed a command that denote that an event will happen, but will not be continuously happening, like StaticCmd.
Imaginary Version ~4 Beta 0 (2024-09-??)
This version never actually existed. I'm just leaving it here to show how things change if I let the project sit for months at a time.
- Rename
LinearCmd
toGoalWithDurationCmd
(Ed. Note: This is still a maybe)- Much like the move to
ScalarCmd
in v3,LinearCmd
is now being generalized to "movement toward a goal value with a duration". Added to the definition will be a curve type for the movement, though at the moment the only supported curve will be of "Linear" type (later versions may include different curves or the ability to define a curve function over time). For now, this means we can handle both stroker style movement as well as things like angular rotation in TCode v3, denoting the movement type via feature types.
- Much like the move to
- Rename
ScalarCmd
toStaticCmd
(Ed. Note: I'm not sure about this name yet :| )ScalarCmd
is being renamed toStaticCmd
to denote that sending the command is expected to set a value and leave it set until anotherStaticCmd
orStopDeviceCmd
call is sent.ScalarCmd
didn't properly relay this meaning.
- Remove
RotateCmd
, useStaticCmd
- See note on last bullet for more info.
- Remove
ActuatorType
fromStaticCmd
(Ed Note: This is still a maybe)- This was initially added as a safety check on
ScalarCmd
, to make sure that the developer was actually triggering the type of actuator they meant to be. However, as clients usually (or at least should) hide this detail from end users, it's not useful to anyone but client developers.
- This was initially added as a safety check on
- Change
StaticCmd
to take signed double instead of unsigned double- The unsigned value given to v3
ScalarCmd
made it difficult to define messages that might actually be 2d instead of 1d (i.e. embedding rotation direction with a -1 <= x <= 1 value, letting us removeRotateCmd
). ChangeStaticCmd
in v4 to take signed values, so we can condense methods.
- The unsigned value given to v3
Version 3 Patch 3 (2022-12-30)
- Message Definitions Fixed:
- The
SensorType
andSensorRange
message attributes are valid for SensorSubscribeCmd as well as SensorReadCmd.
- The
Version 3 Patch 2 (2022-12-27)
- Message Definitions Fixed:
- DeviceAdded/DeviceList use
DeviceMessageTimingGap
, notDeviceMessageGap
. - LinearCmd/RotateCmd information in the message attributes of DeviceAdded/DeviceList will have an ActuatorType (Previously stated that only ScalarCmd has an actuator type).
- DeviceAdded/DeviceList use
Version 3 Patch 1 (2022-10-14)
- Message Descriptions Changed:
- ServerInfo
- The original idea behind ServerInfo's message spec version output was to notify clients if a new, higher version of the message spec might be available, prompting for upgrade. Unfortunately, a long running programming error in multiple official reference libraries will cause connections to fail if the server lists its maximum available spec version and that version is higher than the client's spec version. Therefore, ServerInfo cannot return a version that is higher than the client's spec verison. ServerInfo should return either a version that matches the clients, or throw an error if it cannot match the client's version. This does not change the structure of the message, just the expectations of how it should function.
- ServerInfo
Version 3 (2022-08-29)
- Messages Added:
- ScalarCmd
- Replaces VibrateCmd and adds ability to easily extend with new actuator types that take a single value.
- SensorReadCmd
- Replaces Battery/RSSI messages and adds ability to easily extend with new sensor types.
- SensorSubscribeCmd
- Allows users to receive realtime updates from devices (pressure sensors kegelcizers, accelerometers in toys that have them, etc...)
- SensorUnsubscribeCmd
- SensorReading
- Data returned from either sensor being read, or a subscription event.
- ScalarCmd
- Messages Changed:
- DeviceList/DeviceAdded
- Remove FeatureCount, Message Attributes are now an array of attribute objects instead of many fields of arrays that had to be reconstructed. Should reduce bookkeeping.
- Added Message Attributes FeatureDescriptor, ActuatorType, SensorType
- Added Device Attributes DisplayName, DeviceMessageGap
- For messages that have matching "undo" types, like RawSubscribe/RawUnsubscribe or SensorSubscribe/SensorUnsubscribe, only the initial command is relayed in the message attributes of DeviceAdded or DeviceList. The arguments for these commands are the same, and it's assumed that if you can do something that has a matching undo, you'll only need to know about one.
- DeviceList/DeviceAdded
- Messages Deprecated:
- VibrateCmd
- Superceded by ScalarCmd. Will still be available via API calls in client APIs, just no longer needs to be a specific message in the protocol.
- BatteryLevelCmd
- Superceded by SensorReadCmd
- RSSILevelCmd
- Superceded by SensorReadCmd
- BatteryLevelReading
- Superceded by SensorReading
- RSSILevelReading
- Superceded by SensorReading
- VibrateCmd
Version 2 (2020-09-28)
- Messages Added:
- RawWriteCmd
- RawReadCmd
- RawReading
- RawSubscribeCmd
- RawUnsubscribeCmd
- BatteryLevelCmd
- BatteryLevelReading
- RSSILevelCmd
- RSSILevelReading
- Messages Changed:
- DeviceList/DeviceAdded
- Adding StepCount to Message Attributes, to let users know how many steps a feature can use (i.e. how many vibration levels a piece of hardware might have)
- ServerInfo
- Remove Version fields
- DeviceList/DeviceAdded
- Messages Deprecated:
- LovenseCmd
- Superceded by VibrateCmd/RotateCmd/Raw*Cmd. The protocol messages were originally meant to map generic -> protocol -> raw, but the protocols change quickly enough that it's not worth it to encode that at the protocol level. From v2 of the spec on, we will try to encode as many actions as possible in generic messages. For anything we haven't mapped yet, Raw*Cmd can be used, though it's not a great idea due to security concerns.
- LovenseCmd was never implemented in any of the Buttplug reference libraries, so removal shouldn't affect anything.
- KiirooCmd
- Superceded by VibrateCmd/LinearCmd/Raw*Cmd. See above for more explanation.
- Only implemented by the Kiiroo Pearl 1 and Onyx 1 in Buttplug C#. Not sure it was ever used anywhere.
- VorzeA10CycloneCmd
- Superceded by RotateCmd/PatternCmd. See above for more explanation.
- Implemented for the Vorze A10 Cyclone in C# and JS, but translates directly to rotation messages.
- FleshlightLaunchFW12Cmd
- Superceded by LinearCmd/Raw*Cmd. See LovenseCmd reason for more explanation.
- Implemented for the Fleshlight Launch, and will be problematic to switch out. We should still support it on the server side for v0/v1 for compat.
- Test
- Violates assumptions that client/server sends different message types. Also, not particularly useful.
- RequestLog/Log
- Allows too much information leakage across the protocol in situations we may not want, and also has nothing to do with sex toy control. Logging is an application level function, not really required in the protocol itself.
- LovenseCmd
Version 1 (2017-12-11)
- Messages Added:
- VibrateCmd
- LinearCmd
- RotateCmd
- Messages Changed:
- DeviceList/DeviceAdded
- Added Message Attributes blocks to device info, with FeatureCount attribute
- RequestServerInfo
- Added Spec Version Field
- DeviceList/DeviceAdded
- Messages Deprecated:
- SingleMotorVibrateCmd
- Superceded by VibrateCmd
- SingleMotorVibrateCmd
Version 0 (2017-08-24)
- First version of spec
- Messages Added:
- Ok
- Error
- Log
- RequestLog
- Ping
- Test
- RequestServerInfo
- ServerInfo
- RequestDeviceList
- DeviceList
- DeviceAdded
- DeviceRemoved
- StartScanning
- StopScanning
- ScanningFinished
- SingleMotorVibrateCmd
- FleshlightLaunchFW12Cmd
- LovenseCmd
- KiirooCmd
- VorzeA10CycloneCmd
- StopDeviceCmd
- StopAllDevices