homebridge-tuya-plus 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  2. package/.github/ISSUE_TEMPLATE/new-device.md +24 -0
  3. package/.github/workflows/codeql-analysis.yml +67 -0
  4. package/.github/workflows/lint.yml +23 -0
  5. package/Changelog.md +63 -0
  6. package/LICENSE +21 -0
  7. package/Readme.MD +106 -0
  8. package/assets/Tuya-Plugin-Branding.png +0 -0
  9. package/bin/cli-decode.js +197 -0
  10. package/bin/cli-find.js +207 -0
  11. package/bin/cli.js +13 -0
  12. package/config-example.MD +43 -0
  13. package/config.schema.json +538 -0
  14. package/eslint.config.mjs +15 -0
  15. package/index.js +242 -0
  16. package/lib/AirConditionerAccessory.js +445 -0
  17. package/lib/AirPurifierAccessory.js +532 -0
  18. package/lib/BaseAccessory.js +290 -0
  19. package/lib/ConvectorAccessory.js +313 -0
  20. package/lib/CustomMultiOutletAccessory.js +111 -0
  21. package/lib/DehumidifierAccessory.js +301 -0
  22. package/lib/DoorbellAccessory.js +208 -0
  23. package/lib/EnergyCharacteristics.js +86 -0
  24. package/lib/GarageDoorAccessory.js +307 -0
  25. package/lib/MultiOutletAccessory.js +106 -0
  26. package/lib/OilDiffuserAccessory.js +480 -0
  27. package/lib/OutletAccessory.js +83 -0
  28. package/lib/RGBTWLightAccessory.js +234 -0
  29. package/lib/RGBTWOutletAccessory.js +296 -0
  30. package/lib/SimpleBlindsAccessory.js +299 -0
  31. package/lib/SimpleDimmer2Accessory.js +54 -0
  32. package/lib/SimpleDimmerAccessory.js +54 -0
  33. package/lib/SimpleFanAccessory.js +137 -0
  34. package/lib/SimpleFanLightAccessory.js +201 -0
  35. package/lib/SimpleHeaterAccessory.js +154 -0
  36. package/lib/SimpleLightAccessory.js +39 -0
  37. package/lib/SwitchAccessory.js +106 -0
  38. package/lib/TWLightAccessory.js +91 -0
  39. package/lib/TuyaAccessory.js +746 -0
  40. package/lib/TuyaDiscovery.js +165 -0
  41. package/lib/ValveAccessory.js +150 -0
  42. package/package.json +49 -0
@@ -0,0 +1,538 @@
1
+ {
2
+ "pluginAlias": "TuyaLan",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "headerDisplay": "<p align='center'><img height='60px' src='https://user-images.githubusercontent.com/3979615/78354049-dc7ff780-75f6-11ea-8026-2f8bf81d8331.png'></p>\n\nBefore using the Tuya plugin you need to discover your devices by following [these instructions](https://github.com/AMoo-Miki/homebridge-tuya-lan/wiki/Setup-Instructions).\n\n",
6
+ "footerDisplay": "",
7
+ "schema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "devices": {
11
+ "type": "array",
12
+ "orderable": false,
13
+ "items": {
14
+ "type": "object",
15
+ "properties": {
16
+ "type": {
17
+ "type": "string",
18
+ "required": true,
19
+ "default": "null",
20
+ "oneOf": [
21
+ {
22
+ "title": "Please select device type...",
23
+ "enum": [
24
+ "null"
25
+ ]
26
+ },
27
+ {
28
+ "title": "Smart Plug / Barely Smart Power Strip",
29
+ "enum": [
30
+ "Outlet"
31
+ ]
32
+ },
33
+ {
34
+ "title": "Simple Light Bulb / Socket",
35
+ "enum": [
36
+ "SimpleLight"
37
+ ]
38
+ },
39
+ {
40
+ "title": "Tunable White Light Bulb",
41
+ "enum": [
42
+ "TWLight"
43
+ ]
44
+ },
45
+ {
46
+ "title": "White and Color Light Bulb",
47
+ "enum": [
48
+ "RGBTWLight"
49
+ ]
50
+ },
51
+ {
52
+ "title": "Smart Power Strip",
53
+ "enum": [
54
+ "MultiOutlet"
55
+ ]
56
+ },
57
+ {
58
+ "title": "Non-sequential Power Strip",
59
+ "enum": [
60
+ "CustomMultiOutlet"
61
+ ]
62
+ },
63
+ {
64
+ "title": "Air Conditioner",
65
+ "enum": [
66
+ "AirConditioner"
67
+ ]
68
+ },
69
+ {
70
+ "title": "Heat Convector",
71
+ "enum": [
72
+ "Convector"
73
+ ]
74
+ },
75
+ {
76
+ "title": "Simple Dimmer",
77
+ "enum": [
78
+ "SimpleDimmer"
79
+ ]
80
+ },
81
+ {
82
+ "title": "Simple Heater",
83
+ "enum": [
84
+ "SimpleHeater"
85
+ ]
86
+ },
87
+ {
88
+ "title": "Garage Door",
89
+ "enum": [
90
+ "GarageDoor"
91
+ ]
92
+ },
93
+ {
94
+ "title": "Simple Blinds",
95
+ "enum": [
96
+ "SimpleBlinds"
97
+ ]
98
+ },
99
+ {
100
+ "title": "Smart Plug w/ White and Color Lights",
101
+ "enum": [
102
+ "RGBTWOutlet"
103
+ ]
104
+ },
105
+ {
106
+ "title": "Simple Fan",
107
+ "enum": [
108
+ "Fan"
109
+ ]
110
+ },
111
+ {
112
+ "title": "Simple Fan Light",
113
+ "enum": [
114
+ "FanLight"
115
+ ]
116
+ },
117
+ {
118
+ "title": "Air Purifier",
119
+ "enum": [
120
+ "AirPurifier"
121
+ ]
122
+ }
123
+ ]
124
+ },
125
+ "name": {
126
+ "type": "string",
127
+ "description": "Anything you'd like to use to identify this device. You can always change the name from within the Home app later.",
128
+ "required": true,
129
+ "condition": {
130
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
131
+ }
132
+ },
133
+ "id": {
134
+ "type": "string",
135
+ "title": "Tuya ID",
136
+ "description": "If you don't have the Tuya ID or Key, follow the steps found on the <a href='https://github.com/AMoo-Miki/homebridge-tuya-lan/wiki/Setup-Instructions' target='_blank'>Setup Instructions</a> page.",
137
+ "required": true,
138
+ "condition": {
139
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
140
+ }
141
+ },
142
+ "key": {
143
+ "title": "Tuya Key",
144
+ "type": "string",
145
+ "required": true,
146
+ "condition": {
147
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
148
+ }
149
+ },
150
+ "ip": {
151
+ "title": "IP Address",
152
+ "type": "string",
153
+ "required": false,
154
+ "condition": {
155
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
156
+ }
157
+ },
158
+ "manufacturer": {
159
+ "type": "string",
160
+ "description": "Anything you'd like to use to help identify this device.",
161
+ "condition": {
162
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
163
+ }
164
+ },
165
+ "model": {
166
+ "type": "string",
167
+ "description": "Anything you'd like to use to help identify this device.",
168
+ "condition": {
169
+ "functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
170
+ }
171
+ },
172
+ "voltsId": {
173
+ "type": "integer",
174
+ "placeholder": "9",
175
+ "condition": {
176
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
177
+ }
178
+ },
179
+ "ampsId": {
180
+ "type": "integer",
181
+ "placeholder": "8",
182
+ "condition": {
183
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
184
+ }
185
+ },
186
+ "wattsId": {
187
+ "type": "integer",
188
+ "placeholder": "7",
189
+ "condition": {
190
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
191
+ }
192
+ },
193
+ "voltsDivisor": {
194
+ "type": "integer",
195
+ "placeholder": "10",
196
+ "condition": {
197
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
198
+ }
199
+ },
200
+ "ampsDivisor": {
201
+ "type": "integer",
202
+ "placeholder": "1000",
203
+ "condition": {
204
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
205
+ }
206
+ },
207
+ "wattsDivisor": {
208
+ "type": "integer",
209
+ "placeholder": "10",
210
+ "condition": {
211
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
212
+ }
213
+ },
214
+ "dpPower": {
215
+ "type": "integer",
216
+ "placeholder": "1",
217
+ "condition": {
218
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Outlet', 'TWLight', 'RGBTWLight', 'SimpleDimmer','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
219
+ }
220
+ },
221
+ "dpBrightness": {
222
+ "type": "integer",
223
+ "placeholder": "2",
224
+ "condition": {
225
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['TWLight', 'RGBTWLight', 'SimpleDimmer','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
226
+ }
227
+ },
228
+ "dpColorTemperature": {
229
+ "type": "integer",
230
+ "condition": {
231
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['TWLight', 'RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
232
+ }
233
+ },
234
+ "minWhiteColor": {
235
+ "type": "integer",
236
+ "placeholder": "140",
237
+ "condition": {
238
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['TWLight', 'RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
239
+ }
240
+ },
241
+ "maxWhiteColor": {
242
+ "type": "integer",
243
+ "placeholder": "400",
244
+ "condition": {
245
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['TWLight', 'RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
246
+ }
247
+ },
248
+ "dpMode": {
249
+ "type": "integer",
250
+ "placeholder": "2",
251
+ "condition": {
252
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWLight', 'RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
253
+ }
254
+ },
255
+ "dpColor": {
256
+ "type": "integer",
257
+ "placeholder": "5",
258
+ "condition": {
259
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
260
+ }
261
+ },
262
+ "colorFunction": {
263
+ "type": "string",
264
+ "placeholder": "HEXHSB",
265
+ "condition": {
266
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
267
+ }
268
+ },
269
+ "scaleBrightness": {
270
+ "type": "integer",
271
+ "placeholder": "255",
272
+ "condition": {
273
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
274
+ }
275
+ },
276
+ "scaleWhiteColor": {
277
+ "type": "integer",
278
+ "placeholder": "255",
279
+ "condition": {
280
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWLight','RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
281
+ }
282
+ },
283
+ "outletCount": {
284
+ "type": "integer",
285
+ "placeholder": "5",
286
+ "condition": {
287
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['MultiOutlet'].includes(model.devices[arrayIndices].type);"
288
+ }
289
+ },
290
+ "outlets": {
291
+ "type": "array",
292
+ "orderable": false,
293
+ "items": {
294
+ "type": "object",
295
+ "properties": {
296
+ "name": {
297
+ "type": "string"
298
+ },
299
+ "dp": {
300
+ "type": "integer"
301
+ }
302
+ }
303
+ },
304
+ "condition": {
305
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['CustomMultiOutlet'].includes(model.devices[arrayIndices].type);"
306
+ }
307
+ },
308
+ "noCool": {
309
+ "type": "boolean",
310
+ "condition": {
311
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
312
+ }
313
+ },
314
+ "noHeat": {
315
+ "type": "boolean",
316
+ "condition": {
317
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
318
+ }
319
+ },
320
+ "cmdCool": {
321
+ "type": "string",
322
+ "placeholder": "COOL",
323
+ "condition": {
324
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
325
+ }
326
+ },
327
+ "cmdHeat": {
328
+ "type": "string",
329
+ "placeholder": "HEAT",
330
+ "condition": {
331
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
332
+ }
333
+ },
334
+ "noSwing": {
335
+ "type": "boolean",
336
+ "condition": {
337
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
338
+ }
339
+ },
340
+ "minTemperature": {
341
+ "type": "integer",
342
+ "placeholder": "15",
343
+ "condition": {
344
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner','Convector', 'SimpleHeater'].includes(model.devices[arrayIndices].type);"
345
+ }
346
+ },
347
+ "maxTemperature": {
348
+ "type": "integer",
349
+ "placeholder": "40",
350
+ "condition": {
351
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner','Convector', 'SimpleHeater'].includes(model.devices[arrayIndices].type);"
352
+ }
353
+ },
354
+ "minTemperatureSteps": {
355
+ "type": "integer",
356
+ "placeholder": "1",
357
+ "condition": {
358
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
359
+ }
360
+ },
361
+ "dpActive": {
362
+ "type": "integer",
363
+ "placeholder": "7",
364
+ "condition": {
365
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector', 'SimpleHeater'].includes(model.devices[arrayIndices].type);"
366
+ }
367
+ },
368
+ "dpDesiredTemperature": {
369
+ "type": "integer",
370
+ "placeholder": "2",
371
+ "condition": {
372
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector', 'SimpleHeater'].includes(model.devices[arrayIndices].type);"
373
+ }
374
+ },
375
+ "dpCurrentTemperature": {
376
+ "type": "integer",
377
+ "placeholder": "3",
378
+ "condition": {
379
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector', 'SimpleHeater'].includes(model.devices[arrayIndices].type);"
380
+ }
381
+ },
382
+ "dpLightOn": {
383
+ "type": "integer",
384
+ "placeholder": "9",
385
+ "condition": {
386
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
387
+ }
388
+ },
389
+ "dpFanOn": {
390
+ "type": "integer",
391
+ "placeholder": "1",
392
+ "condition": {
393
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
394
+ }
395
+ },
396
+ "dpRotationSpeed": {
397
+ "type": "integer",
398
+ "placeholder": "4",
399
+ "condition": {
400
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector', 'Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
401
+ }
402
+ },
403
+ "maxSpeed": {
404
+ "type": "integer",
405
+ "placeholder": "3",
406
+ "condition": {
407
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
408
+ }
409
+ },
410
+ "fanDefaultSpeed": {
411
+ "type": "integer",
412
+ "placeholder": "1",
413
+ "condition": {
414
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
415
+ }
416
+ },
417
+ "useStrings": {
418
+ "type": "boolean",
419
+ "placeholder": true,
420
+ "condition": {
421
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
422
+ }
423
+ },
424
+ "dpChildLock": {
425
+ "type": "integer",
426
+ "placeholder": "6",
427
+ "condition": {
428
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
429
+ }
430
+ },
431
+ "dpTemperatureDisplayUnits": {
432
+ "type": "integer",
433
+ "placeholder": "19",
434
+ "condition": {
435
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
436
+ }
437
+ },
438
+ "cmdLow": {
439
+ "type": "string",
440
+ "placeholder": "Low",
441
+ "condition": {
442
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
443
+ }
444
+ },
445
+ "cmdHigh": {
446
+ "type": "string",
447
+ "placeholder": "High",
448
+ "condition": {
449
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
450
+ }
451
+ },
452
+ "noChildLock": {
453
+ "type": "boolean",
454
+ "condition": {
455
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
456
+ }
457
+ },
458
+ "noTemperatureUnit": {
459
+ "type": "boolean",
460
+ "condition": {
461
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
462
+ }
463
+ },
464
+ "temperatureDivisor": {
465
+ "type": "integer",
466
+ "placeholder": "1",
467
+ "condition": {
468
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater'].includes(model.devices[arrayIndices].type);"
469
+ }
470
+ },
471
+ "thresholdTemperatureDivisor": {
472
+ "type": "integer",
473
+ "placeholder": "1",
474
+ "condition": {
475
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater'].includes(model.devices[arrayIndices].type);"
476
+ }
477
+ },
478
+ "targetTemperatureDivisor": {
479
+ "type": "integer",
480
+ "placeholder": "1",
481
+ "condition": {
482
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater'].includes(model.devices[arrayIndices].type);"
483
+ }
484
+ },
485
+ "dpAction": {
486
+ "type": "integer",
487
+ "placeholder": "1",
488
+ "condition": {
489
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['GarageDoor'].includes(model.devices[arrayIndices].type);"
490
+ }
491
+ },
492
+ "dpStatus": {
493
+ "type": "integer",
494
+ "placeholder": "2",
495
+ "condition": {
496
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['GarageDoor'].includes(model.devices[arrayIndices].type);"
497
+ }
498
+ },
499
+ "flipState": {
500
+ "type": "boolean",
501
+ "condition": {
502
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['GarageDoor','SimpleBlinds'].includes(model.devices[arrayIndices].type);"
503
+ }
504
+ },
505
+ "timeToOpen": {
506
+ "type": "integer",
507
+ "placeholder": "45",
508
+ "condition": {
509
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleBlinds'].includes(model.devices[arrayIndices].type);"
510
+ }
511
+ },
512
+ "timeToTighten": {
513
+ "type": "integer",
514
+ "placeholder": "0",
515
+ "condition": {
516
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleBlinds'].includes(model.devices[arrayIndices].type);"
517
+ }
518
+ },
519
+ "dpLight": {
520
+ "type": "integer",
521
+ "placeholder": 1,
522
+ "condition": {
523
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['RGBTWOutlet'].includes(model.devices[arrayIndices].type);"
524
+ }
525
+ },
526
+ "dpBlindType": {
527
+ "type": "integer",
528
+ "placeholder": 1,
529
+ "condition": {
530
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleBlinds'].includes(model.devices[arrayIndices].type);"
531
+ }
532
+ }
533
+ }
534
+ }
535
+ }
536
+ }
537
+ }
538
+ }
@@ -0,0 +1,15 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import { defineConfig } from "eslint/config";
4
+
5
+
6
+ export default defineConfig([
7
+ { files: ["**/*.{js,mjs,cjs}"], plugins: { js }, extends: ["js/recommended"], "rules": {
8
+ // TODO(adrianjagielak): Fix remaining problems.
9
+ "no-prototype-builtins": "off",
10
+ "no-unused-vars": "off",
11
+ "no-empty": "off",
12
+ } },
13
+ { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
14
+ { files: ["**/*.{js,mjs,cjs}"], languageOptions: { globals: globals.node } },
15
+ ]);