SDK Reference

The reference documentation for the Handy SDK.

The Handy SDK is a JavaScript library and a collection of examples to get you started with developing apps for the Handy. The SDK is built on top of Handy API 2.0 and intended for Handys with Firmware 3.

Documentation of usage and the library methods can be found below. You can also find an interactive version of the API 2.0 documentation here.

Installation

From NPM

To install the latest release:

npm i @ohdoki/handy-sdk

To install a specific version:

npm install @ohdoki/handy-sdk@version

Usage:

import * as Handy from '@ohdoki/handy-sdk';
const HANDY = Handy.init();

From a CDN

You can also include the client bundle from a CDN:

<script src="https://unpkg.com/@ohdoki/handy-sdk"></script>
<script>
  const HANDY = Handy.init();
</script>

Handy Configuration

The Handy object constructor can be provided with a number of parameters to simplify your integration.

API

Default value: https://www.handyfeeling.com/api/handy/v2

The URL of the API being used. Default value is the production API.

A staging API is also available at: https://staging.handyfeeling.com/api/handy/v2

scriptAPI

Default value: https://scripts01.handyfeeling.com/api/script/v0

The URL for the Handy Script API. The Script API is used to upload scripts to the Handy script server and retrieve them at a later time for synchronization.

For more details, read the Handy Script API docs.

UUI

The URL of the Handy UI interface.

Default value: { URL: 'https://universalui.handyfeeling.com', theme: 'default', compact: false, }

  • URL <string> – URL of universal UI instance
  • theme <'default' | 'dark'> – Theme of the universal UI
  • compact boolean – Whether Handy universal UI should use a compact layout

videoPlayerId

Default value: None

The element ID of the <video> element. If set, play and pause event listeners will be added to that <video> element so that a connected Handy will start and stop along with the video.

<script src="https://unpkg.com/@ohdoki/handy-sdk"></script>
<video id="video"></video>
<script>
  const HANDY = Handy.init({ videoPlayerId: 'video' });
</script>

syncClientServerTime

Default value: true

Determines whether to recalculate round-trip delay (RTD) and offset between client and server upon Handy connection.

syncClient

Default value: { syncCount: 30, outliers: 10 }

Settings for the baseline delay calculation between the client and the Handy server used for Handy video synchronization. On initial connection, the client will ping the server 30 times (by default), discard the 10 highest latencies, and use the average of the remaining values as a delay for the video element.

  • syncCount <number> — The number of round-trip samples to take in synchronization calculation
  • outliers <number> — The number of sample outliers to discard from the syncCount set

syncHandy

Default value: { syncCount: 30, outliers: 10 }

Settings for the baseline delay calculation between the Handy and the Handy server used for Handy video synchronization. On initial connection, the Handy will ping the server 30 times (by default), discard the 10 highest latencies, and use the average of the remaining values as a delay for the video element.

  • syncCount <number> – The number of round-trip samples to take in synchronization
  • outliers <number> – The number of sample outliers to discard from the syncCount set

videoPlayerDelayForSecondPlay

Default value: 2500 (ms)

Delay (in milliseconds) before the second play event after an initial play event to adjust for video player issues.

timeBetweenSyncs

Default value: 3600000 (1 hour in ms)

Minimum time (in milliseconds) before a client-server round-trip delay and offset recalculation is triggered.

timeBetweenAllInfoUpdates

Default value: 60000 (10 minutes in ms)

Minimum time (in milliseconds) before a full status update is triggered.

throttleDelay

Default value: 200 (ms)

Minimum time between asynchronous methods call.

Available methods

connect

handy.connect(connectionKey)

Connects the Handy to the Handy servers. Must be done to enable communication with the Handy.

Params
  • connectionKey <string>
Returns

disconnect

handy.disconnect([all])

Disconnects the Handy from the Handy servers.

If all is true, the states of all previously connected Handys saved in local storage are removed. If all is false, only the state of the currently connected Handy is removed. Defaults to true.

Params
  • all <boolean>
Returns
  • <Promise>

getStoredKey

handy.getStoredKey()

Returns the connection key of the last connected Handy from the local storage.

Returns
  • <string | undefined>

on

handy.on(event, handler)

Sets up a function that will be called whenever an event of the specified type occurs.

Params
<script src="https://unpkg.com/@ohdoki/handy-sdk"></script>
<script>
  const HANDY = Handy.init();

  HANDY.on('state', ({ state, change }) => {
    console.log(state, change);
  });
</script>

off

handy.off(event, handler)

Removes the listener registered with the handy.on() method.

Params

attachUUI

handy.attachUUI([uuiId])

Attaches Handy UI to the element with the provided ID.

Params
  • uuiId <string> (Default handy-ui)

toggleUUI

handy.toggleUUI([open])

Opens/closes the Handy universal UI.

Params
  • open <boolean> (Default true)

getClientServerLatency

handy.getClientServerLatency()

Returns average offset and RTD between client and server.

Returns <Object>
  • avgOffset <number>
  • avgRtd <number>
  • lastSyncTime <number>

setVideoPlayer

handy.setVideoPlayer([videoPlayer])

Adds play and pause event listeners to the selected element to start or stop the Handy based on the play/pause status of the video player. Play and pause events will throw errors if a script has not been set. Overwrites all previously set listeners.

Params
  • videoPlayer <HTMLVideoElement>

setMode

handy.setMode(mode)

Sets the current mode of the Handy. Available Handy modes include:

  • 0 - HAMP
  • 1 - HSSP
  • 2 - HDSP
  • 3 - MAINTENANCE
Params
Returns <Promise>

getMode

handy.getMode()

Gets the current mode of the Handy.

Returns <Promise>

syncClientServerTime

handy.syncClientServerTime([settings])

Calculates RTD and offset between client and server.

Params
Returns <Promise>

syncHandyServerTime

handy.syncHandyServerTime([settings])

Calculates RTD and offset between Handy and server.

Params
Returns <Promise>

sync

handy.sync([clientSettings, handySettings])

Calculates RTD and offset between both client and server and Handy and server.

Params
Returns <Promise>

getHandyRtd

handy.getHandyRtd()

Gets the round-trip-delay-time (rtd) between the device and the server. The rtd is calculated when the synchronization of the server and device time is triggered.

Returns <Promise>

setOffset

handy.setOffset(offset)

Sets the HSTP offset of the device. The purpose of the offset is to provide a way to manually adjust the device/server clock synchronization.

Params
  • offset <number>
Returns <Promise>

getOffset

handy.getOffset()

Gets the HSTP offset of the device. The purpose of the offset value is to provide a way to manually adjust the device/server clock synchronization.

Returns <Promise>

setStrokeZone

handy.setStrokeZone(slide)

Sets the minimum and maximum position of the Handy stroker. The slide minimum and maximum positions decide the range of the movement of the Handy stroker arm. You can update the minimum and maximum individually or set both values at the same time.

The fixed flag can be set to move the current min-max-range relative to a new min or max value. If fixed is true, the current min-max-range will be shifted relative to the new value.

The fixed flag can be used to maintain the minimum value while changing the maximum value, or vice versa.

Params
Returns <Promise>
SlideSettings
{
  min: PercentValue;
  max: PercentValue;
}

OR

{
  min: PercentValue;
  fixed?: boolean;
}

OR

{
  max: PercentValue;
  fixed?: boolean;
}

getStrokeZone

handy.getStrokeZone()

Gets the minimum and maximum positions of the Handy stroke zone.

Returns <Promise>

getAbsolutePosition

handy.getAbsolutePosition()

Gets the current stroker position in millimeters (mm). The Handy stroker ranges from 0 mm (at the bottom) to 110 mm (at the top).

Returns <Promise>

hampPlay

handy.hampPlay()

Starts alternating motion. No effect if the device is already moving.

Handy must be set to mode 2 (HAMP) for this method to work.

Returns <Promise>

hampStop

handy.hampStop()

Stops alternating motion. No effect if the device is already stopped.

Handy must be set to mode 2 (HAMP) for this method to work.

Returns <Promise>

setHampVelocity

handy.setHampVelocity(velocity)

Sets the velocity of the alternating motion as a percent value.

Note: The velocity can only be set when HAMP mode is enabled (mode=2) and when the stroker is moving (HAMP state=2). Attempting to set the velocity outside of this mode and state will result in an error response.

Params
Returns <Promise>

getHampVelocity

handy.getHampVelocity()

Gets the HAMP velocity setting of the Handy as a percent value.

Returns <Promise>

setScript

handy.setScript(scriptUrl)

Prepares Handy for video sync by providing the device with an URL from where the script can be downloaded. This method will set your Handy to HSSP mode (mode 1) if is not already in that mode.

Params
  • scriptUrl <string>
Returns <Promise>

setScriptFromData

handy.setScriptFromData(script)

Uploads script to the Handy script server and prepares Handy for video sync by providing the device with a URL from where the script can be downloaded. This method will set your Handy to HSSP mode (mode 1) if is not already in that mode.

Params
  • script <Funscript | string>
Returns <Promise>

hsspPlay

handy.hsspPlay([startTime, estimatedServerTime])

Starts script playback from a specified time index.

For the script and a video to be correctly synchronized, the client must provide a client-side estimated server time value. This can be achieved by calling the getEstimatedServerTime() method.

Params
Returns <Promise>

hsspStop

handy.hsspStop()

Stops script playback.

Returns <Promise>

setHsspLoop

handy.setHsspLoop([loop])

Sets the HSSP loop setting of the device. If looping is enabled, the device will play the script again from the beginning when the end of the script is reached.

Params
  • loop <boolean> (Default true)
Returns <Promise>

getHsspLoop

handy.getHsspLoop()

Gets the HSSP loop setting of the device.

Returns <Promise>

hdsp

handy.hdsp(position, speed, positionType, speedType, stopOnTarget)

Sets the next absolute/percent position of the device, and the time/absolute velocity/percent velocity the device should use to reach the position.

Handy must be set to mode 2 (HDSP) for this method to work.

  • position <number>
  • speed <number>
  • positionType <'absolute' | 'percent'>
  • speedType <'time' | 'absolute' | 'percent'>
  • stopOnTarget <boolean>
Returns <Promise>

uploadDataToServer

Handy.uploadDataToServer(script[, scriptAPI])

Uploads script to the Handy script server and returns a URL. This URL can then be passed to the Handy for playback.

  • script <Funscript | string>
  • scriptAPI <string> (Default scriptAPI config default value)
Returns <Promise<string>>

isValidCSV

Handy.isValidCSV(data)

Checks if the input string is a valid CSV file.

Params
  • data <string>
Returns <boolean>

convertDataToCSV

Handy.convertFunscriptToCSV(funscript[, lineTerminator])

Converts script input file to a CSV file.

Params
  • script <Funscript | string>
  • lineTerminator <string> (Default \n)
Returns <string>

getEstimatedServerTime

Handy.getEstimatedServerTime()

Gets an estimated server time.

Returns <number>

API 2.0 methods

You can directly access all available API 2.0 methods by accessing the API object in the following way:

import * as Handy from '@ohdoki/handy-sdk';

const HANDY = Handy.init();
const getModeResponse = await HANDY.API.get.mode(connectionKey);

Types

GenericResult

  • -1 - ERROR
  • 0 - SUCCESS

GenericAndNotChangedResult

  • -1 - ERROR
  • 0 - SUCCESS
  • 1 - NOT_CHANGED

Mode

  • 0 - HAMP
  • 1 - HSSP
  • 2 - HDSP
  • 3 - MAINTENANCE

ConnectResult

  • 0 - NOT_CONNECTED
  • 1 - CONNECTED
  • 2 - UPDATE_REQUIRED

Events

Event: state — triggered on state update Event: connect — triggered on Handy connect Event: disconnect — triggered on Handy disconnect

Data: <Object>

  • state <HandyState> — new state of the Handy
  • change <Partial<HandyState>> — change in the state

ModeUpdateResult

  • -1 - ERROR
  • 0 - SUCCESS_NEW_MODE
  • 1 - SUCCESS_SAME_MODE

StateResult

  • -1 - ERROR
  • 0 - SUCCESS_NEW_STATE
  • 1 - SUCCESS_SAME_STATE

HSSPSetupResult

  • 0 - USING_CACHED
  • 1 - DOWNLOADED

HSSPPlayAndNotChangedResult

  • -1 - ERROR
  • 0 - SUCCESS
  • 1 - NOT_CHANGED

HDSPResult

  • -3 - ERROR
  • 0 - SUCCESS_POSITION_REACHED
  • 1 - SUCCESS_POSITION_NOT_REACHED
  • 2 - SUCCESS_ALREADY_AT_POSITION
  • 3 - SUCCESS_INTERRTUPTED

PercentValue

  • type: double
  • minimum: 100
  • maximum: 0
  • example: 10.5

SyncSettings

{
  syncCount?: number;
  outliers?: number;
}

SlideSettings

{
  min: PercentValue;
  max: PercentValue;
}

OR

{
  min: PercentValue;
  fixed?: boolean;
}

OR

{
  max: PercentValue;
  fixed?: boolean;
}

Development

  1. Run npm run dev. This will start a watcher that will rebuild code automatically on any file change.
  2. Link file from /dist/handy.umd.js wherever you need it.

License

MIT