signalk-shelly2 1.0.0

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.
package/dist/index.js ADDED
@@ -0,0 +1,1015 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2025 Scott Bender <scott@scottbender.net>
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.default = default_1;
21
+ const camelcase_1 = __importDefault(require("camelcase"));
22
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
23
+ const mdns = require('mdns-js');
24
+ const device_1 = require("./device");
25
+ const SERVICE_NAME = 'shelly';
26
+ const deviceKey = (device) => device.id;
27
+ function default_1(app) {
28
+ const error = app.error;
29
+ const debug = app.debug;
30
+ let sentMetaDevices = {};
31
+ let props;
32
+ let onStop = [];
33
+ let startedOnce = false;
34
+ let stopped = true;
35
+ let discoveredDevices = {};
36
+ let browser;
37
+ const plugin = {
38
+ start: function (properties) {
39
+ props = properties;
40
+ browser = mdns.createBrowser(mdns.tcp(SERVICE_NAME));
41
+ browser.on('ready', () => {
42
+ browser.discover();
43
+ });
44
+ browser.on('update', async (data) => {
45
+ if (Array.isArray(data.type) &&
46
+ data.type[0].name === SERVICE_NAME &&
47
+ data.fullname) {
48
+ let deviceId = data.fullname.split('.', 1)[0];
49
+ if (discoveredDevices[deviceId]) {
50
+ return;
51
+ }
52
+ const gen = data.txt.find((txt) => txt.startsWith('gen=')).split('=')[1];
53
+ if (gen && Number(gen) >= 2) {
54
+ const props = getDeviceProps(deviceId);
55
+ let device = new device_1.Device(app, plugin, props, data.addresses[0]);
56
+ try {
57
+ discoveredDevices[deviceId] = device;
58
+ if (props?.enabled === false) {
59
+ return;
60
+ }
61
+ await device.connect();
62
+ }
63
+ catch (error) {
64
+ console.error(`Failed to connect to device ${deviceId}`);
65
+ console.error(error);
66
+ return;
67
+ }
68
+ }
69
+ }
70
+ });
71
+ },
72
+ stop: function () {
73
+ sentMetaDevices = {};
74
+ onStop.forEach((f) => f());
75
+ onStop = [];
76
+ stopped = true;
77
+ Object.values(discoveredDevices).forEach((device) => {
78
+ device.disconnect();
79
+ });
80
+ discoveredDevices = {};
81
+ if (browser) {
82
+ browser.stop();
83
+ browser = null;
84
+ }
85
+ },
86
+ id: 'signalk-shelly2',
87
+ name: 'Shelly 2',
88
+ description: 'Signal K Plugin For Shelly Gen2+ devices',
89
+ schema: () => {
90
+ const schema = {
91
+ type: 'object',
92
+ properties: {}
93
+ };
94
+ let devices = Object.values(discoveredDevices);
95
+ devices.forEach((device) => {
96
+ debug(`adding Device ID ${deviceKey(device)} to schema`);
97
+ let props = (schema.properties[`Device ID ${deviceKey(device)}`] = {
98
+ type: 'object',
99
+ properties: {
100
+ deviceName: {
101
+ type: 'string',
102
+ title: 'Name',
103
+ default: device.name,
104
+ readOnly: true
105
+ },
106
+ deviceModel: {
107
+ type: 'string',
108
+ title: 'Model',
109
+ default: device.model,
110
+ readOnly: true
111
+ },
112
+ deviceAddress: {
113
+ type: 'string',
114
+ title: 'Address',
115
+ default: device.address,
116
+ readOnly: true
117
+ },
118
+ enabled: {
119
+ type: 'boolean',
120
+ title: 'Enabled',
121
+ default: true
122
+ },
123
+ devicePath: {
124
+ type: 'string',
125
+ title: 'Device Path',
126
+ default: device.name ? (0, camelcase_1.default)(device.name) : deviceKey(device),
127
+ description: 'Used to generate the path name, ie. electrical.switches.${devicePath}'
128
+ },
129
+ displayName: {
130
+ type: 'string',
131
+ title: 'Display Name (meta)',
132
+ default: device.name
133
+ }
134
+ }
135
+ });
136
+ if (device.numSwitches > 1) {
137
+ for (let i = 0; i < device.numSwitches; i++) {
138
+ const key = `switch${i}`;
139
+ let defaultPath;
140
+ let description;
141
+ defaultPath = i.toString();
142
+ description =
143
+ 'Used to generate the path name, ie electrical.switches.${bankPath}.${switchPath}.state';
144
+ props.properties[key] = {
145
+ type: 'object',
146
+ properties: {
147
+ switchPath: {
148
+ type: 'string',
149
+ title: 'Switch Path',
150
+ default: defaultPath,
151
+ description
152
+ },
153
+ displayName: {
154
+ type: 'string',
155
+ title: 'Display Name (meta)'
156
+ },
157
+ enabled: {
158
+ type: 'boolean',
159
+ title: 'Enabled',
160
+ default: true
161
+ }
162
+ }
163
+ };
164
+ }
165
+ }
166
+ /*
167
+ if ( info.readPaths?.find((prop:any) => {
168
+ return typeof prop !== 'string' && prop.notification
169
+ }) ) {
170
+ props.properties.sendNotifications = {
171
+ type: 'boolean',
172
+ title: 'Send Notifications',
173
+ default: true
174
+ }
175
+ }
176
+
177
+ if (info.isRGBW) {
178
+ props.properties.presets = {
179
+ title: 'Presets',
180
+ type: 'array',
181
+ items: {
182
+ type: 'object',
183
+ required: ['name', 'red', 'green', 'blue', 'white', 'bright'],
184
+ properties: {
185
+ name: {
186
+ type: 'string',
187
+ title: 'Name'
188
+ },
189
+ red: {
190
+ type: 'number',
191
+ title: 'Red',
192
+ default: 255
193
+ },
194
+ green: {
195
+ type: 'number',
196
+ title: 'Green',
197
+ default: 255
198
+ },
199
+ blue: {
200
+ type: 'number',
201
+ title: 'Blue',
202
+ default: 255
203
+ },
204
+ white: {
205
+ type: 'number',
206
+ title: 'White',
207
+ default: 255
208
+ },
209
+ bright: {
210
+ type: 'number',
211
+ title: 'Brightness',
212
+ description:
213
+ 'Number between 1-100. Set to 0 to preserve current brightness',
214
+ default: 100
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ */
221
+ });
222
+ schema.properties.nextGenPassswords = {
223
+ title: 'Next Gen Device Passwords',
224
+ type: 'array',
225
+ items: {
226
+ type: 'object',
227
+ required: ['id', 'password'],
228
+ properties: {
229
+ id: {
230
+ type: 'string',
231
+ title: 'Device Id'
232
+ },
233
+ password: {
234
+ type: 'string',
235
+ title: 'Password'
236
+ }
237
+ }
238
+ }
239
+ };
240
+ return schema;
241
+ },
242
+ uiSchema: () => {
243
+ const uiSchema = {};
244
+ let devices = Object.values(discoveredDevices);
245
+ devices.forEach((device) => {
246
+ uiSchema[`Device ID ${deviceKey(device)}`] = {
247
+ password: {
248
+ 'ui:widget': 'password'
249
+ }
250
+ };
251
+ });
252
+ return uiSchema;
253
+ }
254
+ };
255
+ function filterEnabledDevices(devices) {
256
+ return Object.values(discoveredDevices).filter((device) => {
257
+ const deviceProps = getDeviceProps(device);
258
+ return (!deviceProps ||
259
+ typeof deviceProps.enabled === 'undefined' ||
260
+ deviceProps.enabled);
261
+ });
262
+ }
263
+ function getDeviceProps(id) {
264
+ return props[`Device ID ${id}`];
265
+ }
266
+ const rgbwPutPaths = [
267
+ {
268
+ deviceProp: 'switch',
269
+ name: 'state',
270
+ setter: (device, value) => {
271
+ return device.setColor({
272
+ turn: boolString(value)
273
+ });
274
+ },
275
+ convertFrom: (value) => {
276
+ return value === true ? 1 : 0;
277
+ }
278
+ },
279
+ {
280
+ //deviceProp: 'gain',
281
+ name: 'dimmingLevel',
282
+ setter: (device, value) => {
283
+ if (device.white > 0) {
284
+ let white = device.white / 255;
285
+ let gain = device.gain / 100;
286
+ if (white < gain) {
287
+ white = white + value - gain;
288
+ }
289
+ else {
290
+ white = value;
291
+ value = gain + value - white;
292
+ }
293
+ if (white <= 0) {
294
+ white = 0.01;
295
+ }
296
+ device.setColor({
297
+ white: white * 255
298
+ });
299
+ }
300
+ if (value <= 0) {
301
+ value = 0.01;
302
+ }
303
+ return device.setColor({
304
+ gain: Number((value * 100).toFixed(0))
305
+ });
306
+ },
307
+ getter: (device) => {
308
+ let value = device.gain / 100;
309
+ if (device.red === 0 && device.green === 0 && device.blue === 0) {
310
+ value = device.white / 255;
311
+ }
312
+ else if (device.gain > 0 && device.white > 0) {
313
+ value = device.white > device.gain ? device.white / 255 : value;
314
+ }
315
+ return Number(value.toFixed(2));
316
+ },
317
+ meta: {
318
+ units: 'ratio',
319
+ type: 'dimmer',
320
+ canDimWhenOff: true
321
+ }
322
+ },
323
+ {
324
+ deviceProp: 'red',
325
+ setter: (device, value) => {
326
+ return device.setColor({
327
+ red: value
328
+ });
329
+ },
330
+ meta: {
331
+ units: 'rgbColor',
332
+ range: [0, 255]
333
+ }
334
+ },
335
+ {
336
+ deviceProp: 'green',
337
+ setter: (device, value) => {
338
+ return device.setColor({
339
+ green: value
340
+ });
341
+ },
342
+ meta: {
343
+ units: 'rgbColor',
344
+ range: [0, 255]
345
+ }
346
+ },
347
+ {
348
+ deviceProp: 'blue',
349
+ setter: (device, value) => {
350
+ return device.setColor({
351
+ blue: value
352
+ });
353
+ },
354
+ meta: {
355
+ units: 'rgbColor',
356
+ range: [0, 255]
357
+ }
358
+ },
359
+ {
360
+ deviceProp: 'white',
361
+ setter: (device, value) => {
362
+ return device.setColor({
363
+ white: value
364
+ });
365
+ },
366
+ meta: {
367
+ units: 'rgbColor',
368
+ range: [0, 255]
369
+ }
370
+ },
371
+ {
372
+ name: 'preset',
373
+ getter: (device) => {
374
+ const deviceProps = getDeviceProps(device);
375
+ const preset = deviceProps?.presets?.find((preset) => {
376
+ return (device.red == preset.red &&
377
+ device.green == preset.green &&
378
+ device.blue == preset.blue &&
379
+ device.white == preset.white &&
380
+ (preset.bright === 0 || device.gain == preset.bright));
381
+ });
382
+ return preset?.name || 'Unknown';
383
+ },
384
+ setter: (device, value) => {
385
+ const deviceProps = getDeviceProps(device);
386
+ const preset = deviceProps?.presets.find((preset) => preset.name == value);
387
+ if (value === 'Unknown' || !preset) {
388
+ throw new Error(`invalid value ${value}`);
389
+ }
390
+ else {
391
+ const params = {
392
+ red: preset.red,
393
+ green: preset.green,
394
+ blue: preset.blue,
395
+ white: preset.white,
396
+ turn: 'on'
397
+ };
398
+ if (preset.bright !== 0) {
399
+ params.gain = preset.bright;
400
+ }
401
+ return device.setColor(params);
402
+ }
403
+ }
404
+ }
405
+ ];
406
+ const simpleRelayPutPaths = [
407
+ {
408
+ deviceProp: 'relay0',
409
+ name: 'state',
410
+ setter: (device, value) => {
411
+ return device.setRelay(0, boolValue(value));
412
+ },
413
+ convertFrom: (value) => {
414
+ return value ? 1 : 0;
415
+ }
416
+ }
417
+ ];
418
+ const simpleRelayReadPaths = ['input0'];
419
+ const nextgenSwitchPutPaths = (key) => {
420
+ return [
421
+ {
422
+ deviceProp: key,
423
+ name: 'state',
424
+ setter: (device, value) => {
425
+ return device[key].set(boolValue(value));
426
+ },
427
+ convertFrom: (value) => {
428
+ return value.output ? 1 : 0;
429
+ }
430
+ }
431
+ ];
432
+ };
433
+ const nextgenSwitchReadPaths = (key) => {
434
+ return [
435
+ {
436
+ key: `${key}.voltage`,
437
+ path: 'voltage',
438
+ meta: {
439
+ units: 'V'
440
+ }
441
+ },
442
+ {
443
+ key: `${key}.temperature`,
444
+ path: 'temperature',
445
+ converter: nextgenTemperatureConverter,
446
+ meta: {
447
+ units: 'K'
448
+ }
449
+ },
450
+ {
451
+ key: `${key}.source`,
452
+ path: 'source',
453
+ meta: {
454
+ units: 'string'
455
+ }
456
+ },
457
+ {
458
+ key: `${key}.apower`,
459
+ path: 'apower',
460
+ meta: {
461
+ units: 'W'
462
+ }
463
+ },
464
+ {
465
+ key: `${key}.current`,
466
+ path: 'current',
467
+ meta: {
468
+ units: 'A'
469
+ }
470
+ },
471
+ {
472
+ key: `${key}.pf`,
473
+ path: 'powerFactor',
474
+ converter: (val) => {
475
+ return val * 1000;
476
+ },
477
+ meta: {
478
+ units: 'W'
479
+ }
480
+ }
481
+ ];
482
+ };
483
+ const nextgenInputPaths = (key) => {
484
+ return [
485
+ {
486
+ key: `${key}.state`,
487
+ path: key,
488
+ converter: (value) => {
489
+ return value ? 1 : 0;
490
+ }
491
+ /*
492
+ notification: {
493
+ handler: (value) => {
494
+ return value === true
495
+ },
496
+ messageOn: 'flood sensor is on',
497
+ messageOff: 'flood sensor is off'
498
+ }
499
+ */
500
+ }
501
+ ];
502
+ };
503
+ const simpleRelay = {
504
+ putPaths: simpleRelayPutPaths,
505
+ readPaths: simpleRelayReadPaths
506
+ };
507
+ const temperatureConverter = (value) => {
508
+ if (props?.tempUnits === 'C') {
509
+ return value + 273.15;
510
+ }
511
+ else {
512
+ return ((value - 32) * 5) / 9 + 273.15;
513
+ }
514
+ };
515
+ const nextgenTemperatureConverter = (value) => {
516
+ return value?.tC + 273.15;
517
+ };
518
+ const humidityConverter = (value) => {
519
+ return value / 100;
520
+ };
521
+ const nextgenHumidityConverter = (value) => {
522
+ return value?.rh / 100;
523
+ };
524
+ const deviceTypes = {
525
+ /* For testing bank stuff */
526
+ /*
527
+ 'Shelly Plus 1': {
528
+ nextGen: true,
529
+ isSwitchBank: true,
530
+ switchCount: 1,
531
+ switchKey: 'switch',
532
+ isDimmable: false,
533
+ bankReadPaths: nextgenSwitchReadPaths,
534
+ switchSetter: (device: any, value: any, switchIdx: number) => {
535
+ return device[`switch${switchIdx}`].set(boolValue(value))
536
+ },
537
+ readPaths: [
538
+ ...nextgenInputPaths('input0')
539
+ ]
540
+ },
541
+ */
542
+ 'Shelly Plus 1': {
543
+ nextGen: true,
544
+ putPaths: nextgenSwitchPutPaths('switch0'),
545
+ readPaths: [
546
+ ...nextgenSwitchReadPaths('switch0'),
547
+ ...nextgenInputPaths('input0')
548
+ ],
549
+ },
550
+ 'Shelly Plus 1 PM': {
551
+ nextGen: true,
552
+ putPaths: nextgenSwitchPutPaths('switch0'),
553
+ readPaths: [
554
+ ...nextgenSwitchReadPaths('switch0'),
555
+ ...nextgenInputPaths('input0')
556
+ ]
557
+ },
558
+ 'Shelly Pro 1': {
559
+ nextGen: true,
560
+ putPaths: nextgenSwitchPutPaths('switch0'),
561
+ readPaths: [
562
+ ...nextgenSwitchReadPaths('switch0'),
563
+ ...nextgenInputPaths('input0'),
564
+ ...nextgenInputPaths('input1')
565
+ ]
566
+ },
567
+ 'Shelly Pro 1 PM': {
568
+ nextGen: true,
569
+ putPaths: nextgenSwitchPutPaths('switch0'),
570
+ readPaths: [
571
+ ...nextgenSwitchReadPaths('switch0'),
572
+ ...nextgenInputPaths('input0'),
573
+ ...nextgenInputPaths('input1')
574
+ ]
575
+ },
576
+ 'Shelly Plus 2 PM': {
577
+ nextGen: true,
578
+ isSwitchBank: true,
579
+ switchCount: 2,
580
+ switchKey: 'switch',
581
+ isDimmable: false,
582
+ bankReadPaths: nextgenSwitchReadPaths,
583
+ switchSetter: (device, value, switchIdx) => {
584
+ return device[`switch${switchIdx}`].set(boolValue(value));
585
+ },
586
+ readPaths: [
587
+ ...nextgenInputPaths('input0'),
588
+ ...nextgenInputPaths('input1')
589
+ ]
590
+ },
591
+ 'Shelly Pro 4 PM': {
592
+ nextGen: true,
593
+ isSwitchBank: true,
594
+ switchCount: 4,
595
+ switchKey: 'switch',
596
+ isDimmable: false,
597
+ bankReadPaths: nextgenSwitchReadPaths,
598
+ switchSetter: (device, value, switchIdx) => {
599
+ return device[`switch${switchIdx}`].set(boolValue(value));
600
+ },
601
+ readPaths: [
602
+ ...nextgenInputPaths('input0'),
603
+ ...nextgenInputPaths('input1'),
604
+ ...nextgenInputPaths('input2'),
605
+ ...nextgenInputPaths('input3')
606
+ ]
607
+ },
608
+ 'Shelly Plus I4': {
609
+ nextGen: true,
610
+ readPaths: [
611
+ ...nextgenInputPaths('input0'),
612
+ ...nextgenInputPaths('input1'),
613
+ ...nextgenInputPaths('input2'),
614
+ ...nextgenInputPaths('input3'),
615
+ ]
616
+ },
617
+ 'Shelly Plus Plug US': {
618
+ nextGen: true,
619
+ putPaths: nextgenSwitchPutPaths('switch0'),
620
+ readPaths: [
621
+ ...nextgenSwitchReadPaths('switch0')
622
+ ]
623
+ },
624
+ 'SHSW-1': {
625
+ putPaths: simpleRelayPutPaths,
626
+ readPaths: [
627
+ ...simpleRelayReadPaths,
628
+ {
629
+ key: 'externalTemperature0',
630
+ converter: temperatureConverter
631
+ },
632
+ {
633
+ key: 'externalTemperature1',
634
+ converter: temperatureConverter
635
+ },
636
+ {
637
+ key: 'externalTemperature2',
638
+ converter: temperatureConverter
639
+ }
640
+ ]
641
+ },
642
+ 'SHRGBWW-01': {
643
+ isRGBW: true,
644
+ putPaths: rgbwPutPaths
645
+ },
646
+ 'SHRGBW2:white': {
647
+ isSwitchBank: true,
648
+ switchCount: 4,
649
+ switchKey: 'switch',
650
+ isDimmable: true,
651
+ canDimWhenOff: true,
652
+ switchSetter: (device, value, switchIdx) => {
653
+ return device.setWhite(switchIdx, undefined, value === 1 || value === 'on' || value === 'true' || value === true);
654
+ },
655
+ dimmerSetter: (device, value, switchIdx) => {
656
+ return device.setWhite(switchIdx, Number((value * 100).toFixed(0)), device[`switch${switchIdx}`]);
657
+ }
658
+ },
659
+ 'SHRGBW2:color': {
660
+ isRGBW: true,
661
+ putPaths: rgbwPutPaths,
662
+ readPaths: [
663
+ 'mode',
664
+ 'overPower',
665
+ 'input0',
666
+ 'power0',
667
+ 'power1',
668
+ 'power2',
669
+ 'power3'
670
+ ]
671
+ },
672
+ 'SHSW-44': {
673
+ isSwitchBank: true,
674
+ switchCount: 4,
675
+ switchKey: 'relay',
676
+ isDimmable: false,
677
+ switchSetter: (device, value, switchIdx) => {
678
+ return device.setRelay(switchIdx, boolValue(value));
679
+ }
680
+ },
681
+ 'SHSW-L': {
682
+ putPaths: simpleRelayPutPaths,
683
+ readPaths: [
684
+ ...simpleRelayReadPaths,
685
+ 'input1',
686
+ 'power0',
687
+ 'energyCounter0',
688
+ 'deviceTemperature',
689
+ 'overTemperature'
690
+ ]
691
+ },
692
+ 'SHSW-PM': {
693
+ putPaths: simpleRelayPutPaths,
694
+ readPaths: [
695
+ ...simpleRelayReadPaths,
696
+ 'power0',
697
+ 'energyCounter0',
698
+ 'overPower',
699
+ 'overPowerValue',
700
+ 'deviceTemperature',
701
+ 'overTemperature'
702
+ ]
703
+ },
704
+ 'SHSW-21:relay': {
705
+ isSwitchBank: true,
706
+ switchCount: 2,
707
+ switchKey: 'relay',
708
+ isDimmable: false,
709
+ switchSetter: (device, value, switchIdx) => {
710
+ return device.setRelay(switchIdx, boolValue(value));
711
+ },
712
+ readPaths: [
713
+ 'mode',
714
+ 'energyCounter0',
715
+ 'overPower0',
716
+ 'overPower1',
717
+ 'overPowerValue'
718
+ ]
719
+ },
720
+ 'SHUNI-1': {
721
+ isSwitchBank: true,
722
+ switchCount: 2,
723
+ switchKey: 'relay',
724
+ isDimmable: false,
725
+ switchSetter: (device, value, switchIdx) => {
726
+ return device.setRelay(switchIdx, boolValue(value));
727
+ },
728
+ readPaths: [
729
+ 'input0',
730
+ 'inputEvent0',
731
+ 'inputEventCounter0',
732
+ 'input1',
733
+ 'inputEvent1',
734
+ 'inputEventCounter1',
735
+ {
736
+ key: 'externalTemperature0',
737
+ converter: temperatureConverter
738
+ },
739
+ {
740
+ key: 'externalTemperature1',
741
+ converter: temperatureConverter
742
+ },
743
+ {
744
+ key: 'externalTemperature2',
745
+ converter: temperatureConverter
746
+ },
747
+ {
748
+ key: 'externalTemperature3',
749
+ converter: temperatureConverter
750
+ },
751
+ {
752
+ key: 'externalTemperature4',
753
+ converter: temperatureConverter
754
+ },
755
+ 'voltage0',
756
+ {
757
+ key: 'externalHumidity',
758
+ converter: humidityConverter,
759
+ meta: {
760
+ units: 'ratio',
761
+ }
762
+ }
763
+ ]
764
+ },
765
+ 'SHHT-1': {
766
+ readPaths: [
767
+ {
768
+ key: 'temperature',
769
+ converter: temperatureConverter
770
+ },
771
+ {
772
+ key: 'humidity',
773
+ converter: humidityConverter,
774
+ meta: {
775
+ units: 'ratio',
776
+ }
777
+ },
778
+ 'battery'
779
+ ]
780
+ },
781
+ 'Shelly Plus H&T': {
782
+ nextGen: true,
783
+ readPaths: [
784
+ {
785
+ key: 'temperature0',
786
+ converter: nextgenTemperatureConverter
787
+ },
788
+ {
789
+ key: 'humidity0',
790
+ converter: nextgenHumidityConverter,
791
+ meta: {
792
+ units: 'ratio',
793
+ }
794
+ }
795
+ ]
796
+ },
797
+ SHEM: {
798
+ isSwitchBank: true,
799
+ switchCount: 1,
800
+ switchKey: 'relay',
801
+ isDimmable: false,
802
+ switchSetter: (device, value, switchIdx) => {
803
+ return device.setRelay(switchIdx, boolValue(value));
804
+ },
805
+ readPaths: [
806
+ 'power0',
807
+ 'energyCounter0',
808
+ 'energyReturned0',
809
+ 'voltage0',
810
+ 'power1',
811
+ 'energyCounter1',
812
+ 'energyReturned1',
813
+ 'voltage1',
814
+ 'overPower'
815
+ ]
816
+ },
817
+ 'SHEM-3': {
818
+ isSwitchBank: true,
819
+ switchCount: 1,
820
+ switchKey: 'relay',
821
+ isDimmable: false,
822
+ switchSetter: (device, value, switchIdx) => {
823
+ return device.setRelay(switchIdx, boolValue(value));
824
+ },
825
+ readPaths: [
826
+ 'power0',
827
+ 'energyCounter0',
828
+ 'energyReturned0',
829
+ 'powerFactor0',
830
+ 'current0',
831
+ 'voltage0',
832
+ 'power1',
833
+ 'energyCounter1',
834
+ 'energyReturned1',
835
+ 'powerFactor1',
836
+ 'current1',
837
+ 'voltage1',
838
+ 'power2',
839
+ 'energyCounter2',
840
+ 'energyReturned2',
841
+ 'powerFactor2',
842
+ 'current2',
843
+ 'voltage2',
844
+ 'overPower'
845
+ ]
846
+ },
847
+ 'SHSW-21:roller': {
848
+ readPaths: [
849
+ 'mode',
850
+ 'power0',
851
+ 'energyCounter0',
852
+ 'overPower0',
853
+ 'overPower1',
854
+ 'overPowerValue'
855
+ ],
856
+ putPaths: [
857
+ {
858
+ deviceProp: 'rollerState',
859
+ setter: (device, value) => {
860
+ return device.setRollerState(value);
861
+ }
862
+ },
863
+ {
864
+ deviceProp: 'rollerPosition',
865
+ setter: (device, value) => {
866
+ return device.setRollerPosition(value);
867
+ }
868
+ }
869
+ ]
870
+ },
871
+ 'SHSW-22': {
872
+ isSwitchBank: true,
873
+ switchCount: 2,
874
+ switchKey: 'relay',
875
+ isDimmable: false,
876
+ switchSetter: (device, value, switchIdx) => {
877
+ return device.setRelay(switchIdx, boolValue(value));
878
+ }
879
+ },
880
+ 'SHPLG2-1': simpleRelay,
881
+ 'SHPLG-S': simpleRelay,
882
+ 'SHPLG-U1': simpleRelay,
883
+ 'SHPLG-1': {
884
+ putPaths: simpleRelayPutPaths,
885
+ readPaths: [
886
+ ...simpleRelayReadPaths,
887
+ 'power0',
888
+ 'energyCounter0',
889
+ 'overPower',
890
+ 'overPowerValue'
891
+ ]
892
+ },
893
+ 'SHDW-1': {
894
+ readPaths: [
895
+ 'state',
896
+ 'vibration',
897
+ 'illuminance',
898
+ 'illuminanceLevel',
899
+ 'sensorError',
900
+ 'battery',
901
+ 'wakeupEvent'
902
+ ]
903
+ },
904
+ 'SHDW-2': {
905
+ readPaths: [
906
+ {
907
+ key: 'state',
908
+ notification: {
909
+ handler: (value) => {
910
+ return value === 1;
911
+ },
912
+ messageOn: 'is open',
913
+ messageOff: 'is closed'
914
+ }
915
+ },
916
+ 'vibration',
917
+ 'illuminance',
918
+ 'illuminanceLevel',
919
+ 'sensorError',
920
+ 'battery',
921
+ 'wakeupEvent',
922
+ {
923
+ key: 'temperature',
924
+ converter: temperatureConverter
925
+ },
926
+ ]
927
+ },
928
+ 'SHWT-1': {
929
+ readPaths: [
930
+ {
931
+ key: 'flood',
932
+ notification: {
933
+ handler: (value) => {
934
+ return value === 1;
935
+ },
936
+ messageOn: 'flood sensor is on',
937
+ messageOff: 'flood sensor is off'
938
+ }
939
+ },
940
+ 'sensorError',
941
+ 'battery',
942
+ 'wakeupEvent',
943
+ {
944
+ key: 'temperature',
945
+ converter: temperatureConverter
946
+ },
947
+ ]
948
+ },
949
+ 'SHMOS-01': {
950
+ readPaths: [
951
+ {
952
+ key: 'motion',
953
+ notification: {
954
+ handler: (value) => {
955
+ return value === 1;
956
+ },
957
+ messageOn: 'motion detected',
958
+ messageOff: 'motion cleared'
959
+ }
960
+ },
961
+ 'vibration',
962
+ 'battery',
963
+ 'illuminance'
964
+ ],
965
+ },
966
+ 'SHMOS-02': {
967
+ readPaths: [
968
+ {
969
+ key: 'motion',
970
+ notification: {
971
+ handler: (value) => {
972
+ return value === 1;
973
+ },
974
+ messageOn: 'motion detected',
975
+ messageOff: 'motion cleared'
976
+ }
977
+ },
978
+ 'vibration',
979
+ 'battery',
980
+ 'illuminance',
981
+ {
982
+ key: 'temperature',
983
+ converter: temperatureConverter
984
+ },
985
+ ]
986
+ },
987
+ };
988
+ deviceTypes['SHSW-25:roller'] = { ...deviceTypes['SHSW-21:roller'] };
989
+ deviceTypes['SHSW-25:roller'].readPaths.push('overTemperature');
990
+ deviceTypes['SHSW-25:roller'].readPaths.push('deviceTemperature');
991
+ deviceTypes['SHSW-25:relay'] = { ...deviceTypes['SHSW-21:relay'] };
992
+ deviceTypes['SHSW-25:relay'].readPaths.push('overTemperature');
993
+ deviceTypes['SHSW-25:relay'].readPaths.push('deviceTemperature');
994
+ deviceTypes['SH2LED-1'] = { ...deviceTypes['SHRGBWW-01'] };
995
+ deviceTypes['SH2LED-1'].switchCount = 2;
996
+ deviceTypes['SHBLB-1:color'] = { ...deviceTypes['SHRGBWW-01'] };
997
+ deviceTypes['SHBLB-1:white'] = { ...deviceTypes['SHRGBW2:white'] };
998
+ deviceTypes['SHCB-1:color'] = { ...deviceTypes['SHRGBWW-01'] };
999
+ deviceTypes['SHCB-1:white'] = { ...deviceTypes['SHRGBW2:white'] };
1000
+ deviceTypes['SHCL-255:color'] = { ...deviceTypes['SHRGBWW-01'] };
1001
+ deviceTypes['SHCL-255:white'] = { ...deviceTypes['SHRGBW2:white'] };
1002
+ deviceTypes['Shelly Pro 2'] = { ...deviceTypes['Shelly Plus 2 PM'] };
1003
+ deviceTypes['Shelly Pro 2 PM'] = { ...deviceTypes['Shelly Plus 2 PM'] };
1004
+ return plugin;
1005
+ }
1006
+ function boolValue(value) {
1007
+ return value === 1 || value === 'on' || value === 'true' || value === true;
1008
+ }
1009
+ function boolString(value) {
1010
+ return boolValue(value) ? 'on' : 'off';
1011
+ }
1012
+ function boolFrom(value) {
1013
+ return value === 'on' ? 1 : 0;
1014
+ }
1015
+ //# sourceMappingURL=index.js.map