zigbee-herdsman-converters 15.0.0 → 15.0.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.
- package/README.md +2 -0
- package/converters/toZigbee.js +5 -2
- package/devices/danfoss.js +20 -6
- package/devices/ewelink.js +15 -0
- package/devices/nue_3a.js +1 -1
- package/devices/philips.js +14 -0
- package/devices/tuya.js +2 -0
- package/devices/ubisys.js +37 -18
- package/devices/woolley.js +0 -12
- package/lib/utils.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ If any of those commands finish with an error your PR won't pass the tests and w
|
|
|
23
23
|
|
|
24
24
|
## Documentation of definition meta property
|
|
25
25
|
- `multiEndpoint`: enables the multi endpoint functionallity in e.g. fromZigbee.on_off, example: normally this converter would return {"state": "OFF"}, when multiEndpoint is enabled the 'endpoint' method of the device definition will be called to determine the endpoint name which is then used as key e.g. {"state_left": "OFF"}. Only needed when device sends the same attribute from multiple endpoints. (default: false)
|
|
26
|
+
- `multiEndpointSkip`: array of attributes to not suffix with the endpoint name
|
|
27
|
+
- `multiEndpointEnforce`: enforce a certain endpoint for an attribute, e.g. {"power": 4} see utils.enforceEndpoint()
|
|
26
28
|
- `disableDefaultResponse`: used by toZigbee converters to disable the default response of some devices as they don't provide one. (default: false)
|
|
27
29
|
- `applyRedFix`: see toZigbee.light_color (default: false)
|
|
28
30
|
- `enhancedHue`: see toZigbee.light_color (default: true)
|
package/converters/toZigbee.js
CHANGED
|
@@ -1526,13 +1526,13 @@ const converters = {
|
|
|
1526
1526
|
metering_power: {
|
|
1527
1527
|
key: ['power'],
|
|
1528
1528
|
convertGet: async (entity, key, meta) => {
|
|
1529
|
-
await entity.read('seMetering', ['instantaneousDemand']);
|
|
1529
|
+
await utils.enforceEndpoint(entity, key, meta).read('seMetering', ['instantaneousDemand']);
|
|
1530
1530
|
},
|
|
1531
1531
|
},
|
|
1532
1532
|
currentsummdelivered: {
|
|
1533
1533
|
key: ['energy'],
|
|
1534
1534
|
convertGet: async (entity, key, meta) => {
|
|
1535
|
-
await entity.read('seMetering', ['currentSummDelivered']);
|
|
1535
|
+
await utils.enforceEndpoint(entity, key, meta).read('seMetering', ['currentSummDelivered']);
|
|
1536
1536
|
},
|
|
1537
1537
|
},
|
|
1538
1538
|
frequency: {
|
|
@@ -5515,6 +5515,9 @@ const converters = {
|
|
|
5515
5515
|
} else if (attribute === 'brightness') {
|
|
5516
5516
|
extensionfieldsets.push({'clstId': 8, 'len': 1, 'extField': [val]});
|
|
5517
5517
|
state['brightness'] = val;
|
|
5518
|
+
} else if (attribute === 'position') {
|
|
5519
|
+
extensionfieldsets.push({'clstId': 258, 'len': 1, 'extField': [val]});
|
|
5520
|
+
state['position'] = val;
|
|
5518
5521
|
} else if (attribute === 'color_temp') {
|
|
5519
5522
|
/*
|
|
5520
5523
|
* ZCL version 7 added support for ColorTemperatureMireds
|
package/devices/danfoss.js
CHANGED
|
@@ -56,14 +56,28 @@ module.exports = [
|
|
|
56
56
|
'to occupied_heating_setpoint it does not trigger an aggressive response from the actuator. ' +
|
|
57
57
|
'(more suitable for scheduled changes)'),
|
|
58
58
|
exposes.numeric('external_measured_room_sensor', ea.ALL)
|
|
59
|
-
.withDescription('
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
.withDescription('The temperature sensor of the TRV is — due to its design — relatively close to the heat source ' +
|
|
60
|
+
'(i.e. the hot water in the radiator). Thus there are situations where the `local_temperature` measured by the ' +
|
|
61
|
+
'TRV is not accurate enough: If the radiator is covered behind curtains or furniture, if the room is rather big, or ' +
|
|
62
|
+
'if the radiator itself is big and the flow temperature is high, then the temperature in the room may easily diverge ' +
|
|
63
|
+
'from the `local_temperature` measured by the TRV by 5°C to 8°C. In this case you might choose to use an external ' +
|
|
64
|
+
'room sensor and send the measured value of the external room sensor to the `External_measured_room_sensor` property.' +
|
|
65
|
+
'The way the TRV operates on the `External_measured_room_sensor` depends on the setting of the `Radiator_covered` ' +
|
|
66
|
+
'property: If `Radiator_covered` is `true` (Auto Offset Mode): You *must* set the `External_measured_room_sensor` ' +
|
|
67
|
+
'property *at least* every 3 hours. After 3 hours the TRV disables this function and resets the value of the ' +
|
|
68
|
+
'`External_measured_room_sensor` property to -8000 (disabled). You *should* set the `External_measured_room_sensor` ' +
|
|
69
|
+
'property *at most* every 30 minutes or every 0.1K change in measured room temperature.' +
|
|
70
|
+
'If `Radiator_covered` is `false` (Room Sensor Mode): You *must* set the `External_measured_room_sensor` property at ' +
|
|
71
|
+
'least every 30 minutes. After 35 minutes the TRV disables this function and resets the value of the ' +
|
|
72
|
+
'`External_measured_room_sensor` property to -8000 (disabled). You *should* set the `External_measured_room_sensor` ' +
|
|
73
|
+
'property *at most* every 5 minutes or every 0.1K change in measured room temperature.')
|
|
63
74
|
.withValueMin(-8000).withValueMax(3500),
|
|
64
75
|
exposes.binary('radiator_covered', ea.ALL, true, false)
|
|
65
|
-
.withDescription('
|
|
66
|
-
|
|
76
|
+
.withDescription('Controls whether the TRV should solely rely on an external room sensor or operate in offset mode. ' +
|
|
77
|
+
'`false` = Auto Offset Mode (use this e.g. for exposed radiators) or `true` = Room Sensor Mode (use this e.g. for ' +
|
|
78
|
+
'covered radiators). Please note that this flag only controls how the TRV operates on the value of ' +
|
|
79
|
+
'`External_measured_room_sensor`; only setting this flag without setting the `External_measured_room_sensor` ' +
|
|
80
|
+
'has no (noticable?) effect.'),
|
|
67
81
|
exposes.binary('window_open_feature', ea.ALL, true, false)
|
|
68
82
|
.withDescription('Whether or not the window open feature is enabled'),
|
|
69
83
|
exposes.numeric('window_open_internal', ea.STATE_GET).withValueMin(0).withValueMax(4)
|
package/devices/ewelink.js
CHANGED
|
@@ -20,6 +20,21 @@ module.exports = [
|
|
|
20
20
|
device.skipDefaultResponse = true;
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
zigbeeModel: ['SA-030-1'],
|
|
25
|
+
model: 'SA-030-1',
|
|
26
|
+
vendor: 'eWeLink',
|
|
27
|
+
description: 'Zigbee 3.0 smart plug 13A (3120W)(UK version)',
|
|
28
|
+
extend: extend.switch(),
|
|
29
|
+
fromZigbee: [fz.on_off_skip_duplicate_transaction],
|
|
30
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
31
|
+
const endpoint = device.getEndpoint(1);
|
|
32
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
33
|
+
},
|
|
34
|
+
onEvent: async (type, data, device) => {
|
|
35
|
+
device.skipDefaultResponse = true;
|
|
36
|
+
},
|
|
37
|
+
},
|
|
23
38
|
{
|
|
24
39
|
zigbeeModel: ['SWITCH-ZR02'],
|
|
25
40
|
model: 'SWITCH-ZR02',
|
package/devices/nue_3a.js
CHANGED
|
@@ -257,7 +257,7 @@ module.exports = [
|
|
|
257
257
|
model: 'HGZB-02A',
|
|
258
258
|
vendor: 'Nue / 3A',
|
|
259
259
|
description: 'Smart light controller',
|
|
260
|
-
extend: extend.light_onoff_brightness(),
|
|
260
|
+
extend: extend.light_onoff_brightness({disablePowerOnBehavior: true}),
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
zigbeeModel: ['FNB56-ZSW01LX2.0'],
|
package/devices/philips.js
CHANGED
|
@@ -404,6 +404,13 @@ module.exports = [
|
|
|
404
404
|
description: 'Hue Iris copper special edition (generation 4) ',
|
|
405
405
|
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
406
406
|
},
|
|
407
|
+
{
|
|
408
|
+
zigbeeModel: ['929002376803'],
|
|
409
|
+
model: '929002376803',
|
|
410
|
+
vendor: 'Philips',
|
|
411
|
+
description: 'Hue Iris copper special edition (generation 4)',
|
|
412
|
+
extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
|
|
413
|
+
},
|
|
407
414
|
{
|
|
408
415
|
zigbeeModel: ['5063130P7'],
|
|
409
416
|
model: '5063130P7',
|
|
@@ -565,6 +572,13 @@ module.exports = [
|
|
|
565
572
|
description: 'Hue Go portable light',
|
|
566
573
|
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
|
|
567
574
|
},
|
|
575
|
+
{
|
|
576
|
+
zigbeeModel: ['7602031K6'],
|
|
577
|
+
model: '7602031K6',
|
|
578
|
+
vendor: 'Philips',
|
|
579
|
+
description: 'Hue Go portable light',
|
|
580
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 500]}),
|
|
581
|
+
},
|
|
568
582
|
{
|
|
569
583
|
zigbeeModel: ['LLC020'],
|
|
570
584
|
model: '7146060PH',
|
package/devices/tuya.js
CHANGED
|
@@ -2047,6 +2047,8 @@ module.exports = [
|
|
|
2047
2047
|
{modelID: 'TS0601', manufacturerName: '_TZE200_cpmgn2cf'},
|
|
2048
2048
|
{modelID: 'TS0601', manufacturerName: '_TZE200_4eeyebrt'}, // Immax 07732B
|
|
2049
2049
|
{modelID: 'TS0601', manufacturerName: '_TZE200_8whxpsiw'}, // EVOLVEO
|
|
2050
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_xby0s3ta'}, // Sandy Beach HY367
|
|
2051
|
+
{modelID: 'TS0601', manufacturerName: '_TZE200_7fqkphoq'}, // AFINTEK
|
|
2050
2052
|
],
|
|
2051
2053
|
model: 'TS0601_thermostat',
|
|
2052
2054
|
vendor: 'TuYa',
|
package/devices/ubisys.js
CHANGED
|
@@ -536,18 +536,23 @@ module.exports = [
|
|
|
536
536
|
model: 'S1',
|
|
537
537
|
vendor: 'Ubisys',
|
|
538
538
|
description: 'Power switch S1',
|
|
539
|
-
exposes: [
|
|
539
|
+
exposes: [
|
|
540
|
+
e.switch(),
|
|
540
541
|
e.action([
|
|
541
542
|
'toggle', 'on', 'off', 'recall_*',
|
|
542
543
|
'brightness_move_up', 'brightness_move_down', 'brightness_stop',
|
|
543
544
|
]),
|
|
544
|
-
e.power_on_behavior(),
|
|
545
|
+
e.power_on_behavior(),
|
|
546
|
+
e.power().withAccess(ea.STATE_GET),
|
|
547
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
548
|
+
],
|
|
545
549
|
fromZigbee: [fz.on_off, fz.metering, fz.command_toggle, fz.command_on, fz.command_off, fz.command_recall, fz.command_move,
|
|
546
550
|
fz.command_stop, fz.power_on_behavior, ubisys.fz.configure_device_setup],
|
|
547
|
-
toZigbee: [tz.on_off, tz.metering_power, ubisys.tz.configure_device_setup, tz.power_on_behavior],
|
|
551
|
+
toZigbee: [tz.on_off, tz.metering_power, tz.currentsummdelivered, ubisys.tz.configure_device_setup, tz.power_on_behavior],
|
|
548
552
|
endpoint: (device) => {
|
|
549
553
|
return {'l1': 1, 's1': 2, 'meter': 3};
|
|
550
554
|
},
|
|
555
|
+
meta: {multiEndpointEnforce: {'power': 3, 'energy': 3}},
|
|
551
556
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
552
557
|
const endpoint = device.getEndpoint(3);
|
|
553
558
|
await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
|
|
@@ -580,15 +585,20 @@ module.exports = [
|
|
|
580
585
|
model: 'S1-R',
|
|
581
586
|
vendor: 'Ubisys',
|
|
582
587
|
description: 'Power switch S1-R',
|
|
583
|
-
exposes: [
|
|
588
|
+
exposes: [
|
|
589
|
+
e.switch(),
|
|
584
590
|
e.action([
|
|
585
591
|
'toggle', 'on', 'off', 'recall_*',
|
|
586
592
|
'brightness_move_up', 'brightness_move_down', 'brightness_stop',
|
|
587
593
|
]),
|
|
588
|
-
e.power_on_behavior(),
|
|
594
|
+
e.power_on_behavior(),
|
|
595
|
+
e.power().withAccess(ea.STATE_GET),
|
|
596
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
597
|
+
],
|
|
589
598
|
fromZigbee: [fz.on_off, fz.metering, fz.command_toggle, fz.command_on, fz.command_off, fz.command_recall, fz.command_move,
|
|
590
599
|
fz.command_stop, fz.power_on_behavior, ubisys.fz.configure_device_setup],
|
|
591
|
-
toZigbee: [tz.on_off, tz.metering_power, ubisys.tz.configure_device_setup, tz.power_on_behavior],
|
|
600
|
+
toZigbee: [tz.on_off, tz.metering_power, tz.currentsummdelivered, ubisys.tz.configure_device_setup, tz.power_on_behavior],
|
|
601
|
+
meta: {multiEndpointEnforce: {'power': 4, 'energy': 4}},
|
|
592
602
|
endpoint: (device) => {
|
|
593
603
|
return {'l1': 1, 's1': 2, 'meter': 4};
|
|
594
604
|
},
|
|
@@ -625,20 +635,23 @@ module.exports = [
|
|
|
625
635
|
vendor: 'Ubisys',
|
|
626
636
|
description: 'Power switch S2',
|
|
627
637
|
exposes: [
|
|
628
|
-
e.switch().withEndpoint('l1'),
|
|
629
|
-
e.
|
|
630
|
-
e.energy(),
|
|
638
|
+
e.switch().withEndpoint('l1'),
|
|
639
|
+
e.switch().withEndpoint('l2'),
|
|
631
640
|
e.action(['toggle_s1', 'toggle_s2', 'on_s1', 'on_s2', 'off_s1', 'off_s2', 'recall_*_s1', 'recal_*_s2', 'brightness_move_up_s1',
|
|
632
641
|
'brightness_move_up_s2', 'brightness_move_down_s1', 'brightness_move_down_s2', 'brightness_stop_s1',
|
|
633
642
|
'brightness_stop_s2']),
|
|
634
|
-
e.power_on_behavior().withEndpoint('l1'),
|
|
643
|
+
e.power_on_behavior().withEndpoint('l1'),
|
|
644
|
+
e.power_on_behavior().withEndpoint('l2'),
|
|
645
|
+
e.power().withAccess(ea.STATE_GET),
|
|
646
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
647
|
+
],
|
|
635
648
|
fromZigbee: [fz.on_off, fz.metering, fz.command_toggle, fz.command_on, fz.command_off, fz.command_recall, fz.command_move,
|
|
636
649
|
fz.command_stop, fz.power_on_behavior, ubisys.fz.configure_device_setup],
|
|
637
|
-
toZigbee: [tz.on_off, tz.metering_power, ubisys.tz.configure_device_setup, tz.power_on_behavior],
|
|
650
|
+
toZigbee: [tz.on_off, tz.metering_power, ubisys.tz.configure_device_setup, tz.power_on_behavior, tz.currentsummdelivered],
|
|
638
651
|
endpoint: (device) => {
|
|
639
652
|
return {'l1': 1, 'l2': 2, 's1': 3, 's2': 4, 'meter': 5};
|
|
640
653
|
},
|
|
641
|
-
meta: {multiEndpoint: true},
|
|
654
|
+
meta: {multiEndpoint: true, multiEndpointEnforce: {'power': 5, 'energy': 5}},
|
|
642
655
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
643
656
|
const endpoint = device.getEndpoint(5);
|
|
644
657
|
await reporting.bind(endpoint, coordinatorEndpoint, ['seMetering']);
|
|
@@ -684,7 +697,7 @@ module.exports = [
|
|
|
684
697
|
ubisys.fz.dimmer_setup_genLevelCtrl, ubisys.fz.configure_device_setup],
|
|
685
698
|
toZigbee: [tz.light_onoff_brightness, tz.ballast_config, tz.level_config, ubisys.tz.dimmer_setup,
|
|
686
699
|
ubisys.tz.dimmer_setup_genLevelCtrl, ubisys.tz.configure_device_setup, tz.ignore_transition, tz.light_brightness_move,
|
|
687
|
-
tz.light_brightness_step],
|
|
700
|
+
tz.light_brightness_step, tz.metering_power, tz.currentsummdelivered],
|
|
688
701
|
exposes: [
|
|
689
702
|
e.action(['toggle_s1', 'toggle_s2', 'on_s1', 'on_s2', 'off_s1', 'off_s2', 'recall_*_s1', 'recal_*_s2', 'brightness_move_up_s1',
|
|
690
703
|
'brightness_move_up_s2', 'brightness_move_down_s1', 'brightness_move_down_s2', 'brightness_stop_s1',
|
|
@@ -704,7 +717,8 @@ module.exports = [
|
|
|
704
717
|
.withValueMin(1).withValueMax(254)
|
|
705
718
|
.withPreset('previous', 255, 'Use previous value')
|
|
706
719
|
.withDescription('Specifies the initial level to be applied after the device is supplied with power')),
|
|
707
|
-
e.power()
|
|
720
|
+
e.power().withAccess(ea.STATE_GET),
|
|
721
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
708
722
|
exposes.numeric('ballast_minimum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
709
723
|
.withDescription('Specifies the minimum light output of the ballast'),
|
|
710
724
|
exposes.numeric('ballast_maximum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
@@ -748,7 +762,7 @@ module.exports = [
|
|
|
748
762
|
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
749
763
|
await reporting.instantaneousDemand(endpoint);
|
|
750
764
|
},
|
|
751
|
-
meta: {multiEndpoint: true, multiEndpointSkip: ['state', 'brightness']},
|
|
765
|
+
meta: {multiEndpoint: true, multiEndpointSkip: ['state', 'brightness'], multiEndpointEnforce: {'power': 4, 'energy': 4}},
|
|
752
766
|
endpoint: (device) => {
|
|
753
767
|
return {'default': 1, 's1': 2, 's2': 3, 'meter': 4};
|
|
754
768
|
},
|
|
@@ -777,9 +791,13 @@ module.exports = [
|
|
|
777
791
|
description: 'Shutter control J1',
|
|
778
792
|
fromZigbee: [fz.cover_position_tilt, fz.metering, ubisys.fz.configure_device_setup],
|
|
779
793
|
toZigbee: [tz.cover_state, tz.cover_position_tilt, tz.metering_power,
|
|
780
|
-
ubisys.tz.configure_j1, ubisys.tz.configure_device_setup
|
|
781
|
-
|
|
782
|
-
|
|
794
|
+
ubisys.tz.configure_j1, ubisys.tz.configure_device_setup,
|
|
795
|
+
tz.currentsummdelivered],
|
|
796
|
+
exposes: [
|
|
797
|
+
e.cover_position_tilt(),
|
|
798
|
+
e.power().withAccess(ea.STATE_GET),
|
|
799
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
800
|
+
],
|
|
783
801
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
784
802
|
const endpoint1 = device.getEndpoint(1);
|
|
785
803
|
const endpoint3 = device.getEndpoint(3);
|
|
@@ -792,6 +810,7 @@ module.exports = [
|
|
|
792
810
|
endpoint: (device) => {
|
|
793
811
|
return {'default': 1, 'meter': 3};
|
|
794
812
|
},
|
|
813
|
+
meta: {multiEndpointEnforce: {'power': 3, 'energy': 3}},
|
|
795
814
|
onEvent: async (type, data, device) => {
|
|
796
815
|
/*
|
|
797
816
|
* As per technical doc page 21 section 7.3.4
|
package/devices/woolley.js
CHANGED
|
@@ -14,16 +14,4 @@ module.exports = [
|
|
|
14
14
|
await reporting.onOff(endpoint);
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
-
{
|
|
18
|
-
zigbeeModel: ['SA-030-1'],
|
|
19
|
-
model: 'SA-030',
|
|
20
|
-
vendor: 'Woolley',
|
|
21
|
-
description: 'Smart plug',
|
|
22
|
-
extend: extend.switch(),
|
|
23
|
-
configure: async (device, coordinatorEndpoint, logger) => {
|
|
24
|
-
const endpoint = device.getEndpoint(1);
|
|
25
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
26
|
-
await reporting.onOff(endpoint);
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
17
|
];
|
package/lib/utils.js
CHANGED
|
@@ -125,6 +125,7 @@ function postfixWithEndpointName(value, msg, definition, meta) {
|
|
|
125
125
|
meta.logger.warn(`No meta passed to postfixWithEndpointName, update your external converter!`);
|
|
126
126
|
meta = {device: null};
|
|
127
127
|
}
|
|
128
|
+
|
|
128
129
|
if (definition.meta && definition.meta.multiEndpoint &&
|
|
129
130
|
(!definition.meta.multiEndpointSkip || !definition.meta.multiEndpointSkip.includes(value))) {
|
|
130
131
|
const endpointName = definition.hasOwnProperty('endpoint') ?
|
|
@@ -137,6 +138,15 @@ function postfixWithEndpointName(value, msg, definition, meta) {
|
|
|
137
138
|
return value;
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
function enforceEndpoint(entity, key, meta) {
|
|
142
|
+
const multiEndpointEnforce = getMetaValue(entity, meta.mapped, 'multiEndpointEnforce', 'allEqual', []);
|
|
143
|
+
if (multiEndpointEnforce && multiEndpointEnforce.hasOwnProperty(key)) {
|
|
144
|
+
const endpoint = entity.getDevice().getEndpoint(multiEndpointEnforce[key]);
|
|
145
|
+
if (endpoint) return endpoint;
|
|
146
|
+
}
|
|
147
|
+
return entity;
|
|
148
|
+
}
|
|
149
|
+
|
|
140
150
|
function getKey(object, value, fallback, convertTo) {
|
|
141
151
|
for (const key in object) {
|
|
142
152
|
if (object[key]===value) {
|
|
@@ -448,6 +458,7 @@ module.exports = {
|
|
|
448
458
|
toPercentage,
|
|
449
459
|
addActionGroup,
|
|
450
460
|
postfixWithEndpointName,
|
|
461
|
+
enforceEndpoint,
|
|
451
462
|
getKey,
|
|
452
463
|
getObjectProperty,
|
|
453
464
|
batteryVoltageToPercentage,
|