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/LICENSE +1 -1
- package/README.md +14 -245
- package/io-package.json +41 -42
- package/lib/check.js +6 -0
- package/lib/colors.js +26 -6
- package/lib/deviceController.js +69 -17
- package/lib/exposes.js +89 -103
- package/lib/imageController.js +52 -3
- package/lib/messages.js +10 -0
- package/lib/mqttServerController.js +21 -5
- package/lib/nonGenericDevicesExtension.js +6 -2
- package/lib/rgb.js +81 -27
- package/lib/statesController.js +62 -11
- package/lib/utils.js +54 -7
- package/lib/websocketController.js +29 -0
- package/lib/z2mController.js +19 -0
- package/main.js +8 -10
- package/package.json +2 -6
package/lib/exposes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
|
|
15
|
-
|
|
14
|
+
* Bit 0: The property can be found in the published state of this device
|
|
15
|
+
*/
|
|
16
16
|
STATE: 1,
|
|
17
17
|
/**
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
* Bit 1: The property can be set with a /set command
|
|
19
|
+
*/
|
|
20
20
|
SET: 2,
|
|
21
21
|
/**
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* Bit 2: The property can be retrieved with a /get command
|
|
23
|
+
*/
|
|
24
24
|
GET: 4,
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
* Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
|
|
27
|
+
*/
|
|
28
28
|
STATE_SET: 3,
|
|
29
29
|
/**
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
* Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
|
|
31
|
+
*/
|
|
32
32
|
STATE_GET: 5,
|
|
33
33
|
/**
|
|
34
|
-
|
|
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)
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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)
|
|
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
|
-
|
|
796
|
-
|
|
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
|
-
|
|
805
|
-
|
|
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
|
-
|
|
814
|
-
|
|
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
|
-
|
|
822
|
-
|
|
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
|
-
|
|
856
|
-
|
|
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
|
-
|
|
886
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
966
|
-
|
|
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
|
-
|
|
975
|
-
|
|
976
|
-
|
|
982
|
+
`#${
|
|
983
|
+
utils.decimalToHex(colorval[0])
|
|
984
|
+
}${utils.decimalToHex(colorval[1])
|
|
985
|
+
}${utils.decimalToHex(colorval[2])}`
|
|
977
986
|
);
|
|
978
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
-
|
|
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)
|
|
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)
|
|
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
|
-
}
|
|
1250
|
+
}
|
|
1265
1251
|
return undefined;
|
|
1266
|
-
|
|
1252
|
+
|
|
1267
1253
|
};
|
|
1268
1254
|
} else {
|
|
1269
1255
|
state.getter = (payload) => {
|
package/lib/imageController.js
CHANGED
|
@@ -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)
|
|
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
|
-
}
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
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
|
-
`
|
|
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.
|
|
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
|
-
}
|
|
43
|
+
}
|
|
40
44
|
return [];
|
|
41
|
-
|
|
45
|
+
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
module.exports = {
|