iobroker.zigbee2mqtt 3.0.10 → 3.0.13

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/lib/exposes.js CHANGED
@@ -1,5 +1,5 @@
1
- /* eslint-disable no-prototype-builtins */
2
- // @ts-nocheck
1
+
2
+
3
3
  'use strict';
4
4
 
5
5
  const statesDefs = require('./states').states;
@@ -11,28 +11,28 @@ const getNonGenDevStatesDefs = require('./nonGenericDevicesExtension').getStateD
11
11
  // https://www.zigbee2mqtt.io/guide/usage/exposes.html#access
12
12
  const z2mAccess = {
13
13
  /**
14
- * Bit 0: The property can be found in the published state of this device
15
- */
14
+ * Bit 0: The property can be found in the published state of this device
15
+ */
16
16
  STATE: 1,
17
17
  /**
18
- * Bit 1: The property can be set with a /set command
19
- */
18
+ * Bit 1: The property can be set with a /set command
19
+ */
20
20
  SET: 2,
21
21
  /**
22
- * Bit 2: The property can be retrieved with a /get command
23
- */
22
+ * Bit 2: The property can be retrieved with a /get command
23
+ */
24
24
  GET: 4,
25
25
  /**
26
- * Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
27
- */
26
+ * Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
27
+ */
28
28
  STATE_SET: 3,
29
29
  /**
30
- * Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
31
- */
30
+ * Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
31
+ */
32
32
  STATE_GET: 5,
33
33
  /**
34
- * Bitwise inclusive OR of STATE and GET and SET : 0b001 | 0b100 | 0b010
35
- */
34
+ * Bitwise inclusive OR of STATE and GET and SET : 0b001 | 0b100 | 0b010
35
+ */
36
36
  ALL: 7,
37
37
  };
38
38
 
@@ -174,6 +174,11 @@ function genState(expose, role, name, desc) {
174
174
  return state;
175
175
  }
176
176
 
177
+ /**
178
+ *
179
+ * @param devicesMessag
180
+ * @param adapter
181
+ */
177
182
  async function createDeviceFromExposes(devicesMessag, adapter) {
178
183
  const states = [];
179
184
  let scenes = [];
@@ -189,7 +194,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
189
194
  if (state === undefined) {
190
195
  return 0;
191
196
  }
192
- if (access === undefined) access = z2mAccess.ALL;
197
+ if (access === undefined) {
198
+ access = z2mAccess.ALL;
199
+ }
193
200
  state.readable = (access & z2mAccess.STATE) > 0;
194
201
  state.writable = (access & z2mAccess.SET) > 0;
195
202
  const stateExists = states.findIndex((x, _index, _array) => x.id === state.id);
@@ -214,7 +221,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
214
221
  }
215
222
 
216
223
  return states.push(state);
217
- } else {
224
+ }
218
225
  if (state.readable && !states[stateExists].readable) {
219
226
  states[stateExists].read = state.read;
220
227
  // as state is readable, it can't be button or event
@@ -294,7 +301,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
294
301
  }
295
302
 
296
303
  return states.length;
297
- }
304
+
298
305
  }
299
306
 
300
307
  // search for scenes in the endpoints and build them into an array
@@ -461,9 +468,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
461
468
  }
462
469
  if (config.useKelvin == true) {
463
470
  return utils.miredKelvinConversion(payload[propName]);
464
- } else {
471
+ }
465
472
  return payload[propName];
466
- }
473
+
467
474
  },
468
475
  },
469
476
  prop.access
@@ -519,9 +526,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
519
526
  //}
520
527
  if (config.useKelvin == true) {
521
528
  return utils.miredKelvinConversion(payload[propName]);
522
- } else {
529
+ }
523
530
  return payload[propName];
524
- }
531
+
525
532
  },
526
533
  },
527
534
  prop.access
@@ -566,14 +573,14 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
566
573
  payload[stateName].y
567
574
  );
568
575
  return (
569
- '#' +
570
- utils.decimalToHex(colorval[0]) +
571
- utils.decimalToHex(colorval[1]) +
572
- utils.decimalToHex(colorval[2])
576
+ `#${
577
+ utils.decimalToHex(colorval[0])
578
+ }${utils.decimalToHex(colorval[1])
579
+ }${utils.decimalToHex(colorval[2])}`
573
580
  );
574
- } else {
581
+ }
575
582
  return undefined;
576
- }
583
+
577
584
  },
578
585
  epname: expose.endpoint,
579
586
  },
@@ -635,10 +642,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
635
642
  payload[stateName].y
636
643
  );
637
644
  return (
638
- '#' +
639
- utils.decimalToHex(colorval[0]) +
640
- utils.decimalToHex(colorval[1]) +
641
- utils.decimalToHex(colorval[2])
645
+ `#${
646
+ utils.decimalToHex(colorval[0])
647
+ }${utils.decimalToHex(colorval[1])
648
+ }${utils.decimalToHex(colorval[2])}`
642
649
  );
643
650
  }
644
651
  return undefined;
@@ -749,12 +756,19 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
749
756
  break;
750
757
  }
751
758
  }
752
- if (state) pushToStates(state, expose.access);
759
+ if (state) {
760
+ pushToStates(state, expose.access);
761
+ }
753
762
  break;
754
763
 
755
- case 'enum':
764
+ case 'enum': {
756
765
  switch (expose.name) {
757
766
  case 'action': {
767
+ //generate an 'action' state\
768
+ state = genState(expose);
769
+ state.isEvent = true;
770
+ pushToStates(state, expose.access);
771
+
758
772
  if (!Array.isArray(expose.values)) {
759
773
  break;
760
774
  }
@@ -792,8 +806,8 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
792
806
  // is release -> hold state? - skip
793
807
  if (
794
808
  config.simpleHoldReleaseState == true &&
795
- actionName.endsWith('release') &&
796
- expose.values.find((x) => x == actionName.replace('release', 'hold'))
809
+ actionName.endsWith('release') &&
810
+ expose.values.find((x) => x == actionName.replace('release', 'hold'))
797
811
  ) {
798
812
  continue;
799
813
  }
@@ -801,8 +815,8 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
801
815
  // is stop - move state? - skip
802
816
  if (
803
817
  config.simpleMoveStopState == true &&
804
- actionName.endsWith('stop') &&
805
- expose.values.find((x) => x.includes(actionName.replace('stop', 'move')))
818
+ actionName.endsWith('stop') &&
819
+ expose.values.find((x) => x.includes(actionName.replace('stop', 'move')))
806
820
  ) {
807
821
  continue;
808
822
  }
@@ -810,17 +824,16 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
810
824
  // is release -> press state? - skip
811
825
  if (
812
826
  config.simplePressReleaseState == true &&
813
- actionName.endsWith('release') &&
814
- expose.values.find((x) => x == actionName.replace('release', 'press'))
827
+ actionName.endsWith('release') &&
828
+ expose.values.find((x) => x == actionName.replace('release', 'press'))
815
829
  ) {
816
830
  continue;
817
831
  }
818
832
 
819
833
  // is hold -> release state ?
820
- if (
821
- config.simpleHoldReleaseState == true &&
822
- actionName.endsWith('hold') &&
823
- expose.values.find((x) => x == actionName.replace('hold', 'release'))
834
+ if (config.simpleHoldReleaseState == true &&
835
+ actionName.endsWith('hold') &&
836
+ expose.values.find((x) => x == actionName.replace('hold', 'release'))
824
837
  ) {
825
838
  pushToStates(
826
839
  {
@@ -848,12 +861,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
848
861
  },
849
862
  expose.access
850
863
  );
851
- }
852
- // is move -> stop state ?
853
- else if (
864
+ } else if ( // is move -> stop state ?
854
865
  config.simpleMoveStopState == true &&
855
- actionName.includes('move') &&
856
- expose.values.find((x) => x == `${actionName.split('_')[0]}_stop`)
866
+ actionName.includes('move') &&
867
+ expose.values.find((x) => x == `${actionName.split('_')[0]}_stop`)
857
868
  ) {
858
869
  pushToStates(
859
870
  {
@@ -878,12 +889,10 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
878
889
  },
879
890
  expose.access
880
891
  );
881
- }
882
- // is press -> release state ?
883
- else if (
892
+ } else if ( // is press -> release state ?
884
893
  config.simplePressReleaseState == true &&
885
- actionName.endsWith('press') &&
886
- expose.values.find((x) => x == actionName.replace('press', 'release'))
894
+ actionName.endsWith('press') &&
895
+ expose.values.find((x) => x == actionName.replace('press', 'release'))
887
896
  ) {
888
897
  pushToStates(
889
898
  {
@@ -934,9 +943,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
934
943
  return utils.miredKelvinConversion(
935
944
  payload.action_color_temperature
936
945
  );
937
- } else {
946
+ }
938
947
  return payload.action_color_temperature;
939
- }
948
+
940
949
  }
941
950
  },
942
951
  },
@@ -962,22 +971,22 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
962
971
 
963
972
  if (
964
973
  payload.action_color &&
965
- payload.action_color.hasOwnProperty('x') &&
966
- payload.action_color.hasOwnProperty('y')
974
+ payload.action_color.hasOwnProperty('x') &&
975
+ payload.action_color.hasOwnProperty('y')
967
976
  ) {
968
977
  const colorval = rgb.cie_to_rgb(
969
978
  payload.action_color.x,
970
979
  payload.action_color.y
971
980
  );
972
981
  return (
973
- '#' +
974
- utils.decimalToHex(colorval[0]) +
975
- utils.decimalToHex(colorval[1]) +
976
- utils.decimalToHex(colorval[2])
982
+ `#${
983
+ utils.decimalToHex(colorval[0])
984
+ }${utils.decimalToHex(colorval[1])
985
+ }${utils.decimalToHex(colorval[2])}`
977
986
  );
978
- } else {
987
+ }
979
988
  return undefined;
980
- }
989
+
981
990
  },
982
991
  },
983
992
  expose.access
@@ -1004,9 +1013,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1004
1013
 
1005
1014
  if (payload.action_level) {
1006
1015
  return utils.bulbLevelToAdapterLevel(payload.action_level);
1007
- } else {
1016
+ }
1008
1017
  return undefined;
1009
- }
1018
+
1010
1019
  },
1011
1020
  },
1012
1021
  expose.access
@@ -1032,9 +1041,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1032
1041
 
1033
1042
  if (payload.action_level) {
1034
1043
  return payload.action_saturation;
1035
- } else {
1044
+ }
1036
1045
  return undefined;
1037
- }
1046
+
1038
1047
  },
1039
1048
  },
1040
1049
  expose.access
@@ -1061,41 +1070,14 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1061
1070
 
1062
1071
  if (payload.action_enhanced_hue) {
1063
1072
  return payload.action_enhanced_hue;
1064
- } else {
1073
+ }
1065
1074
  return undefined;
1066
- }
1075
+
1067
1076
  },
1068
1077
  },
1069
1078
  expose.access
1070
1079
  );
1071
- }
1072
- // else if (actionName == 'hue_move') {
1073
- // pushToStates({
1074
- // id: 'hue_move',
1075
- // name: 'Hue move rate',
1076
- // icon: undefined,
1077
- // role: 'level.color.hue',
1078
- // write: false,
1079
- // read: true,
1080
- // type: 'number',
1081
- // min: 0,
1082
- // max: 360,
1083
- // def: 0,
1084
- // isEvent: true,
1085
- // getter: (payload) => {
1086
- // if (payload.action != 'hue_move') {
1087
- // return undefined;
1088
- // }
1089
-
1090
- // if (payload.action_level) {
1091
- // return payload.action_level;
1092
- // } else {
1093
- // return undefined;
1094
- // }
1095
- // }
1096
- // }, expose.access);
1097
- // }
1098
- else {
1080
+ } else {
1099
1081
  pushToStates(
1100
1082
  {
1101
1083
  id: actionName.replace(/\*/g, ''),
@@ -1117,7 +1099,7 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1117
1099
  // Can the device simulated_brightness?
1118
1100
  if (
1119
1101
  definition.options &&
1120
- definition.options.find((x) => x.property == 'simulated_brightness')
1102
+ definition.options.find((x) => x.property == 'simulated_brightness')
1121
1103
  ) {
1122
1104
  pushToStates(statesDefs.simulated_brightness, z2mAccess.STATE);
1123
1105
  }
@@ -1128,9 +1110,11 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1128
1110
  state = genState(expose);
1129
1111
  break;
1130
1112
  }
1131
- if (state) pushToStates(state, expose.access);
1113
+ if (state) {
1114
+ pushToStates(state, expose.access);
1115
+ }
1132
1116
  break;
1133
-
1117
+ }
1134
1118
  case 'binary':
1135
1119
  if (expose.endpoint) {
1136
1120
  state = genState(expose);
@@ -1166,7 +1150,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1166
1150
  break;
1167
1151
  }
1168
1152
  }
1169
- if (state) pushToStates(state, expose.access);
1153
+ if (state) {
1154
+ pushToStates(state, expose.access);
1155
+ }
1170
1156
  break;
1171
1157
 
1172
1158
  case 'text':
@@ -1261,9 +1247,9 @@ async function createDeviceFromExposes(devicesMessag, adapter) {
1261
1247
  return !isNaN(payload[expose.property][prop.property])
1262
1248
  ? payload[expose.property][prop.property]
1263
1249
  : undefined;
1264
- } else {
1250
+ }
1265
1251
  return undefined;
1266
- }
1252
+
1267
1253
  };
1268
1254
  } else {
1269
1255
  state.getter = (payload) => {
@@ -1,23 +1,42 @@
1
1
  const axios = require('axios').default;
2
2
  const sharp = require('sharp');
3
3
 
4
+ /**
5
+ *
6
+ */
4
7
  class ImageController {
8
+ /**
9
+ *
10
+ * @param adapter
11
+ */
5
12
  constructor(adapter) {
6
13
  this.adapter = adapter;
7
14
  }
8
15
 
16
+ /**
17
+ *
18
+ * @param modelName
19
+ */
9
20
  sanitizeModelIDForImageUrl(modelName) {
10
21
  const modelNameString = modelName.replace('/', '_');
11
22
  // eslint-disable-next-line no-control-regex
12
23
  return modelNameString.replace(/\u0000/g, '');
13
24
  }
14
25
 
26
+ /**
27
+ *
28
+ * @param deviceName
29
+ */
15
30
  sanitizeZ2MDeviceName(deviceName) {
16
31
  const deviceNameString = deviceName.replace(/:|\s|\//g, '-');
17
32
  // eslint-disable-next-line no-control-regex
18
33
  return deviceName ? deviceNameString.replace(/\u0000/g, '') : 'NA';
19
34
  }
20
35
 
36
+ /**
37
+ *
38
+ * @param device
39
+ */
21
40
  getZ2mDeviceImageModelJPG(device) {
22
41
  if (device && device.definition && device.definition.model) {
23
42
  const icoString = `https://www.zigbee2mqtt.io/images/devices/${this.sanitizeZ2MDeviceName(device.definition.model)}.jpg`;
@@ -26,6 +45,10 @@ class ImageController {
26
45
  }
27
46
  }
28
47
 
48
+ /**
49
+ *
50
+ * @param device
51
+ */
29
52
  getZ2mDeviceImageModelPNG(device) {
30
53
  if (device && device.definition && device.definition.model) {
31
54
  const icoString = `https://www.zigbee2mqtt.io/images/devices/${this.sanitizeZ2MDeviceName(device.definition.model)}.png`;
@@ -35,6 +58,10 @@ class ImageController {
35
58
  }
36
59
 
37
60
 
61
+ /**
62
+ *
63
+ * @param device
64
+ */
38
65
  getSlsDeviceImage(device) {
39
66
  if (device && device.model_id) {
40
67
  const icoString = `https://www.zigbee2mqtt.io/images/devices/${this.sanitizeModelIDForImageUrl(device.model_id)}.png`;
@@ -43,8 +70,14 @@ class ImageController {
43
70
  }
44
71
  }
45
72
 
73
+ /**
74
+ *
75
+ * @param device
76
+ */
46
77
  async getDeviceIcon(device) {
47
- if (!this.adapter.config.useDeviceIcons) return '';
78
+ if (!this.adapter.config.useDeviceIcons) {
79
+ return '';
80
+ }
48
81
 
49
82
  const imageSize = this.adapter.config.deviceIconsSize;
50
83
 
@@ -78,7 +111,7 @@ class ImageController {
78
111
  if (!iconFound) {
79
112
  this.adapter.log.warn(`Failed to download image for device model: ${device.definition.model} - ${device.definition.description}`);
80
113
  return '';
81
- } else {
114
+ }
82
115
  // Load image from the Meta-Store
83
116
  const icon = await this.adapter.readFileAsync(this.adapter.namespace, iconFileName);
84
117
  // Load Image Metadata
@@ -106,8 +139,12 @@ class ImageController {
106
139
 
107
140
  // Create and output Base64
108
141
  return `data:image/png;base64,${icon.file.toString('base64')}`;
109
- }
142
+
110
143
  }
144
+ /**
145
+ *
146
+ * @param url
147
+ */
111
148
  getFileNameWithExtension(url) {
112
149
  const path = new URL(url).pathname;
113
150
  const filename = path.split('/').pop();
@@ -115,6 +152,12 @@ class ImageController {
115
152
  return filename.replace(/\u0000/g, '');
116
153
  }
117
154
 
155
+ /**
156
+ *
157
+ * @param adapter
158
+ * @param url
159
+ * @param namespace
160
+ */
118
161
  async downloadIcon(adapter, url, namespace) {
119
162
  try {
120
163
  const res = await axios.get(url, { responseType: 'arraybuffer' });
@@ -125,6 +168,12 @@ class ImageController {
125
168
  return false;
126
169
  }
127
170
  }
171
+ /**
172
+ *
173
+ * @param z2mIconFileNameJPG
174
+ * @param z2mIconFileNamePNG
175
+ * @param slsIconFileName
176
+ */
128
177
  async getExistingIconFileName(z2mIconFileNameJPG, z2mIconFileNamePNG, slsIconFileName) {
129
178
  if (await this.adapter.fileExistsAsync(this.adapter.namespace, z2mIconFileNameJPG)) {
130
179
  return z2mIconFileNameJPG;
package/lib/messages.js CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ *
3
+ * @param config
4
+ * @param log
5
+ */
1
6
  async function adapterInfo(config, log) {
2
7
  log.info('================================= Adapter Config =================================');
3
8
  log.info(`|| Zigbee2MQTT Frontend Scheme: ${config.webUIScheme}`);
@@ -41,6 +46,11 @@ async function adapterInfo(config, log) {
41
46
  log.info('==================================================================================');
42
47
  }
43
48
 
49
+ /**
50
+ *
51
+ * @param payload
52
+ * @param log
53
+ */
44
54
  async function zigbee2mqttInfo(payload, log) {
45
55
  log.info('============================ Zigbee2MQTT Information =============================');
46
56
  log.info(`|| Zigbee2MQTT Version: ${payload.version} `);
@@ -3,11 +3,21 @@ const Aedes = require('aedes');
3
3
  const net = require('net');
4
4
  let mqttServer;
5
5
 
6
+ /**
7
+ *
8
+ */
6
9
  class MqttServerController {
10
+ /**
11
+ *
12
+ * @param adapter
13
+ */
7
14
  constructor(adapter) {
8
15
  this.adapter = adapter;
9
16
  }
10
17
 
18
+ /**
19
+ *
20
+ */
11
21
  async createMQTTServer() {
12
22
  try {
13
23
  const NedbPersistence = require('aedes-persistence-nedb');
@@ -15,12 +25,12 @@ class MqttServerController {
15
25
  path: `${core.getAbsoluteInstanceDataDir(this.adapter)}/mqttData`,
16
26
  prefix: '',
17
27
  });
18
- // @ts-ignore
28
+
19
29
  const aedes = Aedes({ persistence: db });
20
30
  mqttServer = net.createServer(aedes.handle);
21
31
  mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
22
32
  this.adapter.log.info(
23
- `Statring MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
33
+ `Starting MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
24
34
  );
25
35
  });
26
36
  } catch (err) {
@@ -28,14 +38,17 @@ class MqttServerController {
28
38
  }
29
39
  }
30
40
 
41
+ /**
42
+ *
43
+ */
31
44
  async createDummyMQTTServer() {
32
45
  try {
33
- // @ts-ignore
46
+
34
47
  const aedes = Aedes();
35
48
  mqttServer = net.createServer(aedes.handle);
36
49
  mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
37
50
  this.adapter.log.info(
38
- `Statring DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
51
+ `Starting DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
39
52
  );
40
53
  });
41
54
  } catch (err) {
@@ -43,8 +56,11 @@ class MqttServerController {
43
56
  }
44
57
  }
45
58
 
59
+ /**
60
+ *
61
+ */
46
62
  closeServer() {
47
- if (mqttServer && !mqttServer.closed()) {
63
+ if (mqttServer && !mqttServer.close()) {
48
64
  mqttServer.close();
49
65
  }
50
66
  }
@@ -32,13 +32,17 @@ const nonGenDevStatesDefs = {
32
32
  ],
33
33
  };
34
34
 
35
+ /**
36
+ *
37
+ * @param model
38
+ */
35
39
  function getStateDefinition(model) {
36
40
  const stateDef = nonGenDevStatesDefs[model];
37
41
  if (stateDef) {
38
42
  return stateDef;
39
- } else {
43
+ }
40
44
  return [];
41
- }
45
+
42
46
  }
43
47
 
44
48
  module.exports = {