LinearCmd Client Device method should throw if pos is outside [0, 1]
Describe the bug
- Using buttplug-js v3.1.1 with Intiface Central v2.3.0 and a device configuration with a Linear axis.
- Seeing following error in Intiface Central logs upon sending a LinearCmd via
await device.linear(pos); - No errors reported on the
buttplug-jsclient side when sending.
[E] Global Loggy: Got invalid messages from remote Buttplug connection
- Message: Text("[{\"LinearCmd\":{\"Id\":312,\"DeviceIndex\":0,\"Vectors\":[{\"Index\":0,\"Position\":28}]}}]")
- Error: JsonSerializerError("Error during JSON Schema Validation
- Message: [{\"LinearCmd\":{\"DeviceIndex\":0,\"Id\":312,\"Vectors\":[{\"Index\":0,\"Position\":28}]}}]
- Error: [ValidationError { instance: Array [Object {\"LinearCmd\": Object {\"DeviceIndex\": Number(0), \"Id\": Number(312), \"Vectors\": Array [Object {\"Index\": Number(0), \"Position\": Number(28)}]}}], kind: AnyOf, instance_path: JSONPointer([]), schema_path: JSONPointer([Keyword(\"anyOf\")]) }]")
Should this be reported within the https://github.com/intiface/intiface-central project instead?
Nope that's a buttplug-js bug. We're not encoding position as a 0.0 < x < 1.0 double here.
@mnh86 Ok, taking a look at this again:
Are you sending 28 as the position? Because we expect 0.0 <= x <= 1.0 for position. You'd need to calculate that yourself. If this is for funscript, is assumes 0 <= x <= 100 I think, so you'd want to send 0.28.
That said, I should still at least check and throw if invalid values are sent, so I'll keep this bug open but change the deliverable for it.
After seeing your first comment I did try with the following change, but was still seeing errors in the intiface logs:
async sendToDevice(pos: number) {
console.log(`[buttplug] Action pos: ${pos}`);
// TODO: Possible workaround for https://github.com/buttplugio/buttplug-js/issues/248
// Note: Did not seem to work
let p = pos / 100;
if (p <= 0) {
p = 0.001;
} else if (p >= 1) {
p = 0.999;
}
for (const device of this._client.devices) {
try {
await device.linear(p);
} catch (e) {
// TODO: Cleanup. Workaround for https://github.com/buttplugio/buttplug-js/issues/247
if (!(e instanceof ButtplugDeviceError)) {
throw e;
}
}
}
}
Logs
[E] Global Loggy: Got invalid messages from remote Buttplug connection - Message: Text("[{\"LinearCmd\":{\"Id\":28,\"DeviceIndex\":0,\"Vectors\":[{\"Index\":0,\"Position\":0.73}]}}]") - Error: JsonSerializerError("Error during JSON Schema Validation - Message: [{\"LinearCmd\":{\"DeviceIndex\":0,\"Id\":28,\"Vectors\":[{\"Index\":0,\"Position\":0.73}]}}] - Error: [ValidationError { instance: Array [Object {\"LinearCmd\": Object {\"DeviceIndex\": Number(0), \"Id\": Number(28), \"Vectors\": Array [Object {\"Index\": Number(0), \"Position\": Number(0.73)}]}}], kind: AnyOf, instance_path: JSONPointer([]), schema_path: JSONPointer([Keyword(\"anyOf\")]) }]")
[E] Global Loggy: Got invalid messages from remote Buttplug connection - Message: Text("[{\"LinearCmd\":{\"Id\":29,\"DeviceIndex\":0,\"Vectors\":[{\"Index\":0,\"Position\":0.74}]}}]") - Error: JsonSerializerError("Error during JSON Schema Validation - Message: [{\"LinearCmd\":{\"DeviceIndex\":0,\"Id\":29,\"Vectors\":[{\"Index\":0,\"Position\":0.74}]}}] - Error: [ValidationError { instance: Array [Object {\"LinearCmd\": Object {\"DeviceIndex\": Number(0), \"Id\": Number(29), \"Vectors\": Array [Object {\"Index\": Number(0), \"Position\": Number(0.74)}]}}], kind: AnyOf, instance_path: JSONPointer([]), schema_path: JSONPointer([Keyword(\"anyOf\")]) }]")
[E] Global Loggy: Got invalid messages from remote Buttplug connection - Message: Text("[{\"LinearCmd\":{\"Id\":30,\"DeviceIndex\":0,\"Vectors\":[{\"Index\":0,\"Position\":0.75}]}}]") - Error: JsonSerializerError("Error during JSON Schema Validation - Message: [{\"LinearCmd\":{\"DeviceIndex\":0,\"Id\":30,\"Vectors\":[{\"Index\":0,\"Position\":0.75}]}}] - Error: [ValidationError { instance: Array [Object {\"LinearCmd\": Object {\"DeviceIndex\": Number(0), \"Id\": Number(30), \"Vectors\": Array [Object {\"Index\": Number(0), \"Position\": Number(0.75)}]}}], kind: AnyOf, instance_path: JSONPointer([]), schema_path: JSONPointer([Keyword(\"anyOf\")]) }]")
@mnh86 Oh I see what the issue is there. You aren't putting a move duration in, and the system isn't throwing when you miss the argument. God I hate js.
https://buttplugio.github.io/buttplug-js/classes/ButtplugClientDevice.html#linear
So the signature here is incorrect, it should be device.linear(values: [number, number]) (position, duration in ms) or or device.linear(number, number). If you're only sending one linear command (we currently have no devices that accept multiple linear commands). I'll add the check for this and fix the type signature though.
I'm also about to overhaul the command API to make this way easier to deal with, the current command signatures are gross.
@mnh86 Oh I see what the issue is there. You aren't putting a move duration in, and the system isn't throwing when you miss the argument. God I hate js.
Ah OK, got it. Thanks for finding that. I'll give that a try with the device.linear(p, 0) syntax soon, in the next few days.
Please do not move with linear duration 0. Either things will not work or it will move as fast as possible and in some cases can cause the device to break itself (these things are not well designed).
Ah, my current implementation was doing its own interpolation values between keyframes on a frequency. Sounds like buttplug can handle the interpolations itself, I just have to send the keyframes and duration. Will try that out, thanks. It will also help cut down on number of messages being sent over websockets and be more smooth for the device/user.
@mnh86 Depends on the toy. Some of them we handle interp for (kiiroo), some of them do it internally (handy). That said, almost none of them (outside of the OSR-2/SR-6, which are directly connected and DIY so user numbers are tiny), can handle a stream of realtime updates. They all mostly expect sparse updates (a few per second, max, esp because you're limited by bluetooth's unknown update rate).