└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Standard Solutions 2 | 3 | These solutions allow you to control users' Lovense toys by simple HTTPS request. 4 | 5 | If you want to integrate with your website or web app, we suggest you use our [Standard JS API](#standard-js-api). 6 | 7 | If you integrate a Standard Solution, your users must use Lovense Remote to pair their toys. 8 | Lovense Remote is available on Google Play and the App Store. 9 | 10 | # Contents 11 | 12 | 13 | 14 | 15 | - [Standard API](#standard-api) 16 | - [Configure the developer dashboard](#configure-the-developer-dashboard) 17 | - [Find your user toy](#find-your-user-toy) 18 | - [Command the toy](#command-the-toy) 19 | - [By local application](#by-local-application) 20 | - [GetToys Request](#gettoys-request) 21 | - [Function Request](#function-request) 22 | - [Pattern Request](#pattern-request) 23 | - [Preset Request](#preset-request) 24 | - [Error Codes](#error-codes) 25 | - [By server](#by-server) 26 | - [Function Request](#function-request) 27 | - [Pattern Request](#pattern-request) 28 | - [Preset Request](#preset-request) 29 | - [Server Error Codes](#server-error-codes) 30 | 31 | - [Standard JS API](#standard-js-api) 32 | - [Set your Callback URL](#set-your-callback-url) 33 | - [Import LAN.JS to your user page](#import-lanjs-to-your-user-page) 34 | - [Handle the callback data from Lovense Remote](#handle-the-callback-data-from-lovense-remote) 35 | - [Command the toy](#command-the-toy) 36 | - [Other methods](#other-methods) 37 | - [getToys](#gettoys) 38 | - [getOnlineToys](#getonlinetoys) 39 | - [isToyOnline](#istoyonline) 40 | - [openMobileRemote](#openmobileremote) 41 | 42 | 43 | 44 | 45 | # Standard API 46 | > This API allows any application to access its users Lovense toys from the developer side. 47 | 48 | ## Configure the developer dashboard 49 | Go to the developer dashboard at https://www.lovense.com/user/developer/info and set your Callback URL. 50 | 51 | ## Find your user toy 52 | - Copy your developer token from the Lovense developer dashboard. 53 | - Use a POST request to call Lovense server's API. 54 | - Javascript call example: 55 | ``` 56 | const result = await axios.post('https://api.lovense.com/api/lan/getQrCode', 57 | { 58 | token: 'your developer token', // Lovense developer token 59 | uid: '11111', // user ID on your website 60 | uname: 'user name', // user nickname on your website 61 | utoken: md5(uid + 'salt'), // This is for your own verification purposes. We suggest you to generate a unique token/secret for each user. This allows you to verify the user and avoid others faking the calls. 62 | v: 2 63 | } 64 | ) 65 | ``` 66 | - Java call example 67 | ``` 68 | String url= "https://api.lovense.com/api/lan/getQrCode"; 69 | Map requestParameter = new HashMap(); 70 | //TODO initialize your parameters: 71 | requestParameter.put("token", "{Lovense developer token}"); 72 | requestParameter.put("uid", "{user ID on your website}"); 73 | requestParameter.put("uname", "{user nickname on your website}"); 74 | requestParameter.put("utoken", "{Encrypted user token on your application. This is a security consideration, to avoid others stealing control of the toy.}"); 75 | requestParameter.put("v", 2); 76 | HttpPost httpPost = new HttpPost(url); 77 | List nameValuePairs = new ArrayList(); 78 | if (requestParameter != null && !requestParameter.isEmpty()) { 79 | Set keys = requestParameter.keySet(); 80 | for (String key : keys) { 81 | nameValuePairs.add(new BasicNameValuePair(key, requestParameter.get(key))); 82 | } 83 | } 84 | httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8")); 85 | ``` 86 | - You will receive a json response such as: 87 | ``` 88 | { 89 | code: 0 90 | message: "Success" 91 | result: true 92 | data: { 93 | "qr": "https://test2.lovense.com/UploadFiles/qr/20220106/xxx.jpg", // QR code picture 94 | "code": "xxxxxx" 95 | } 96 | } 97 | ``` 98 | 99 | - After the user scans the QR code with the Lovense Remote app, the app will invoke the Callback URL you've provided in the developer dashboard. The Lovense server is no longer required. All communications will go from the app to your server directly. 100 | The Lovense Remote app will post the following json to your server: 101 | ``` 102 | { 103 | "uid": "xxx", 104 | "appVersion": "4.0.3", 105 | "toys": { 106 | "xxxx": { 107 | "nickName": "", 108 | "name": "max", 109 | "id": "xxxx", 110 | "status": 1 111 | } 112 | }, 113 | "wssPort": "34568", 114 | "httpPort": "34567", 115 | "wsPort": "34567", 116 | "appType": "remote", 117 | "domain": "192-168-1-44.lovense.club", 118 | "utoken": "xxxxxx", 119 | "httpsPort": "34568", 120 | "version": "101", 121 | "platform": "android" 122 | } 123 | ``` 124 | 125 | 126 | ## Command the toy 127 | > Note: iOS Remote 5.1.4+, Android Remote 5.1.1+, or PC Remote 1.5.8+ is required. 128 | 129 | ### By local application 130 | If the user's device is in the same LAN environment, a POST request to Lovense Remote can trigger a toy response. In this case, your server and Lovense's server are not required. 131 | 132 | If the user uses the mobile version of Lovense Remote app, the `domain` and `httpsPort` are accessed from the callback information. If the user uses Lovense Remote for PC, the `domain` is `127-0-0-1.lovense.club` and the `httpsPort` is `30010` 133 | 134 | With the same command line, different parameters will lead to different results. Requests are as follows:
135 | 136 | | | | 137 | |---|----| 138 | |**API URL**| https://{domain}:{httpsPort}/command| 139 | |**Request protocol**| HTTPS Request| 140 | |**Method**| POST| 141 | |**Request Content Type**| application/json| 142 | |**Response Format**| JSON| 143 | 144 | #### GetToys Request 145 | 146 | **Parameters:*** 147 | | Name | Description | Type | Note | Required | 148 | | -------- | ----------------- | ------ | ------ | ---------- | 149 | | command | Type of request | String | / | yes | 150 | 151 | Request example: 152 | 153 | ``` 154 | { 155 | "command": "GetToys" 156 | } 157 | ``` 158 | Response example: 159 | ``` 160 | { 161 | "code": 200, 162 | "data": { 163 | "toys": "{ \"fc9f37e96593\" : { \"id\" : \"fc9f37e96593\", \"status\" : \"1\", \"version\" : \"\", \"name\" : \"nora\", \"battery\" : 100, \"nickName\" : \"\" }}", 164 | "platform": "ios", 165 | "appType": "remote" 166 | }, 167 | "type": "OK" 168 | } 169 | ``` 170 | #### Function Request 171 | 172 | **Parameters** 173 | | Name | Description | Type | Note | Required | 174 | |-------------------|:------------------------------|:---------:|:----------------------------------------------------|----------| 175 | | command | Type of request | String | / | yes | 176 | | action | Control the function and strength of the toy | String |Actions can be Vibrate, Rotate, Pump or Stop.
Use Stop to stop the toy’s response.
`Range: Vibrate:0 \~ 20`
`Rotate: 0 \~ 20`
`Pump:0 \~ 3` | yes | 177 | | timeSec | Total running time | double | 0 = indefinite length
Otherwise, running time should be greater than 1. | yes | 178 | |loopRunningSec | Running time | double | Should be greater than 1 | no | 179 | |loopPauseSec | Suspend time | double | Should be greater than 1 | no | 180 | |toy | Toy ID | string | Optional, if you don’t include this, it will be applied to all toys | no | 181 | |apiVer | The version of the request | int | Always use 1 | yes | 182 | 183 | 184 | Request example: 185 | ``` 186 | // Vibrate toy ff922f7fd345 at 16th strength, run 9 seconds then suspend 4 seconds. It will be looped. Total running time is 20 seconds. 187 | { 188 | "command": "Function", 189 | "action": "Vibrate:16", 190 | "timeSec": 20, 191 | "loopRunningSec": 9, 192 | "loopPauseSec": 4, 193 | "toy": "ff922f7fd345", 194 | "apiVer": 1 195 | } 196 | ``` 197 | ``` 198 | // Vibrate 9 seconds at 2nd strength 199 | // Rotate toys 9 seconds at 3rd strength 200 | // Pump all toys 9 seconds at 4th strength 201 | // For all toys, it will run 9 seconds then suspend 4 seconds. It will be looped. Total running time is 20 seconds. 202 | { 203 | "command": "Function", 204 | "action": "Vibrate:2,Rotate:3,Pump:4", 205 | "timeSec": 20, 206 | "loopRunningSec": 9, 207 | "loopPauseSec": 4, 208 | "apiVer": 1 209 | } 210 | ``` 211 | ``` 212 | // Stop all toys 213 | { 214 | "command": "Function", 215 | "action": "Stop", 216 | "timeSec": 0, 217 | "apiVer": 1 218 | } 219 | ``` 220 | #### Pattern Request 221 | 222 | **Parameters** 223 | 224 | 225 | |Name | Description| Type |Note | Required| 226 | |:--- |:-------------|:------------|:----|----------| 227 | |command| Type of request |String| / |yes| 228 | |rule |"V:1;F:vrp;S:1000#"
V:1; Protocol version, this is static;
F:vrp; Features: v is vibrate, r is rotate, p is pump,this should match the strength below;
S:1000; Intervals in Milliseconds, should be greater than 100. |string |The strength of r and p will automatically correspond to v.| yes| 229 | |strength| The pattern
For example: 20;20;5;20;10 |string| No more than 50 parameters. Use semicolon ; to separate every strength. |yes| 230 | |timeSec| Total running time| double| 0 = indefinite length
Otherwise, running time should be greater than 1. |yes| 231 | |toy| Toy ID |string |Optional, if you don’t include this, it will apply to all toys |no| 232 | |apiVer |The version of the request |int |Always use 1 |yes| 233 | 234 | 235 | Request example 236 | ``` 237 | // Vibrate the toy as defined. The interval between changes is 1 second. Total running time is 9 seconds. 238 | { 239 | "command": "Pattern", 240 | "rule": "V:1;F:v;S:1000#", 241 | "strength": "20;20;5;20;10", 242 | "timeSec": 9, 243 | "toy": "ff922f7fd345", 244 | "apiVer": 1 245 | } 246 | ``` 247 | ``` 248 | // Vibrate the toys as defined. The interval between changes is 0.1 second. Total running time is 9 seconds. 249 | // If the toys include Nora or Max, they will automatically rotate or pump, you don't need to define it. 250 | { 251 | "command": "Pattern", 252 | "rule": "V:1;F:vrp;S:100#", 253 | "strength": "20;20;5;20;10", 254 | "timeSec": 9, 255 | "apiVer": 1 256 | } 257 | ``` 258 | 259 | ### Preset Request 260 | 261 | **Parameters** 262 | 263 | |Name |Description| Type| Note| Required| 264 | |:------|:----------|:------|:------|-----------| 265 | |command |Type of request| String |/ |yes| 266 | |name |Preset pattern name |string |We provide four preset patterns in the Lovense Remote app: pulse, wave, fireworks, earthquake |yes| 267 | |timeSec |Total running time |double |0 = indefinite length
Otherwise, running time should be greater than 1. |yes| 268 | |toy| Toy ID |string |Optional, if you don’t include this, it will be applied to all toys |no| 269 | |apiVer |The version of the request |int| Always use 1 |yes| 270 | 271 | 272 | Request example 273 | 274 | ``` 275 | // Vibrate the toy with pulse pattern, the running time is 9 seconds. 276 | { 277 | "command": "Preset", 278 | "name": "pulse", 279 | "timeSec": 9, 280 | "toy": "ff922f7fd345", 281 | "apiVer": 1 282 | } 283 | ``` 284 | Response example 285 | 286 | ``` 287 | { 288 | "code": 200, 289 | "type": "ok" 290 | } 291 | ``` 292 | 293 | #### Error codes 294 | 295 | |Code | Message| 296 | |:------|:-------| 297 | |500| HTTP server not started or disabled| 298 | |400| Invalid Command| 299 | |401 |Toy Not Found| 300 | |402 |Toy Not Connected| 301 | |403 |Toy Doesn't Support This Command| 302 | |404 |Invalid Parameter| 303 | |506 |Server Error. Restart Lovense Connect| 304 | 305 | 306 | 307 | 308 | ### By server 309 | 310 | If your application can’t establish a LAN connection to the user’s Lovense Remote app, you can use the Server API to connect the user’s toy. 311 | 312 | > ⚠️ If you are using Lovense Remote for PC, you need to enter a code to establish connection. Use the code generated alongside the QR code in step 2 above. 313 | 314 | 315 | Requests are as follows:
316 | 317 | | | | 318 | |---|----| 319 | |**API URL**| https://{domain}:{httpsPort}/command| 320 | |**Request protocol**| HTTPS Request| 321 | |**Method**| POST| 322 | |**Request Content Type**| application/json| 323 | |**Response Format**| JSON| 324 | 325 | 326 | 327 | #### Function Request 328 | 329 | **Parameters:** 330 | 331 | |Name |Description |Type |Note |Required| 332 | |:------|:--------------|:------|:------|--------| 333 | |token |Your developer |token |string | yes| 334 | |uid |Your user’s ID |string |To send commands to multiple users at the same time, add all the user IDs separated by commas. The toy parameter below will be ignored and the commands will go to all user toys by default. |yes| 335 | |command| Type of request| String |/ |yes| 336 | |action |Control the function and strength of the toy |string |Actions can be Vibrate, Rotate, Pump or Stop. Use Stop to stop the toy’s response.
Range:
```Vibrate:0 ~ 20```
```Rotate: 0~20```
```Pump:0~3``` |yes| 337 | |timeSec |Total running time |double |0 = indefinite length
Otherwise, running time should be greater than 1. |yes| 338 | |loopRunningSec |Running time |double| Should be greater than 1 |no| 339 | |loopPauseSec| Suspend time |double| Should be greater than 1 |no| 340 | |toy |Toy ID| string |Optional, if you don’t include this, it will be applied to all toys |no| 341 | |stopPrevious |Stop all previous commands and execute current commands |int |Optional, Default: `1`, If set to `0` , it will not stop the previous command.| no| 342 | |apiVer |The version of the request |int |Always use 1 |yes| 343 | 344 | Request example 345 | 346 | ``` 347 | // Vibrate toy ff922f7fd345 at 16th strength, run 9 seconds then suspend 4 seconds. It will be looped. Total running time is 20 seconds. 348 | { 349 | "token": "FE1TxWpTciAl4E2QfYEfPLvo2jf8V6WJWkLJtzLqv/nB2AMos9XuWzgQNrbXSi6n", 350 | "uid": "1132fsdfsd", 351 | "command": "Function", 352 | "action": "Vibrate:16", 353 | "timeSec": 20, 354 | "loopRunningSec": 9, 355 | "loopPauseSec": 4, 356 | "apiVer": 1 357 | } 358 | ``` 359 | ``` 360 | // Vibrate 9 seconds at 2nd strength 361 | // Rotate toys 9 seconds at 3rd strength 362 | // Pump all toys 9 seconds at 4th strength 363 | // For all toys, it will run 9 seconds then suspend 4 seconds. It will be looped. Total running time is 20 seconds. 364 | { 365 | "token": "FE1TxWpTciAl4E2QfYEfPLvo2jf8V6WJWkLJtzLqv/nB2AMos9XuWzgQNrbXSi6n", 366 | "uid": "1132fsdfsd", 367 | "command": "Function", 368 | "action": "Vibrate:2,Rotate:3,Pump:4", 369 | "timeSec": 20, 370 | "loopRunningSec": 9, 371 | "loopPauseSec": 4, 372 | "apiVer": 1 373 | } 374 | ``` 375 | 376 | #### Pattern request 377 | 378 | If you want to change the way the toy responds very frequently you can use a pattern request. To avoid network pressure and obtain a stable response, use the commands below to send your predefined patterns at once. 379 | 380 | **Parameters:** 381 | 382 | |Name |Description |Type |Note |Required| 383 | |:------|:--------------|:------|:------|--------| 384 | |token |Your developer token |string | yes| 385 | |uid |Your user’s ID |string |yes| 386 | |command |Type of request |String| / |yes| 387 | |rule |"V:1;F:vrp;S:1000#"
V:1; Protocol version, this is static;
F:vrp; Features: v is vibrate, r is rotate, p is pump,this should match the strength below;
S:1000; Intervals in Milliseconds, should be greater than 100. |string |The strength of r and p will automatically correspond to v.| yes| 388 | |strength| The pattern
For example: 20;20;5;20;10 |string| No more than 50 parameters. Use semicolon `; `to separate every strength. |yes| 389 | |timeSec| Total running time| double| 0 = indefinite length
Otherwise, running time should be greater than 1. |yes| 390 | |toy| Toy ID |string |Optional, if you don’t include this, it will apply to all toys |no| 391 | |apiVer |The version of the request |int |Always use 1 |yes| 392 | 393 | Request example 394 | 395 | ``` 396 | // Vibrate the toy as defined. The interval between changes is 1 second. Total running time is 9 seconds. 397 | { 398 | "token": "FE1TxWpTciAl4E2QfYEfPLvo2jf8V6WJWkLJtzLqv/nB2AMos9XuWzgQNrbXSi6n", 399 | "uid": "1ads22adsf", 400 | "command": "Pattern", 401 | "rule": "V:1;F:v;S:1000#", 402 | "strength": "20;20;5;20;10", 403 | "timeSec": 9, 404 | "apiVer": 1 405 | } 406 | ``` 407 | ``` 408 | // Vibrate the toys as defined. The interval between changes is 0.1 second. Total running time is 9 seconds. 409 | // If the toys include Nora or Max, they will automatically rotate or pump, you don't need to define it. 410 | { 411 | "token": "FE1TxWpTciAl4E2QfYEfPLvo2jf8V6WJWkLJtzLqv/nB2AMos9XuWzgQNrbXSi6n", 412 | "uid": "1ads22adsf", 413 | "command": "Pattern", 414 | "rule": "V:1;F:vrp;S:100#", 415 | "strength": "20;20;5;20;10", 416 | "timeSec": 9, 417 | "apiVer": 1 418 | } 419 | ``` 420 | 421 | #### Preset request 422 | 423 | **Parameters:** 424 | 425 | |Name |Description |Type |Note |Required| 426 | |:------|:--------------|:------|:------|--------| 427 | |token |Your developer token |string | | |yes| 428 | |uid |Your user’s ID |string | ||yes| 429 | |command |Type of request |String |/ |yes| 430 | |name |Preset pattern name |string |We provide four preset patterns in the Lovense Remote app: pulse, wave, fireworks, earthquake| yes| 431 | |timeSec |Total running time |double |0 = indefinite length
Otherwise, running time should be greater than 1. |yes| 432 | |toy |Toy ID |string |Optional, if you don’t include this, it will be applied to all toys |no| 433 | |apiVer |The version of the request |int |Always use 1 |yes| 434 | 435 | Request example 436 | 437 | ``` 438 | // Vibrate the toy with pulse pattern, the running time is 9 seconds. 439 | { 440 | "token": "FE1TxWpTciAl4E2QfYEfPLvo2jf8V6WJWkLJtzLqv/nB2AMos9XuWzgQNrbXSi6n", 441 | "uid": "1adsf2323", 442 | "command": "Preset", 443 | "name": "pulse", 444 | "timeSec": 9, 445 | "apiVer": 1 446 | } 447 | ``` 448 | ``` 449 | { 450 | "result": true, 451 | "code": 200, 452 | "message": "Success" 453 | } 454 | ``` 455 | 456 | #### Server error codes 457 | 458 | |Code |Message| 459 | |:------|:------| 460 | |200 |Success| 461 | |400 |Invalid command| 462 | |404 |Invalid Parameter| 463 | |501 |Invalid token| 464 | |502 |You do not have permission to use this API| 465 | |503 |Invalid User ID| 466 | |507 |Lovense APP is offline| 467 | 468 | 469 | 470 | #Standard JS API 471 | 472 | 473 | # Standard JS API 474 | 475 | This solution allows you to control Lovense toys through your webpage. 476 | 477 | Your users must use the Lovense Remote mobile app. 478 | 479 | >⚠️ iOS Remote v5.2.5+ or Android Remote v5.2.1+ is required. 480 | 481 | >⚠️ The user's devices must be in the same LAN. 482 | 483 | ## Set your Callback URL 484 | Go to the developer dashboard at https://www.lovense.com/user/developer/info and set your Callback URL. 485 | 486 | ## Import LAN.JS to your user page 487 | Add the LAN.JS to your user's page: 488 | ``` 489 | 490 | ``` 491 | 492 | ## Handle the callback data from Lovense Remote 493 | You can listen to the callback from Lovense Remote as below: 494 | ``` 495 | // the path should be the same as you set in the Lovense developer dashboard 496 | @RequestMapping(value = "/api/lovense/callback") 497 | public @ResponseBody 498 | MessageResponse callback(@RequestBody Map body) { 499 | //TODO 500 | //send the callback data to the user's page and call `lovense.setConnectCallbackData` there 501 | return new MessageResponse(true, "success"); 502 | } 503 | ``` 504 | Call `lovense.setConnectCallbackData` to set when you receive the callback data from Lovense Remote. 505 | ``` 506 | lovense.setConnectCallbackData(callbackData) 507 | ``` 508 | >⚠️ If the user uses Lovense Connect for PC, this step can be skipped because a QR code is not required. 509 | 510 | ## Command the toy(s) 511 | Send commands/vibrations to Lovense toy(s) by calling `lovense.sendCommand(parameters)`. 512 | 513 | For the parameters list, see [Command the toy(s)](https://developer.lovense.com/#step-3-command-the-toy-s-1) 514 | 515 | Example: 516 | ``` 517 | lovense.sendCommand({ 518 | command: "Function", 519 | action: "Vibrate:16", 520 | timeSec: 20, 521 | loopRunningSec: 9, 522 | loopPauseSec: 4, 523 | toy: "ff922f7fd345", 524 | apiVer: 1, 525 | }) 526 | ``` 527 | 528 | ## Other methods 529 | 530 | ### getToys 531 | Get all toys, it will return all toys as an array 532 | 533 | ```lovense.getToys()``` 534 | 535 | ### getOnlineToys 536 | Get all online toys, it will only return the connected toys as an array 537 | 538 | ```lovense.getOnlineToys()``` 539 | 540 | ### isToyOnline 541 | Determine whether the toy is connected, it will return true as long as there is a toy connected. 542 | 543 | ```lovense.isToyOnline()``` 544 | 545 | ### openMobileRemote 546 | Open Lovense Mobile Remote. 547 | 548 | ```lovense.openMobileRemote()``` 549 | 550 | 551 | GIVE FEEDBACK 552 | ------------- 553 | Please report bugs or issues to [Lovense Support](mailto:developer@mail.lovense.com). 554 | 555 | You can also join our [Lovense Developer Community Discord](https://discord.gg/dW9f54BwqR), visit the [Lovense Developers Website](https://developer.lovense.com/#introduction), or open an issue in this repository. 556 | --------------------------------------------------------------------------------