iobroker.zigbee 1.10.2 → 1.10.11
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 +61 -20
- package/admin/adapter-settings.js +105 -18
- package/admin/admin.js +77 -45
- package/admin/i18n/de/translations.json +1 -1
- package/admin/i18n/en/translations.json +1 -1
- package/admin/i18n/fr/translations.json +1 -1
- package/admin/i18n/nl/translations.json +1 -1
- package/admin/i18n/pl/translations.json +1 -1
- package/admin/i18n/pt/translations.json +1 -1
- package/admin/img/E2204.png +0 -0
- package/admin/img/group_1.png +0 -0
- package/admin/img/group_2.png +0 -0
- package/admin/img/group_3.png +0 -0
- package/admin/img/group_4.png +0 -0
- package/admin/img/group_5.png +0 -0
- package/admin/img/group_6.png +0 -0
- package/admin/img/group_7.png +0 -0
- package/admin/img/ikea_symfonisk_remote_gen2.png +0 -0
- package/admin/img/next_track.png +0 -0
- package/admin/img/play_pause.png +0 -0
- package/admin/img/previous_track.png +0 -0
- package/admin/index_m.html +286 -32
- package/admin/tab_m.html +312 -7
- package/admin/words.js +2 -2
- package/docs/de/readme.md +15 -16
- package/docs/en/readme.md +19 -19
- package/io-package.json +112 -101
- package/lib/backup.js +1 -2
- package/lib/binding.js +28 -26
- package/lib/commands.js +79 -74
- package/lib/developer.js +6 -2
- package/lib/devices.js +14 -2
- package/lib/groups.js +1 -25
- package/lib/ota.js +2 -2
- package/lib/states.js +194 -2
- package/lib/statescontroller.js +48 -39
- package/lib/utils.js +4 -1
- package/lib/zigbeecontroller.js +76 -28
- package/main.js +61 -12
- package/package.json +17 -16
- package/support/docgen.js +3 -1
package/lib/devices.js
CHANGED
|
@@ -37,7 +37,7 @@ const comb = {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
effectJson: (state, value, options, disableQueue) => {
|
|
42
42
|
if (state.id === states.effect_json.id) {
|
|
43
43
|
const effectjson = {};
|
|
@@ -1401,7 +1401,7 @@ const devices = [
|
|
|
1401
1401
|
linkedStates: [comb.brightnessAndState],
|
|
1402
1402
|
},
|
|
1403
1403
|
{
|
|
1404
|
-
models: ['LED1536G5', 'LED1903C5/LED1835C6'],
|
|
1404
|
+
models: ['LED1536G5', 'LED1835C6', 'LED1903C5/LED1835C6'],
|
|
1405
1405
|
icon: 'img/ikea_e14_bulb.png',
|
|
1406
1406
|
states: lightStatesWithColortemp,
|
|
1407
1407
|
linkedStates: [comb.brightnessAndState],
|
|
@@ -1516,6 +1516,14 @@ const devices = [
|
|
|
1516
1516
|
states: [states.button_action_skip_back, states.button_action_skip_forward, states.action_play_pause,
|
|
1517
1517
|
states.rotate_left, states.rotate_right, states.rotate_stop, states.battery],
|
|
1518
1518
|
},
|
|
1519
|
+
{
|
|
1520
|
+
models: ['E2123'],
|
|
1521
|
+
icon: 'img/ikea_symfonisk_remote_gen2.png',
|
|
1522
|
+
states: [states.battery, states.action_play_pause, states.action_track_previous, states.action_track_next,
|
|
1523
|
+
states.action_volume_up, states.action_volume_down, states.action_volume_up_hold, states.action_volume_down_hold,
|
|
1524
|
+
states.action_dots_1_initial_press, states.action_dots_2_initial_press, states.action_dots_1_long_press, states.action_dots_2_long_press, states.action_dots_1_short_release,
|
|
1525
|
+
states.action_dots_2_short_release, states.action_dots_1_long_release, states.action_dots_2_long_release, states.action_dots_1_double_press, states.action_dots_2_double_press],
|
|
1526
|
+
},
|
|
1519
1527
|
// Hive
|
|
1520
1528
|
{
|
|
1521
1529
|
models: ['HALIGHTDIMWWE27'],
|
|
@@ -3082,6 +3090,10 @@ const devices = [
|
|
|
3082
3090
|
models: ['E1603/E1702/E1708'],
|
|
3083
3091
|
icon: 'img/ikea_control_outlet.png',
|
|
3084
3092
|
},
|
|
3093
|
+
{
|
|
3094
|
+
models: ['E2204'],
|
|
3095
|
+
icon: 'img/E2204.png',
|
|
3096
|
+
},
|
|
3085
3097
|
];
|
|
3086
3098
|
|
|
3087
3099
|
const commonStates = [
|
package/lib/groups.js
CHANGED
|
@@ -206,32 +206,8 @@ class Groups {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
async deleteGroup(from, command, message) {
|
|
209
|
-
/*
|
|
210
|
-
const members = await this.getGroupMembersFromController(parseInt(message));
|
|
211
|
-
if (members && members.length) {
|
|
212
|
-
for (const member of members) {
|
|
213
|
-
const devName = member.device.substring(2);
|
|
214
|
-
const groupEntry = this.adapter.getStateAsync(`${devName}.groups`);
|
|
215
|
-
const memberarray = (groupEntry && groupEntry.val) ? JSON.parse(groupEntry.val) : [];
|
|
216
|
-
const index = memberarray.indexOf(message.toString());
|
|
217
|
-
if (index > -1) {
|
|
218
|
-
memberarray.splice(index, 1);
|
|
219
|
-
}
|
|
220
|
-
if (memberarray.length > 0) {
|
|
221
|
-
await this.adapter.setStateAsync(`${devName}.groups`, JSON.stringify(memberarray), true);
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
await this.adapter.setStateAsync(`${devName}.groups`, '', true);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const groupsEntry = await this.adapter.getStateAsync('info.groups');
|
|
229
|
-
const objGroups = (groupsEntry && groupsEntry.val ? JSON.parse(groupsEntry.val) : {});
|
|
230
|
-
delete objGroups[message.toString()];
|
|
231
|
-
await this.adapter.setStateAsync('info.groups', JSON.stringify(objGroups), true);
|
|
232
|
-
*/
|
|
233
209
|
await this.zbController.removeGroupById(message);
|
|
234
|
-
await this.stController.
|
|
210
|
+
await this.stController.deleteGroupById(`group_${parseInt(message)}`);
|
|
235
211
|
}
|
|
236
212
|
|
|
237
213
|
async renameGroup(from, command, message) {
|
package/lib/ota.js
CHANGED
|
@@ -94,7 +94,7 @@ class Ota {
|
|
|
94
94
|
this.debug(`Checking if firmware update is available for ${device.name}`);
|
|
95
95
|
|
|
96
96
|
if (device && device.mapped.ota) {
|
|
97
|
-
const available = await device.mapped.ota.isUpdateAvailable(device.device,
|
|
97
|
+
const available = await device.mapped.ota.isUpdateAvailable(device.device, null);
|
|
98
98
|
result.status = available.available ? 'available' : 'not_available';
|
|
99
99
|
if (available.currentFileVersion !== available.otaFileVersion) {
|
|
100
100
|
this.warn(`current Firmware for ${device.name} is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
|
|
@@ -155,7 +155,7 @@ class Ota {
|
|
|
155
155
|
};
|
|
156
156
|
|
|
157
157
|
const from_ = await this.readSoftwareBuildIDAndDateCode(device.device, false);
|
|
158
|
-
await device.mapped.ota.updateToLatest(device.device,
|
|
158
|
+
const fileVersion = await device.mapped.ota.updateToLatest(device.device, onProgress);
|
|
159
159
|
const to = await this.readSoftwareBuildIDAndDateCode(device.device, true);
|
|
160
160
|
const [fromS, toS] = [JSON.stringify(from_), JSON.stringify(to)];
|
|
161
161
|
result.status = 'success';
|
package/lib/states.js
CHANGED
|
@@ -1035,8 +1035,8 @@ const states = {
|
|
|
1035
1035
|
action_play_pause: {
|
|
1036
1036
|
id: 'button_play_pause',
|
|
1037
1037
|
prop: 'action',
|
|
1038
|
-
name: 'Play/Pause
|
|
1039
|
-
icon:
|
|
1038
|
+
name: 'Play/Pause button',
|
|
1039
|
+
icon: 'img/play_pause.png',
|
|
1040
1040
|
role: 'button',
|
|
1041
1041
|
write: false,
|
|
1042
1042
|
read: true,
|
|
@@ -1044,6 +1044,198 @@ const states = {
|
|
|
1044
1044
|
isEvent: true,
|
|
1045
1045
|
getter: payload => (payload.action === 'play_pause') ? true : undefined,
|
|
1046
1046
|
},
|
|
1047
|
+
action_track_previous: {
|
|
1048
|
+
id: 'button_track_previous',
|
|
1049
|
+
prop: 'action',
|
|
1050
|
+
name: 'Previous track button',
|
|
1051
|
+
icon: 'img/previous_track.png',
|
|
1052
|
+
role: 'button',
|
|
1053
|
+
write: false,
|
|
1054
|
+
read: true,
|
|
1055
|
+
type: 'boolean',
|
|
1056
|
+
isEvent: true,
|
|
1057
|
+
getter: payload => (payload.action === 'track_previous') ? true : undefined,
|
|
1058
|
+
},
|
|
1059
|
+
action_track_next: {
|
|
1060
|
+
id: 'button_track_next',
|
|
1061
|
+
prop: 'action',
|
|
1062
|
+
name: 'Next track button',
|
|
1063
|
+
icon: 'img/next_track.png',
|
|
1064
|
+
role: 'button',
|
|
1065
|
+
write: false,
|
|
1066
|
+
read: true,
|
|
1067
|
+
type: 'boolean',
|
|
1068
|
+
isEvent: true,
|
|
1069
|
+
getter: payload => (payload.action === 'track_next') ? true : undefined,
|
|
1070
|
+
},
|
|
1071
|
+
action_volume_up: {
|
|
1072
|
+
id: 'button_volume_up',
|
|
1073
|
+
prop: 'action',
|
|
1074
|
+
name: 'Volume up button',
|
|
1075
|
+
icon: undefined,
|
|
1076
|
+
role: 'button',
|
|
1077
|
+
write: false,
|
|
1078
|
+
read: true,
|
|
1079
|
+
type: 'boolean',
|
|
1080
|
+
isEvent: true,
|
|
1081
|
+
getter: payload => (payload.action === 'volume_up') ? true : undefined,
|
|
1082
|
+
},
|
|
1083
|
+
action_volume_down: {
|
|
1084
|
+
id: 'button_volume_down',
|
|
1085
|
+
prop: 'action',
|
|
1086
|
+
name: 'Volume down button',
|
|
1087
|
+
icon: undefined,
|
|
1088
|
+
role: 'button',
|
|
1089
|
+
write: false,
|
|
1090
|
+
read: true,
|
|
1091
|
+
type: 'boolean',
|
|
1092
|
+
isEvent: true,
|
|
1093
|
+
getter: payload => (payload.action === 'volume_down') ? true : undefined,
|
|
1094
|
+
},
|
|
1095
|
+
action_volume_up_hold: {
|
|
1096
|
+
id: 'button_volume_up_hold',
|
|
1097
|
+
prop: 'action',
|
|
1098
|
+
name: 'Volume up button hold',
|
|
1099
|
+
icon: undefined,
|
|
1100
|
+
role: 'button',
|
|
1101
|
+
write: false,
|
|
1102
|
+
read: true,
|
|
1103
|
+
type: 'boolean',
|
|
1104
|
+
isEvent: true,
|
|
1105
|
+
getter: payload => (payload.action === 'volume_up_hold') ? true : undefined,
|
|
1106
|
+
},
|
|
1107
|
+
action_volume_down_hold: {
|
|
1108
|
+
id: 'button_volume_down_hold',
|
|
1109
|
+
prop: 'action',
|
|
1110
|
+
name: 'Volume down button hold',
|
|
1111
|
+
icon: undefined,
|
|
1112
|
+
role: 'button',
|
|
1113
|
+
write: false,
|
|
1114
|
+
read: true,
|
|
1115
|
+
type: 'boolean',
|
|
1116
|
+
isEvent: true,
|
|
1117
|
+
getter: payload => (payload.action === 'volume_down_hold') ? true : undefined,
|
|
1118
|
+
},
|
|
1119
|
+
action_dots_1_initial_press: {
|
|
1120
|
+
id: 'button_dots_1_initial_pressd',
|
|
1121
|
+
prop: 'action',
|
|
1122
|
+
name: 'Dot1 button press init',
|
|
1123
|
+
icon: undefined,
|
|
1124
|
+
role: 'button',
|
|
1125
|
+
write: false,
|
|
1126
|
+
read: true,
|
|
1127
|
+
type: 'boolean',
|
|
1128
|
+
isEvent: true,
|
|
1129
|
+
getter: payload => (payload.action === 'dots_1_initial_press') ? true : undefined,
|
|
1130
|
+
},
|
|
1131
|
+
action_dots_1_long_press: {
|
|
1132
|
+
id: 'button_dots_1_long_press',
|
|
1133
|
+
prop: 'action',
|
|
1134
|
+
name: 'Dot1 button long press',
|
|
1135
|
+
icon: undefined,
|
|
1136
|
+
role: 'button',
|
|
1137
|
+
write: false,
|
|
1138
|
+
read: true,
|
|
1139
|
+
type: 'boolean',
|
|
1140
|
+
isEvent: false,
|
|
1141
|
+
getter: payload => (payload.action === 'dots_1_long_press') ? true : (payload.action === 'dots_1_long_release') ? false : undefined,
|
|
1142
|
+
},
|
|
1143
|
+
action_dots_1_short_release: {
|
|
1144
|
+
id: 'dots_1_short_release',
|
|
1145
|
+
prop: 'action',
|
|
1146
|
+
name: 'Dot1 button short release',
|
|
1147
|
+
icon: undefined,
|
|
1148
|
+
role: 'button',
|
|
1149
|
+
write: false,
|
|
1150
|
+
read: true,
|
|
1151
|
+
type: 'boolean',
|
|
1152
|
+
isEvent: true,
|
|
1153
|
+
getter: payload => (payload.action === 'dots_1_short_release') ? true : undefined,
|
|
1154
|
+
},
|
|
1155
|
+
action_dots_1_long_release: {
|
|
1156
|
+
id: 'dots_1_long_release',
|
|
1157
|
+
prop: 'action',
|
|
1158
|
+
name: 'Dot1 button long release',
|
|
1159
|
+
icon: undefined,
|
|
1160
|
+
role: 'button',
|
|
1161
|
+
write: false,
|
|
1162
|
+
read: true,
|
|
1163
|
+
type: 'boolean',
|
|
1164
|
+
isEvent: true,
|
|
1165
|
+
getter: payload => (payload.action === 'dots_1_long_release') ? true : undefined,
|
|
1166
|
+
},
|
|
1167
|
+
action_dots_1_double_press: {
|
|
1168
|
+
id: 'dots_1_double_press',
|
|
1169
|
+
prop: 'action',
|
|
1170
|
+
name: 'Dot1 button double press',
|
|
1171
|
+
icon: undefined,
|
|
1172
|
+
role: 'button',
|
|
1173
|
+
write: false,
|
|
1174
|
+
read: true,
|
|
1175
|
+
type: 'boolean',
|
|
1176
|
+
isEvent: true,
|
|
1177
|
+
getter: payload => (payload.action === 'dots_1_double_press') ? true : undefined,
|
|
1178
|
+
},
|
|
1179
|
+
action_dots_2_initial_press: {
|
|
1180
|
+
id: 'button_dots_2_initial_press',
|
|
1181
|
+
prop: 'action',
|
|
1182
|
+
name: 'Dot2 button press init',
|
|
1183
|
+
icon: undefined,
|
|
1184
|
+
role: 'button',
|
|
1185
|
+
write: false,
|
|
1186
|
+
read: true,
|
|
1187
|
+
type: 'boolean',
|
|
1188
|
+
isEvent: true,
|
|
1189
|
+
getter: payload => (payload.action === 'dots_2_initial_press') ? true : undefined,
|
|
1190
|
+
},
|
|
1191
|
+
action_dots_2_long_press: {
|
|
1192
|
+
id: 'button_dots_2_long_press',
|
|
1193
|
+
prop: 'action',
|
|
1194
|
+
name: 'Dot2 button long press',
|
|
1195
|
+
icon: undefined,
|
|
1196
|
+
role: 'button',
|
|
1197
|
+
write: false,
|
|
1198
|
+
read: true,
|
|
1199
|
+
type: 'boolean',
|
|
1200
|
+
isEvent: false,
|
|
1201
|
+
getter: payload => (payload.action === 'dots_2_long_press') ? true : (payload.action === 'dots_2_long_release') ? false : undefined,
|
|
1202
|
+
},
|
|
1203
|
+
action_dots_2_short_release: {
|
|
1204
|
+
id: 'dots_2_short_release',
|
|
1205
|
+
prop: 'action',
|
|
1206
|
+
name: 'Dot2 button short release',
|
|
1207
|
+
icon: undefined,
|
|
1208
|
+
role: 'button',
|
|
1209
|
+
write: false,
|
|
1210
|
+
read: true,
|
|
1211
|
+
type: 'boolean',
|
|
1212
|
+
isEvent: true,
|
|
1213
|
+
getter: payload => (payload.action === 'dots_2_short_release') ? true : undefined,
|
|
1214
|
+
},
|
|
1215
|
+
action_dots_2_long_release: {
|
|
1216
|
+
id: 'dots_2_long_release',
|
|
1217
|
+
prop: 'action',
|
|
1218
|
+
name: 'Dot2 button long release',
|
|
1219
|
+
icon: undefined,
|
|
1220
|
+
role: 'button',
|
|
1221
|
+
write: false,
|
|
1222
|
+
read: true,
|
|
1223
|
+
type: 'boolean',
|
|
1224
|
+
isEvent: true,
|
|
1225
|
+
getter: payload => (payload.action === 'dots_2_long_release') ? true : undefined,
|
|
1226
|
+
},
|
|
1227
|
+
action_dots_2_double_press: {
|
|
1228
|
+
id: 'dots_2_double_press',
|
|
1229
|
+
prop: 'action',
|
|
1230
|
+
name: 'Dot2 button double press',
|
|
1231
|
+
icon: undefined,
|
|
1232
|
+
role: 'button',
|
|
1233
|
+
write: false,
|
|
1234
|
+
read: true,
|
|
1235
|
+
type: 'boolean',
|
|
1236
|
+
isEvent: true,
|
|
1237
|
+
getter: payload => (payload.action === 'dots_2_double_press') ? true : undefined,
|
|
1238
|
+
},
|
|
1047
1239
|
load_power: {
|
|
1048
1240
|
id: 'load_power',
|
|
1049
1241
|
prop: 'power',
|
package/lib/statescontroller.js
CHANGED
|
@@ -5,7 +5,7 @@ const statesMapping = require('./devices');
|
|
|
5
5
|
const getAdId = require('./utils').getAdId;
|
|
6
6
|
const getZbId = require('./utils').getZbId;
|
|
7
7
|
const fs = require('fs');
|
|
8
|
-
const
|
|
8
|
+
const axios = require('axios');
|
|
9
9
|
|
|
10
10
|
let savedDeviceNamesDB = {};
|
|
11
11
|
const knownUndefinedDevices = {};
|
|
@@ -78,6 +78,19 @@ class StatesController extends EventEmitter {
|
|
|
78
78
|
this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
checkDebugDevice(dev) {
|
|
82
|
+
if (typeof dev != 'string' || dev == '') return false;
|
|
83
|
+
if (this.debugDevices === undefined) {
|
|
84
|
+
this.getDebugDevices();
|
|
85
|
+
}
|
|
86
|
+
for (const addressPart of this.debugDevices) {
|
|
87
|
+
if (typeof dev === 'string' && dev.includes(addressPart)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
81
94
|
onStateChange(id, state) {
|
|
82
95
|
if (!this.adapter.zbController || !this.adapter.zbController.connected()) {
|
|
83
96
|
return;
|
|
@@ -98,12 +111,9 @@ class StatesController extends EventEmitter {
|
|
|
98
111
|
}
|
|
99
112
|
return;
|
|
100
113
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
114
|
+
|
|
115
|
+
if (this.checkDebugDevice(id)) this.warn(`ELEVATED: User stateChange ${id} ${JSON.stringify(state)}`);
|
|
116
|
+
|
|
107
117
|
this.debug(`User stateChange ${id} ${JSON.stringify(state)}`);
|
|
108
118
|
const devId = getAdId(this.adapter, id); // iobroker device id
|
|
109
119
|
let deviceId = getZbId(id); // zigbee device id
|
|
@@ -185,7 +195,7 @@ class StatesController extends EventEmitter {
|
|
|
185
195
|
knownUndefinedDevices[deviceId]++;
|
|
186
196
|
} else {
|
|
187
197
|
knownUndefinedDevices[deviceId] = 1;
|
|
188
|
-
this.
|
|
198
|
+
this.info(`Device ${deviceId} "${model}" not present in statesMapping - relying on exposes for device definition.`);
|
|
189
199
|
}
|
|
190
200
|
this.adapter.setStateAsync(`info.undefinedDevices`, JSON.stringify(knownUndefinedDevices), true);
|
|
191
201
|
states = statesMapping.commonStates;
|
|
@@ -209,14 +219,13 @@ class StatesController extends EventEmitter {
|
|
|
209
219
|
async publishFromState(deviceId, model, stateKey, state, options) {
|
|
210
220
|
if (this.debugDevices === undefined) this.getDebugDevices();
|
|
211
221
|
this.debug(`Change state '${stateKey}' at device ${deviceId} type '${model}'`);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
}
|
|
222
|
+
const elevated = this.checkDebugDevice(deviceId);
|
|
223
|
+
|
|
224
|
+
if (elevated) this.warn(`ELEVATED Change state '${stateKey}' at device ${deviceId} type '${model}'`);
|
|
225
|
+
|
|
218
226
|
const devStates = await this.getDevStates(deviceId, model);
|
|
219
227
|
if (!devStates) {
|
|
228
|
+
if (elevated) this.error(`ELEVATED no device states for device ${deviceId} type '${model}'`);
|
|
220
229
|
return;
|
|
221
230
|
}
|
|
222
231
|
const commonStates = statesMapping.commonStates.find(statedesc => stateKey === statedesc.id);
|
|
@@ -229,6 +238,7 @@ class StatesController extends EventEmitter {
|
|
|
229
238
|
|
|
230
239
|
const value = state.val;
|
|
231
240
|
if (value === undefined || value === '') {
|
|
241
|
+
if (elevated) this.error(`ELEVATED no value for device ${deviceId} type '${model}'`);
|
|
232
242
|
return;
|
|
233
243
|
}
|
|
234
244
|
let stateList = [{stateDesc: stateDesc, value: value, index: 0, timeout: 0}];
|
|
@@ -304,22 +314,22 @@ class StatesController extends EventEmitter {
|
|
|
304
314
|
states.forEach(state =>
|
|
305
315
|
this.adapter.deleteState(devId, null, state._id));
|
|
306
316
|
}
|
|
307
|
-
this.adapter.
|
|
317
|
+
this.adapter.delObject(devId, () =>
|
|
308
318
|
callback && callback());
|
|
309
319
|
});
|
|
310
320
|
}
|
|
311
321
|
|
|
312
|
-
async
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
async deleteGroupById(devId) {
|
|
323
|
+
const options = { recursive:true };
|
|
324
|
+
try {
|
|
325
|
+
this.adapter.delObject(devId,options), (err) => { }
|
|
326
|
+
|
|
327
|
+
} catch (err) {
|
|
328
|
+
this.adapter.log.info(`Cannot delete Group ${devId}: ${err}`);
|
|
318
329
|
}
|
|
319
|
-
await this.adapter.deleteDevice(devId);
|
|
320
330
|
}
|
|
321
331
|
|
|
322
|
-
|
|
332
|
+
|
|
323
333
|
async deleteOrphanedDeviceStates(ieeeAddr, model, force, callback) {
|
|
324
334
|
const devStates = await this.getDevStates(ieeeAddr, model);
|
|
325
335
|
const commonStates = statesMapping.commonStates;
|
|
@@ -540,15 +550,17 @@ class StatesController extends EventEmitter {
|
|
|
540
550
|
async downloadIcon(url, image_path) {
|
|
541
551
|
if (!fs.existsSync(image_path)) {
|
|
542
552
|
return new Promise((resolve, reject) => {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
553
|
+
axios({
|
|
554
|
+
method: 'get',
|
|
555
|
+
url: url,
|
|
556
|
+
responseType: 'stream' // Dies ist wichtig, um den Stream direkt zu erhalten
|
|
557
|
+
}).then(response => {
|
|
558
|
+
const writer = fs.createWriteStream(image_path);
|
|
559
|
+
response.data.pipe(writer);
|
|
560
|
+
writer.on('finish', resolve);
|
|
561
|
+
writer.on('error', reject);
|
|
562
|
+
}).catch(err => {
|
|
563
|
+
reject(err);
|
|
552
564
|
});
|
|
553
565
|
});
|
|
554
566
|
}
|
|
@@ -608,18 +620,15 @@ class StatesController extends EventEmitter {
|
|
|
608
620
|
const devStates = await this.getDevStates(`0x${devId}`, model);
|
|
609
621
|
let has_debug = false;
|
|
610
622
|
if (this.debugDevices === undefined) this.getDebugDevices();
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
break;
|
|
615
|
-
}
|
|
616
|
-
|
|
623
|
+
if (this.checkDebugDevice(devId))
|
|
624
|
+
{
|
|
625
|
+
if (!payload.hasOwnProperty('msg_from_zigbee')) {
|
|
617
626
|
this.warn(`ELEVATED publishToState: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`);
|
|
618
627
|
has_debug = true;
|
|
619
|
-
break;
|
|
620
628
|
}
|
|
621
629
|
}
|
|
622
630
|
if (!devStates) {
|
|
631
|
+
if (has_debug) this.error(`ELEVATED publishToState: no device states for device ${devId} type '${model}'`)
|
|
623
632
|
return;
|
|
624
633
|
}
|
|
625
634
|
// find states for payload
|
package/lib/utils.js
CHANGED
|
@@ -127,8 +127,11 @@ function getDeviceIcon(definition) {
|
|
|
127
127
|
if (icon) {
|
|
128
128
|
icon = icon.replace('${model}', sanitizeImageParameter(definition.model));
|
|
129
129
|
}
|
|
130
|
+
// if (!icon) {
|
|
131
|
+
// icon = `https://www.zigbee2mqtt.io/images/devices/${sanitizeImageParameter(definition.model)}.jpg`;
|
|
132
|
+
// }
|
|
130
133
|
if (!icon) {
|
|
131
|
-
icon = `https://www.zigbee2mqtt.io/images/devices/${sanitizeImageParameter(definition.model)}.
|
|
134
|
+
icon = `https://www.zigbee2mqtt.io/images/devices/${sanitizeImageParameter(definition.model)}.png`;
|
|
132
135
|
}
|
|
133
136
|
return icon;
|
|
134
137
|
}
|
package/lib/zigbeecontroller.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const pathLib = require('path');
|
|
4
4
|
const ZigbeeHerdsman = require('zigbee-herdsman');
|
|
5
5
|
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
|
6
|
+
const ZDO = require('zigbee-herdsman/dist/zspec/zdo');
|
|
6
7
|
const zigbeeHerdsmanConvertersPhilips = require('zigbee-herdsman-converters/lib/philips');
|
|
7
8
|
const EventEmitter = require('events').EventEmitter;
|
|
8
9
|
const safeJsonStringify = require('./json');
|
|
@@ -11,6 +12,7 @@ const DeviceConfigureExt = require('./zbDeviceConfigure');
|
|
|
11
12
|
const DeviceEventExt = require('./zbDeviceEvent');
|
|
12
13
|
const DelayedActionExt = require('./zbDelayedAction');
|
|
13
14
|
const utils = require('./utils');
|
|
15
|
+
const { waitForDebugger } = require('inspector');
|
|
14
16
|
const groupConverters = [
|
|
15
17
|
zigbeeHerdsmanConverters.toZigbee.light_onoff_brightness,
|
|
16
18
|
zigbeeHerdsmanConverters.toZigbee.light_color_colortemp,
|
|
@@ -301,9 +303,9 @@ class ZigbeeController extends EventEmitter {
|
|
|
301
303
|
}
|
|
302
304
|
|
|
303
305
|
async removeGroupById(id) {
|
|
304
|
-
const group = await this.getGroupByID(id);
|
|
306
|
+
const group = await this.getGroupByID(Number(id));
|
|
305
307
|
try {
|
|
306
|
-
group && group.
|
|
308
|
+
group && group.removeFromNetwork();
|
|
307
309
|
} catch (error) {
|
|
308
310
|
this.sendError(error);
|
|
309
311
|
this.error(`error in removeGroupById: ${error}`);
|
|
@@ -505,7 +507,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
505
507
|
if (isFunction(devid) && !isFunction(failure)) {
|
|
506
508
|
failure = devid;
|
|
507
509
|
} else {
|
|
508
|
-
|
|
510
|
+
if (devid != '') {
|
|
511
|
+
permitDev = this.getDevice(devid);
|
|
512
|
+
} else {
|
|
513
|
+
permitDev = '';
|
|
514
|
+
}
|
|
509
515
|
}
|
|
510
516
|
|
|
511
517
|
if (permitTime) {
|
|
@@ -518,7 +524,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
518
524
|
if (permitTime && !this.herdsman.getPermitJoin()) {
|
|
519
525
|
clearInterval(this._permitJoinInterval);
|
|
520
526
|
this._permitJoinTime = permitTime;
|
|
521
|
-
await this.herdsman.permitJoin(true, permitDev);
|
|
527
|
+
await this.herdsman.permitJoin(true, permitDev, this._permitJoinTime);
|
|
522
528
|
this._permitJoinInterval = setInterval(async () => {
|
|
523
529
|
this.emit('pairing', 'Pairing time left', this._permitJoinTime);
|
|
524
530
|
if (this._permitJoinTime === 0) {
|
|
@@ -548,7 +554,8 @@ class ZigbeeController extends EventEmitter {
|
|
|
548
554
|
const device = await this.herdsman.getDeviceByIeeeAddr(deviceID);
|
|
549
555
|
if (device) {
|
|
550
556
|
try {
|
|
551
|
-
await
|
|
557
|
+
await device.removeFromNetwork();
|
|
558
|
+
//this.herdsman.adapter.removeDevice(device.networkAddress, device.ieeeAddr);
|
|
552
559
|
} catch (error) {
|
|
553
560
|
this.sendError(error);
|
|
554
561
|
if (error)
|
|
@@ -810,20 +817,25 @@ class ZigbeeController extends EventEmitter {
|
|
|
810
817
|
|
|
811
818
|
if (type === 'foundation') {
|
|
812
819
|
cfg.disableDefaultResponse = true;
|
|
820
|
+
|
|
813
821
|
if (cmd === 'read' && !Array.isArray(zclData)) {
|
|
814
|
-
// needs to be iterable (string[] | number [])
|
|
822
|
+
/* // needs to be iterable (string[] | number [])
|
|
815
823
|
zclData[Symbol.iterator] = function* () {
|
|
816
824
|
let k;
|
|
817
825
|
for (k in this) {
|
|
818
826
|
yield k;
|
|
819
827
|
}
|
|
820
828
|
};
|
|
829
|
+
*/
|
|
821
830
|
}
|
|
822
831
|
let result;
|
|
823
832
|
if (cmd === 'configReport') {
|
|
824
833
|
result = await endpoint.configureReporting(cid, zclData, cfg);
|
|
825
834
|
} else {
|
|
826
|
-
|
|
835
|
+
if (cmd === 'read' && !Array.isArray(zclData))
|
|
836
|
+
result = await endpoint[cmd](cid, Object.keys(zclData), cfg);
|
|
837
|
+
else
|
|
838
|
+
result = await endpoint[cmd](cid, zclData, cfg);
|
|
827
839
|
}
|
|
828
840
|
callback && callback(undefined, result);
|
|
829
841
|
} else if (type === 'functionalResp') {
|
|
@@ -995,27 +1007,63 @@ class ZigbeeController extends EventEmitter {
|
|
|
995
1007
|
}
|
|
996
1008
|
|
|
997
1009
|
async getChannelsEnergy() {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1010
|
+
/*
|
|
1011
|
+
const BLANK_EUI64 = "0xFFFFFFFFFFFFFFFF";
|
|
1012
|
+
const SLEEPY = 0xffff;
|
|
1013
|
+
|
|
1014
|
+
let clusterId = ZDO.ClusterId.NWK_UPDATE_REQUEST;
|
|
1015
|
+
|
|
1016
|
+
//for (let i=26;i>0;i--)
|
|
1017
|
+
{
|
|
1018
|
+
try
|
|
1019
|
+
{
|
|
1020
|
+
let result = {};
|
|
1021
|
+
let payload = ZDO.Buffalo.buildRequest(false, clusterId, [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26], 0x05, undefined, 0, undefined);
|
|
1022
|
+
this.warn(`Payload is [${JSON.stringify(payload)}]`);
|
|
1023
|
+
result = await this.herdsman.adapter.sendZdo(0x0, 0x0, clusterId , payload, false);
|
|
1024
|
+
this.warn(`result is ${JSON.stringify(result)}`)
|
|
1025
|
+
//await this.Wait(5000);
|
|
1026
|
+
|
|
1027
|
+
//let payload1 = ZDO.Buffalo.buildRequest(true, clusterId, [16,17,18,19,20], 0x5, undefined, 0, undefined);
|
|
1028
|
+
//result = await this.herdsman.adapter.sendZdo(0x0, 0x0, clusterId , payload1, false);
|
|
1029
|
+
//this.warn(`result 2 is ${JSON.stringify(result)}`)
|
|
1030
|
+
//await this.Wait(5000);
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
//let payload2 = ZDO.Buffalo.buildRequest(true, clusterId, [21,22,23,24,25], 0x5, undefined, 0, undefined);
|
|
1034
|
+
//result = await this.herdsman.adapter.sendZdo(0x0, 0x0, clusterId , payload2, false);
|
|
1035
|
+
//this.warn(`result 3 is ${JSON.stringify(result)}`)
|
|
1036
|
+
/* const payload = {
|
|
1037
|
+
dstaddr: 0x0,
|
|
1038
|
+
dstaddrmode: 0x02,
|
|
1039
|
+
channelmask: 0x07FFF800,
|
|
1040
|
+
scanduration: 0x5,
|
|
1041
|
+
scancount: 1,
|
|
1042
|
+
nwkmanageraddr: 0x0000
|
|
1043
|
+
};
|
|
1044
|
+
const energyScan = this.herdsman.adapter.znp.waitFor(
|
|
1045
|
+
2, // unpi_1.Constants.Type.AREQ,
|
|
1046
|
+
5, // Subsystem.ZDO,
|
|
1047
|
+
'mgmtNwkUpdateNotify'
|
|
1048
|
+
);
|
|
1049
|
+
await this.herdsman.adapter.znp.request(
|
|
1050
|
+
0x5, // Subsystem.ZDO
|
|
1051
|
+
'mgmtNwkUpdateReq',
|
|
1052
|
+
payload,
|
|
1053
|
+
energyScan.ID
|
|
1054
|
+
);
|
|
1055
|
+
const result = await energyScan.start().promise;
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
//return result.payload;
|
|
1059
|
+
}
|
|
1060
|
+
catch (error) {
|
|
1061
|
+
this.sendError(error);
|
|
1062
|
+
this.error(`Failed to touchlinkReset ${error.stack}`);
|
|
1063
|
+
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
*/
|
|
1019
1067
|
}
|
|
1020
1068
|
}
|
|
1021
1069
|
|