Copyright | (c) James Sully 2020-2021 |
---|---|
License | BSD 3-Clause |
Maintainer | sullyj3@gmail.com |
Stability | experimental |
Portability | untested |
Safe Haskell | None |
Language | Haskell2010 |
An implementation of the Buttplug Intimate Device Control Standard (https://buttplug.io/)
Synopsis
- class Connector c
- type family Connection c = conn | conn -> c
- runClient :: Connector c => c -> (Connection c -> IO a) -> IO a
- sendMessages :: Connector c => Connection c -> [Message] -> IO ()
- receiveMsgs :: Connector c => Connection c -> IO [Message]
- sendMessage :: forall c. Connector c => Connection c -> Message -> IO ()
- data ConnectorException
- data WebSocketConnector
- clientMessageVersion :: Word
- data Message
- = MsgOk { }
- | MsgError { }
- | MsgPing { }
- | MsgRequestServerInfo {
- msgId :: Word
- msgClientName :: Text
- msgMessageVersion :: Word
- | MsgServerInfo { }
- | MsgStartScanning { }
- | MsgStopScanning { }
- | MsgScanningFinished { }
- | MsgRequestDeviceList { }
- | MsgDeviceList {
- msgId :: Word
- msgDevices :: [Device]
- | MsgDeviceAdded { }
- | MsgDeviceRemoved {
- msgId :: Word
- msgDeviceIndex :: Word
- | MsgRawWriteCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- msgEndpoint :: Text
- msgData :: RawData
- msgWriteWithResponse :: Bool
- | MsgRawReadCmd { }
- | MsgRawReading {
- msgId :: Word
- msgDeviceIndex :: Word
- msgEndpoint :: Text
- msgData :: RawData
- | MsgRawSubscribeCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- msgEndpoint :: Text
- | MsgRawUnsubscribeCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- msgEndpoint :: Text
- | MsgStopDeviceCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- | MsgStopAllDevices { }
- | MsgVibrateCmd { }
- | MsgLinearCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- msgVectors :: [LinearActuate]
- | MsgRotateCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- msgRotations :: [Rotate]
- | MsgBatteryLevelCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- | MsgBatteryLevelReading {
- msgId :: Word
- msgDeviceIndex :: Word
- msgBatteryLevel :: Double
- | MsgRSSILevelCmd {
- msgId :: Word
- msgDeviceIndex :: Word
- | MsgRSSILevelReading {
- msgId :: Word
- msgDeviceIndex :: Word
- msgRSSILevel :: Int
- data ErrorCode
- data Vibrate = Vibrate {}
- data Rotate = Rotate {}
- data LinearActuate = LinearActuate {}
- newtype RawData = RawData ByteString
- data MessageAttributes = MessageAttributes {
- attrFeatureCount :: Maybe Word
- attrStepCount :: Maybe [Word]
- data Device = Device {}
- data DeviceMessageType
Overview
See (https://buttplug.io/documentation/) for documentation of the Buttplug protocol.
The basic idea is:
- The Buttplug protocol is designed to simplify the process of using computers to control sex toys, by abstracting over individual hardware details.
- A Buttplug server is responsible for connecting to individual devices, and understanding the specific details of operating them. I recommend Intiface-cli-rs, a command line server implementation: (https://github.com/intiface/intiface-cli-rs)
- Applications act as Buttplug clients, speaking a straightforward message format to the server, which abstracts over the individual details of different devices. In this way developers are presented with a simple API for controlling a wide variety of different toys.
This package contains the core types and functionality for writing clients, including:
- The
Message
type, and Aeson instances for serialization and deserialization. The Buttplug message format is documented here: (https://buttplug-spec.docs.buttplug.io/messages.html#basic-message-structure) - The
Connector
typeclass, which abstracts over different ways of communicating with a Buttplug server. A connector allows the developer to open connections to the Buttplug Server, and send and receive Messages. WebSocketConnector
, for connecting to a Buttplug server using Websockets.
As this library is still experimental, please feel free to suggest API improvements!
Tutorial
See (https://github.com/sullyj3/buttplug-hs-core/blob/main/examples/example.lhs) for a basic tutorial.
Connectors and connections
Abstracts over methods of connecting to a buttplug server. The connector contains all the information necessary for establishing a connection.
Instances
Connector WebSocketConnector Source # | |
Defined in Buttplug.Core.Connector type Connection WebSocketConnector = (conn :: Type) Source # runClient :: WebSocketConnector -> (Connection WebSocketConnector -> IO a) -> IO a Source # sendMessages :: Connection WebSocketConnector -> [Message] -> IO () Source # receiveMsgs :: Connection WebSocketConnector -> IO [Message] Source # |
type family Connection c = conn | conn -> c Source #
A Connector determines a unique connection type that is used for communication.
Instances
type Connection WebSocketConnector Source # | |
Defined in Buttplug.Core.Connector |
runClient :: Connector c => c -> (Connection c -> IO a) -> IO a Source #
Main entry point for communicating with the Buttplug server. Establish a connection to the server and pass the connection handle to the continuation.
sendMessages :: Connector c => Connection c -> [Message] -> IO () Source #
Send Message
s to the server. In the Buttplug protocol, all messages
are wrapped in a JSON array (here a Haskell list) to facilitate sending
multiple messages simultaneously. Use sendMessage
to send a single
message.
receiveMsgs :: Connector c => Connection c -> IO [Message] Source #
receive Message
s from the server
sendMessage :: forall c. Connector c => Connection c -> Message -> IO () Source #
Send the server a single Message
data ConnectorException Source #
An exception type abstracting over the exceptions that might arise in the
course of communication with the buttplug server. Connector
instances in
general should throw these rather than Exceptions specific to the connection
type.
ConnectionFailed String | |
UnexpectedConnectionClosed | |
ConnectionClosedNormally | |
ReceivedInvalidMessage ByteString | |
OtherConnectorError String |
Instances
Show ConnectorException Source # | |
Defined in Buttplug.Core.Connector showsPrec :: Int -> ConnectorException -> ShowS # show :: ConnectorException -> String # showList :: [ConnectorException] -> ShowS # | |
Exception ConnectorException Source # | |
Defined in Buttplug.Core.Connector |
data WebSocketConnector Source #
Connect to the buttplug server using websockets
InsecureWebSocketConnector | |
SecureWebSocketConnector | |
|
Instances
Connector WebSocketConnector Source # | |
Defined in Buttplug.Core.Connector type Connection WebSocketConnector = (conn :: Type) Source # runClient :: WebSocketConnector -> (Connection WebSocketConnector -> IO a) -> IO a Source # sendMessages :: Connection WebSocketConnector -> [Message] -> IO () Source # receiveMsgs :: Connection WebSocketConnector -> IO [Message] Source # | |
type Connection WebSocketConnector Source # | |
Defined in Buttplug.Core.Connector |
Messages
clientMessageVersion :: Word Source #
The version of the Buttplug message protocol that the client speaks. (currently version 2)
The type of Buttplug protocol messages. See (https://buttplug-spec.docs.buttplug.io/messages.html) for the protocol specification and an explanation of the purpose of each message.
Instances
Errors from the server, used in the Error message.
ERROR_UNKNOWN | An unknown error occurred. |
ERROR_INIT | Handshake did not succeed. |
ERROR_PING | A ping was not sent in the expected time. |
ERROR_MSG | A message parsing or permission error occurred. |
ERROR_DEVICE | A command sent to a device returned an error. |
Instances
Used in VibrateCmd to specify the speed of the motor at the given index
Instances
Eq Vibrate Source # | |
Show Vibrate Source # | |
Generic Vibrate Source # | |
FromJSON Vibrate Source # | |
Defined in Buttplug.Core.Message parseJSON :: Value -> Parser Vibrate parseJSONList :: Value -> Parser [Vibrate] | |
ToJSON Vibrate Source # | |
Defined in Buttplug.Core.Message toEncoding :: Vibrate -> Encoding toJSONList :: [Vibrate] -> Value toEncodingList :: [Vibrate] -> Encoding | |
type Rep Vibrate Source # | |
Defined in Buttplug.Core.Message type Rep Vibrate = D1 ('MetaData "Vibrate" "Buttplug.Core.Message" "buttplug-hs-core-0.1.0.0-inplace" 'False) (C1 ('MetaCons "Vibrate" 'PrefixI 'True) (S1 ('MetaSel ('Just "vibrateIndex") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word) :*: S1 ('MetaSel ('Just "vibrateSpeed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Double))) |
Used in RotateCmd to specify the speed and direction of rotation of the motor at the given index
Rotate | |
|
Instances
Eq Rotate Source # | |
Show Rotate Source # | |
Generic Rotate Source # | |
FromJSON Rotate Source # | |
Defined in Buttplug.Core.Message parseJSON :: Value -> Parser Rotate parseJSONList :: Value -> Parser [Rotate] | |
ToJSON Rotate Source # | |
Defined in Buttplug.Core.Message toEncoding :: Rotate -> Encoding toJSONList :: [Rotate] -> Value toEncodingList :: [Rotate] -> Encoding | |
type Rep Rotate Source # | |
Defined in Buttplug.Core.Message type Rep Rotate = D1 ('MetaData "Rotate" "Buttplug.Core.Message" "buttplug-hs-core-0.1.0.0-inplace" 'False) (C1 ('MetaCons "Rotate" 'PrefixI 'True) (S1 ('MetaSel ('Just "rotateIndex") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word) :*: (S1 ('MetaSel ('Just "rotateSpeed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Double) :*: S1 ('MetaSel ('Just "rotateClockwise") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool)))) |
data LinearActuate Source #
Used in LinearCmd to specify how to move the linear actuator at the given index
Instances
Used for the Raw* messages.
Instances
Eq RawData Source # | |
Show RawData Source # | |
Generic RawData Source # | |
FromJSON RawData Source # | |
Defined in Buttplug.Core.Message parseJSON :: Value -> Parser RawData parseJSONList :: Value -> Parser [RawData] | |
ToJSON RawData Source # | |
Defined in Buttplug.Core.Message toEncoding :: RawData -> Encoding toJSONList :: [RawData] -> Value toEncodingList :: [RawData] -> Encoding | |
type Rep RawData Source # | |
Defined in Buttplug.Core.Message type Rep RawData = D1 ('MetaData "RawData" "Buttplug.Core.Message" "buttplug-hs-core-0.1.0.0-inplace" 'True) (C1 ('MetaCons "RawData" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ByteString))) |
Devices
data MessageAttributes Source #
For a particular actuation feature (Vibration, Rotation, or Linear), represents how many of that feature the device has, and the available resolution of control of that feature. See (https://buttplug-spec.docs.buttplug.io/enumeration.html#message-attributes-for-devicelist-and-deviceadded) for details.
Instances
An intimate device, containing info about the functionality it supports.
Instances
Eq Device Source # | |
Show Device Source # | |
Generic Device Source # | |
FromJSON Device Source # | |
Defined in Buttplug.Core.Device parseJSON :: Value -> Parser Device parseJSONList :: Value -> Parser [Device] | |
ToJSON Device Source # | |
Defined in Buttplug.Core.Device toEncoding :: Device -> Encoding toJSONList :: [Device] -> Value toEncodingList :: [Device] -> Encoding | |
type Rep Device Source # | |
Defined in Buttplug.Core.Device type Rep Device = D1 ('MetaData "Device" "Buttplug.Core.Device" "buttplug-hs-core-0.1.0.0-inplace" 'False) (C1 ('MetaCons "Device" 'PrefixI 'True) (S1 ('MetaSel ('Just "deviceName") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Text) :*: (S1 ('MetaSel ('Just "deviceIndex") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word) :*: S1 ('MetaSel ('Just "deviceMessages") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Map DeviceMessageType MessageAttributes))))) |
data DeviceMessageType Source #
Represents which message types the device supports See (https://buttplug-spec.docs.buttplug.io/enumeration.html#message-attributes-for-devicelist-and-deviceadded) for details.
DevRawWriteCmd | |
DevRawReadCmd | |
DevRawSubscribeCmd | |
DevRawUnsubscribeCmd | |
DevStopDeviceCmd | |
DevVibrateCmd | |
DevLinearCmd | |
DevRotateCmd |