Buttplug
Not a toy. A way of driving everybody else's.
Outlet and Milker are ours down to the solder. This one is not. There are hundreds of consumer toys out there, each with its own radio protocol, and Intiface already speaks all of them. So the radios are somebody else's problem, and this is the thing that puts a shop-bought vibrator on the same timeline as a mains relay and a stroking machine.
Somnus ──► this ──websocket──► Intiface ──BLE──► whatever you own
Source on git.somnus.engineering
Read this part before you trust it
Everything else here has a deadman in the firmware. Pull the cable on Outlet and the relay opens because the relay opens. Nothing in any program gets a say.
There is no firmware deadman under this one. The toy stops when the server decides the client is gone, and that is the end of the guarantee.
Locally that is usually fine. Kill the process, panic it, SIGKILL it in the
middle of holding a toy at full power, and the kernel shuts the socket, the
server sees a dead client, and everything stops. That case is tested by actually
doing it rather than by hoping.
Over a network it is a different story. Yank the power on the host, or lose the link, and nothing stops until the server's ping watchdog fires. And that watchdog is off by default. A server with no ping time set will happily keep a toy running until TCP gives up, which is minutes.
So set one. --max-ping-time 1000. The client tells you when there isn't one,
in the CLI and in its health, because a missing watchdog is not a detail to
discover afterwards:
$ somnus-buttplug list
connected to Intiface Server, 2 device(s), no ping watchdog
Where the server does want pings, this one sends them four times as often as it strictly has to. Three dropped in a row still will not drop a running session.
Half power means half power
Every toy has its own idea of resolution. One motor's speeds run 0 to 20. Another's run 0 to 100. A cue that says half has to mean the same thing on both or it means nothing at all.
So the currency is a fraction, and the scaling into whatever integers a particular motor accepts happens underneath. Rounded, not truncated. Truncate and a fader dragged all the way to the top lands on 19 out of 20 and never quite gets there. Somebody would notice.
Zero means stop. On a toy that rotates both ways it would be arithmetically tidy to have the bottom of the range mean full reverse, and it is not going to work that way here.
A number is not a name
Worth understanding before you trust a session to it.
The protocol calls toys by a small integer, and the spec is blunt about what that integer is worth: a server may hand a departed toy's number to the next thing that connects. It is a slot. It is not an identity.
A show that remembered the number would, after an unlucky reconnect, drive whatever is sitting in that slot now, and you would not get an error, because the wrong toy responds perfectly.
So toys are addressed by a name-derived ID and the numbers get looked up fresh underneath. Two consequences, and no amount of cleverness here fixes either:
Two identical toys with no display name cannot be told apart. No serial number reaches a client. Go into Intiface and give each one a name. Then the ID is something a person chose instead of an accident of what connected first.
A toy that has left is refused, never guessed at. Switch one off mid-session and cues naming it fail and, more to the point, send nothing. Firing blind into its old slot is not a harmless no-op. Switch it back on and the same handle picks it up again, so a session survives a toy whose battery gave out.
Same rule everywhere on this rig: a named device that is not attached is an error. It is never quietly swapped for whatever else happens to be plugged in.
It refuses old servers
The client speaks message spec v4 and will not pretend otherwise. Point it at something older and it says so, and says what to install, rather than half-connecting and failing later in a way nobody can read.
That is the spec's own rule, not a shortcut. A newer server can talk down to an older client. It does not work in the other direction.
What it will not do
It will not reconnect on its own. Server goes away, session is over, and restarting is a decision a person makes. Quietly picking up again mid-session and resuming whatever was running is not obviously the right thing to do to somebody. Milker takes the same view about arming.
It will not talk to a toy directly. The raw read and write messages exist for reverse-engineering hardware. That is Intiface's job. Nothing here needs to be poking at unknown firmware.