iobroker.zigbee 3.0.0 → 3.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 +23 -12
- package/admin/admin.js +140 -14
- package/admin/img/channel_scan.png +0 -0
- package/admin/img/nvram_delete.png +0 -0
- package/admin/img/nvram_read.png +0 -0
- package/admin/img/reset.png +0 -0
- package/admin/img/start_stop.png +0 -0
- package/admin/img/test_port.png +0 -0
- package/admin/index_m.html +133 -121
- package/admin/tab_m.html +101 -88
- package/docs/de/readme.md +7 -3
- package/docs/en/readme.md +7 -12
- package/io-package.json +28 -27
- package/lib/commands.js +40 -9
- package/lib/groups.js +1 -1
- package/lib/localConfig.js +31 -8
- package/lib/networkmap.js +2 -1
- package/lib/statescontroller.js +60 -58
- package/lib/zbDeviceConfigure.js +1 -1
- package/lib/zigbeecontroller.js +12 -1
- package/main.js +10 -4
- package/package.json +8 -8
package/lib/networkmap.js
CHANGED
|
@@ -9,6 +9,7 @@ class NetworkMap {
|
|
|
9
9
|
start(zbController, stController) {
|
|
10
10
|
this.zbController = zbController;
|
|
11
11
|
this.stController = stController;
|
|
12
|
+
return this.stop;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
stop() {
|
|
@@ -53,4 +54,4 @@ class NetworkMap {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
module.exports = NetworkMap;
|
|
57
|
+
module.exports = NetworkMap;
|
package/lib/statescontroller.js
CHANGED
|
@@ -57,23 +57,6 @@ class StatesController extends EventEmitter {
|
|
|
57
57
|
this.adapter.sendError(error, message);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
TriggerUpload(delay) {
|
|
61
|
-
if (this.timeoutHandleUpload) return;
|
|
62
|
-
this.warn('triggering upload')
|
|
63
|
-
this.timeoutHandleUpload = this.adapter.setTimeout(() => {
|
|
64
|
-
try {
|
|
65
|
-
this.warn('executing upload')
|
|
66
|
-
exec('iobroker upload zigbee', (error, stdout, stderr) => {
|
|
67
|
-
if (error) this.error('exec error: ' + JSON.stringify(error));
|
|
68
|
-
this.warn('upload done');
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
this.error('error on upload exec');
|
|
73
|
-
}
|
|
74
|
-
}, delay);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
60
|
getStashedErrors() {
|
|
78
61
|
const rv = [];
|
|
79
62
|
try {
|
|
@@ -99,19 +82,19 @@ class StatesController extends EventEmitter {
|
|
|
99
82
|
|
|
100
83
|
async AddModelFromHerdsman(device, model) {
|
|
101
84
|
// this.warn('addModelFromHerdsman ' + JSON.stringify(model) + ' ' + JSON.stringify(this.localConfig.getOverrideWithKey(model, 'legacy', true)));
|
|
102
|
-
if (this.localConfig.
|
|
85
|
+
if (this.localConfig.getOverrideWithTargetAndKey(model, 'legacy', true)) {
|
|
103
86
|
this.debug('Applying legacy definition for ' + model);
|
|
104
87
|
await this.addLegacyDevice(model);
|
|
105
88
|
}
|
|
106
89
|
else {
|
|
107
90
|
this.debug('Generating states from exposes for ' + model);
|
|
108
|
-
const modelDesc = await statesMapping.addExposeToDevices(device, this, model);
|
|
109
|
-
const srcIcon = modelDesc.icon;
|
|
110
91
|
// download icon if it external and not undefined
|
|
111
92
|
if (model === undefined) {
|
|
112
93
|
const dev_name = this.verifyDeviceName(device.ieeeAddr.substr(2), model, device.modelID);
|
|
113
|
-
this.warn(`
|
|
94
|
+
this.warn(`icon ${dev_name} for undefined Device not available. Check your devices.`);
|
|
114
95
|
} else {
|
|
96
|
+
const modelDesc = await statesMapping.addExposeToDevices(device, this, model);
|
|
97
|
+
const srcIcon = modelDesc.icon;
|
|
115
98
|
const model_modif = model.replace(/\//g, '-');
|
|
116
99
|
const pathToAdminIcon = `img/${model_modif}.png`;
|
|
117
100
|
|
|
@@ -134,15 +117,17 @@ class StatesController extends EventEmitter {
|
|
|
134
117
|
}
|
|
135
118
|
const base64Match = srcIcon.match(/data:image\/(.+);base64,/);
|
|
136
119
|
if (base64Match) {
|
|
120
|
+
this.warn(`base 64 Icon matched, trying to save it to disk as ${pathToAdminIcon}`);
|
|
137
121
|
modelDesc.icon = pathToAdminIcon;
|
|
138
122
|
this.adapter.fileExists(namespace, pathToAdminIcon, async (err,result) => {
|
|
139
123
|
if (result) {
|
|
140
|
-
this.
|
|
124
|
+
this.warn(`no need to save icon to ${pathToAdminIcon}`);
|
|
141
125
|
return;
|
|
142
126
|
}
|
|
143
|
-
this.
|
|
127
|
+
this.warn(`Saving base64 data to ${pathToAdminIcon}`)
|
|
144
128
|
const buffer = new Buffer(srcIcon.replace(base64Match[0],''), 'base64');
|
|
145
129
|
this.adapter.writeFile(pathToAdminIcon, buffer);
|
|
130
|
+
this.warn('write file complete.');
|
|
146
131
|
});
|
|
147
132
|
return;
|
|
148
133
|
}
|
|
@@ -296,48 +281,60 @@ class StatesController extends EventEmitter {
|
|
|
296
281
|
}
|
|
297
282
|
|
|
298
283
|
}
|
|
299
|
-
this.collectOptions(id.split('.')[2], model, options =>
|
|
284
|
+
this.collectOptions(id.split('.')[2], model, true, options =>
|
|
300
285
|
this.publishFromState(deviceId, model, stateKey, state, options, debugId));
|
|
301
286
|
}
|
|
302
287
|
});
|
|
303
288
|
}
|
|
304
289
|
}
|
|
305
290
|
|
|
306
|
-
async collectOptions(devId, model, callback) {
|
|
307
|
-
const result = {};
|
|
308
|
-
// find model states for options and get it values. No options for groups !!!
|
|
309
|
-
const devStates = await this.getDevStates('0x' + devId, model);
|
|
310
|
-
if (devStates == null || devStates == undefined || devStates.states == null || devStates.states == undefined) {
|
|
311
|
-
callback(result);
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const states = devStates.states.filter(statedesc => statedesc.isOption || statedesc.inOptions);
|
|
316
|
-
if (states == null || states == undefined) {
|
|
317
|
-
callback(result);
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
let cnt = 0;
|
|
291
|
+
async collectOptions(devId, model, getOptionStates, callback) {
|
|
321
292
|
try {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
const id = `${this.adapter.namespace}.${devId}.${statedesc.id}`;
|
|
325
|
-
this.adapter.getState(id, (err, state) => {
|
|
326
|
-
cnt = cnt + 1;
|
|
327
|
-
if (!err && state) {
|
|
328
|
-
result[statedesc.id] = state.val;
|
|
329
|
-
}
|
|
330
|
-
if (cnt === len) {
|
|
331
|
-
callback(result);
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
if (!len) {
|
|
293
|
+
const result = this.localConfig.getOptions(devId);
|
|
294
|
+
if (!getOptionStates) {
|
|
336
295
|
callback(result);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
// find model states for options and get it values. No options for groups !!!
|
|
299
|
+
const devStates = await this.getDevStates('0x' + devId, model);
|
|
300
|
+
if (devStates == null || devStates == undefined || devStates.states == null || devStates.states == undefined) {
|
|
301
|
+
callback(result);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const states = devStates.states.filter(statedesc => statedesc.isOption || statedesc.inOptions);
|
|
306
|
+
if (states == null || states == undefined) {
|
|
307
|
+
callback(result);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
let cnt = 0;
|
|
311
|
+
try {
|
|
312
|
+
const len = states.length;
|
|
313
|
+
states.forEach(statedesc => {
|
|
314
|
+
const id = `${this.adapter.namespace}.${devId}.${statedesc.id}`;
|
|
315
|
+
this.adapter.getState(id, (err, state) => {
|
|
316
|
+
cnt = cnt + 1;
|
|
317
|
+
if (!err && state) {
|
|
318
|
+
this.debug(`collect options for ${devId}: ${JSON.stringify(result)}`);
|
|
319
|
+
result[statedesc.id] = state.val;
|
|
320
|
+
}
|
|
321
|
+
if (cnt === len) {
|
|
322
|
+
callback(result);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
if (!len) {
|
|
327
|
+
callback(result);
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
this.sendError(error);
|
|
331
|
+
this.error(`Error collectOptions for ${devId}. Error: ${error.stack}`);
|
|
337
332
|
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
this.error(`Error collectOptions for ${devId}
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
this.error(`Error in collectOptions for ${devId} , ${model} : ${error && error.message ? error.message : 'no message given'}`);
|
|
336
|
+
callback({});
|
|
337
|
+
|
|
341
338
|
}
|
|
342
339
|
}
|
|
343
340
|
|
|
@@ -1047,7 +1044,7 @@ class StatesController extends EventEmitter {
|
|
|
1047
1044
|
|
|
1048
1045
|
} else {
|
|
1049
1046
|
if (statedesc.prepublish) {
|
|
1050
|
-
this.collectOptions(devId, model, options =>
|
|
1047
|
+
this.collectOptions(devId, model, false, options =>
|
|
1051
1048
|
statedesc.prepublish(devId, value, newvalue => {
|
|
1052
1049
|
this.updateState(devId, stateID, newvalue, common) }, options)
|
|
1053
1050
|
);
|
|
@@ -1088,7 +1085,7 @@ class StatesController extends EventEmitter {
|
|
|
1088
1085
|
};
|
|
1089
1086
|
|
|
1090
1087
|
const options = await new Promise((resolve, reject) => {
|
|
1091
|
-
this.collectOptions(devId, model, (options) => {
|
|
1088
|
+
this.collectOptions(devId, model, false, (options) => {
|
|
1092
1089
|
resolve(options);
|
|
1093
1090
|
});
|
|
1094
1091
|
});
|
|
@@ -1220,10 +1217,15 @@ class StatesController extends EventEmitter {
|
|
|
1220
1217
|
if (cluster !== '64529') {
|
|
1221
1218
|
if (has_elevated_debug) this.emit('device_debug', { ID:debugId, data: { error:'EPROC', IO:true }});
|
|
1222
1219
|
this.error(`Error while processing converters DEVICE_ID: '${devId}' cluster '${cluster}' type '${type}'`);
|
|
1220
|
+
this.error(`error message: ${error && error.message ? error.message : ''}`);
|
|
1223
1221
|
}
|
|
1224
1222
|
});
|
|
1225
1223
|
}
|
|
1226
1224
|
|
|
1225
|
+
async stop() {
|
|
1226
|
+
this.localConfig.retainData();
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1227
1229
|
|
|
1228
1230
|
|
|
1229
1231
|
}
|
package/lib/zbDeviceConfigure.js
CHANGED
|
@@ -155,7 +155,7 @@ class DeviceConfigure extends BaseExtension {
|
|
|
155
155
|
if (mappedDevice.configure === undefined) return `No configure available for ${device.ieeeAddr} ${mappedDevice.model}.`;
|
|
156
156
|
this.info(`Configuring ${device.ieeeAddr} ${mappedDevice.model}`);
|
|
157
157
|
this.configuring.add(device.ieeeAddr);
|
|
158
|
-
if (typeof mappedDevice.configure === 'function') await mappedDevice.configure(device, coordinatorEndpoint,
|
|
158
|
+
if (typeof mappedDevice.configure === 'function') await mappedDevice.configure(device, coordinatorEndpoint, mappedDevice);
|
|
159
159
|
else {
|
|
160
160
|
const promises = [];
|
|
161
161
|
promises.push(...mappedDevice.configure);
|
package/lib/zigbeecontroller.js
CHANGED
|
@@ -118,7 +118,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
118
118
|
this.powerText = powerLevels[this.transmitPower] || 'normal';
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
this.info(` --> transmitPower : ${this.powerText}`);
|
|
121
|
+
//this.info(` --> transmitPower : ${this.powerText}`);
|
|
122
122
|
|
|
123
123
|
const herdsmanSettings = {
|
|
124
124
|
network: {
|
|
@@ -185,6 +185,16 @@ class ZigbeeController extends EventEmitter {
|
|
|
185
185
|
async start() {
|
|
186
186
|
try {
|
|
187
187
|
this.emit('pairing',`Starting zigbee-herdsman...`);
|
|
188
|
+
this.powerText = '';
|
|
189
|
+
if (this.transmitPower !== '0') {
|
|
190
|
+
const powerLevels = {
|
|
191
|
+
'-22': 'low',
|
|
192
|
+
'19': 'high',
|
|
193
|
+
'20': 'high+'
|
|
194
|
+
};
|
|
195
|
+
this.powerText = powerLevels[this.transmitPower] || 'normal';
|
|
196
|
+
}
|
|
197
|
+
this.info(`configured transmit power : ${this.powerText}`);
|
|
188
198
|
if (this.debugActive) this.debug(`Starting zigbee-herdsman...`);
|
|
189
199
|
|
|
190
200
|
// install event handlers before start
|
|
@@ -669,6 +679,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
669
679
|
if (this.HerdsmanStarted) await this.permitJoin(0);
|
|
670
680
|
await this.herdsman.stop();
|
|
671
681
|
this.HerdsmanStarted = false;
|
|
682
|
+
this.info('zigbecontroller stopped successfully');
|
|
672
683
|
} catch (error) {
|
|
673
684
|
this.sendError(error);
|
|
674
685
|
if (this.herdsmanStarted) {
|
package/main.js
CHANGED
|
@@ -232,7 +232,11 @@ class Zigbee extends utils.Adapter {
|
|
|
232
232
|
this.deviceDebug.start(this.stController, this.zbController);
|
|
233
233
|
|
|
234
234
|
this.reconnectCounter = 1;
|
|
235
|
-
if (this.config.autostart)
|
|
235
|
+
if (this.config.autostart) {
|
|
236
|
+
this.log.info('Autostart Zigbee subsystem');
|
|
237
|
+
this.doConnect();
|
|
238
|
+
}
|
|
239
|
+
else this.log.warn('Zigbee autostart option not set - omitting start of zigbee substystem!');
|
|
236
240
|
}
|
|
237
241
|
updateDebugLevel(state) {
|
|
238
242
|
const dbActive = state === 'debug';
|
|
@@ -809,7 +813,7 @@ class Zigbee extends utils.Adapter {
|
|
|
809
813
|
this.emit('device_debug', { ID:debugID, data: { error: 'NOCONV',states:[{id:stateDesc.id, value:value, payload:'no converter'}] , IO:false }, message:message});
|
|
810
814
|
}
|
|
811
815
|
else {
|
|
812
|
-
this.log.
|
|
816
|
+
this.log.info(message);
|
|
813
817
|
}
|
|
814
818
|
return;
|
|
815
819
|
}
|
|
@@ -1079,17 +1083,19 @@ class Zigbee extends utils.Adapter {
|
|
|
1079
1083
|
*/
|
|
1080
1084
|
async onUnload(callback) {
|
|
1081
1085
|
try {
|
|
1086
|
+
this.log.info(`Halting zigbee adapter. Restart delay is at least ${this.ioPack.common.stopTimeout / 1000} seconds.`)
|
|
1082
1087
|
if (this.config.debugHerdsman) {
|
|
1083
1088
|
debug.disable();
|
|
1084
1089
|
debug.log = originalLogMethod;
|
|
1085
1090
|
}
|
|
1086
1091
|
|
|
1087
|
-
this.log.info('
|
|
1088
|
-
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
|
1092
|
+
this.log.info('cleaning everything up...');
|
|
1089
1093
|
await this.callPluginMethod('stop');
|
|
1094
|
+
await this.stController.stop();
|
|
1090
1095
|
if (this.zbController) {
|
|
1091
1096
|
await this.zbController.stop();
|
|
1092
1097
|
}
|
|
1098
|
+
this.log.info('cleanup successful');
|
|
1093
1099
|
callback();
|
|
1094
1100
|
} catch (error) {
|
|
1095
1101
|
if (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Kirov Ilya",
|
|
6
6
|
"email": "kirovilya@gmail.com"
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@iobroker/adapter-core": "^3.2.3",
|
|
25
|
-
"@iobroker/dm-utils": "^1.0.
|
|
26
|
-
"humanize-duration": "^3.
|
|
25
|
+
"@iobroker/dm-utils": "^1.0.10",
|
|
26
|
+
"humanize-duration": "^3.33.0",
|
|
27
27
|
"tar": "^7.4.3",
|
|
28
28
|
"ajv": "^8.17.1",
|
|
29
29
|
"uri-js": "^4.4.1",
|
|
30
|
-
"typescript": "^5.
|
|
31
|
-
"zigbee-herdsman": "
|
|
32
|
-
"zigbee-herdsman-converters": "
|
|
30
|
+
"typescript": "^5.8.3",
|
|
31
|
+
"zigbee-herdsman": "4.0.0",
|
|
32
|
+
"zigbee-herdsman-converters": "23.35.0"
|
|
33
33
|
},
|
|
34
34
|
"description": "Zigbee devices",
|
|
35
35
|
"devDependencies": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@iobroker/testing": "^5.0.4",
|
|
41
41
|
"chai": "^5.1.2",
|
|
42
42
|
"chai-as-promised": "^7.1.1",
|
|
43
|
-
"eslint": "^9.
|
|
43
|
+
"eslint": "^9.30.0",
|
|
44
44
|
"eslint-config-prettier": "^9.1.0",
|
|
45
|
-
"eslint-plugin-prettier": "^5.
|
|
45
|
+
"eslint-plugin-prettier": "^5.5.1",
|
|
46
46
|
"gulp": "^4.0.2",
|
|
47
47
|
"gulp-jsdoc3": "^3.0.0",
|
|
48
48
|
"gulp-replace": "^1.1.4",
|