iobroker.zigbee 1.6.6 → 1.6.15

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.
@@ -105,11 +105,11 @@ class ZigbeeController extends EventEmitter {
105
105
  this.debug('zigbee-herdsman started');
106
106
  this.herdsman_started = true;
107
107
  this.info(`Coordinator firmware version: ${JSON.stringify(await this.herdsman.getCoordinatorVersion())}`);
108
-
108
+
109
109
  // debug info from herdsman getNetworkParameters
110
110
  const debNetworkParam = JSON.parse(JSON.stringify(await this.herdsman.getNetworkParameters()));
111
111
  const extendedPanIDDebug = (typeof debNetworkParam.extendedPanID == 'string') ? debNetworkParam.extendedPanID.replace('0x','') : debNetworkParam.extendedPanID;
112
-
112
+
113
113
  let extPanIDDebug = '';
114
114
  for (let i = extendedPanIDDebug.length - 1; i >= 0; i--) {
115
115
  extPanIDDebug += extendedPanIDDebug[i-1];
@@ -117,8 +117,8 @@ class ZigbeeController extends EventEmitter {
117
117
  i--;
118
118
  }
119
119
 
120
- this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
-
120
+ this.debug(`Zigbee network parameters: panID=${debNetworkParam.panID} channel=${debNetworkParam.channel} extendedPanID=${extPanIDDebug}`);
121
+
122
122
  } catch (e) {
123
123
  this.sendError(e);
124
124
  this.error('Starting zigbee-herdsman problem : ' + JSON.stringify(e.message));
@@ -148,6 +148,9 @@ class ZigbeeController extends EventEmitter {
148
148
  case '19':
149
149
  powerText = 'high';
150
150
  break;
151
+ case '20':
152
+ powerText = 'high+';
153
+ break;
151
154
  default:
152
155
  powerText = 'normal';
153
156
  }
@@ -175,8 +178,16 @@ class ZigbeeController extends EventEmitter {
175
178
  }
176
179
  for (const device of devices) {
177
180
  const entity = await this.resolveEntity(device);
181
+ this.adapter.getObject(device.ieeeAddr.substr(2),(err, obj) => {
182
+ if (obj && obj.common && obj.common.deactivated)
183
+ {
184
+ this.callExtensionMethod('deregisterDevicePing', [device, entity]);
185
+ }
186
+ else {
187
+ this.callExtensionMethod('registerDevicePing', [device, entity]);
188
+ }
189
+ });
178
190
  // ensure that objects for all found clients are present
179
- this.callExtensionMethod('registerDevicePing', [device, entity]);
180
191
 
181
192
  if (entity.mapped) this.emit('new', entity);
182
193
  this.info(
@@ -217,13 +228,14 @@ class ZigbeeController extends EventEmitter {
217
228
  }
218
229
 
219
230
  callExtensionMethod(method, parameters) {
231
+ const result = [];
220
232
  for (const extension of this.extensions) {
221
233
  if (extension[method]) {
222
234
  try {
223
235
  if (parameters !== undefined) {
224
- extension[method](...parameters);
236
+ result.push(extension[method](...parameters));
225
237
  } else {
226
- extension[method]();
238
+ result.push(extension[method]());
227
239
  }
228
240
  } catch (error) {
229
241
  this.sendError(error);
@@ -231,6 +243,7 @@ class ZigbeeController extends EventEmitter {
231
243
  }
232
244
  }
233
245
  }
246
+ return Promise.all(result);
234
247
  }
235
248
 
236
249
  async getClients(all) {
@@ -248,9 +261,11 @@ class ZigbeeController extends EventEmitter {
248
261
 
249
262
  async getGroups() {
250
263
  try {
251
- return this.herdsman.getGroups();
264
+ const rv = await this.herdsman.getGroups();
265
+ return rv;
252
266
  } catch (error) {
253
267
  this.sendError(error);
268
+ this.error(JSON.stringify(error));
254
269
  return undefined;
255
270
  }
256
271
  }
@@ -274,17 +289,32 @@ class ZigbeeController extends EventEmitter {
274
289
  }
275
290
  }
276
291
 
292
+ async verifyGroupExists(id) {
293
+ const nid = (typeof(id) === 'number' ? id:parseInt(id));
294
+ let group = await this.herdsman.getGroupByID(nid);
295
+ if (!group) {
296
+ group = await this.herdsman.createGroup(nid);
297
+ group.toZigbee = groupConverters;
298
+ group.model = 'group';
299
+ this.debug('verifyGroupExists: created group ' + nid);
300
+ }
301
+ else {
302
+ this.debug('verifyGroupExists: group ' + nid + ' exists');
303
+ }
304
+
305
+ }
306
+
277
307
  async getGroupMembersFromController(id) {
278
308
  const members = [];
279
309
  try {
280
310
  const group = await this.getGroupByID(id);
281
311
  if (group) {
282
312
  const groupmembers = group.members;
283
-
284
313
  for (const member of groupmembers) {
314
+ const epid = (member.ID ? member.ID:-1);
285
315
  const nwk = member.deviceNetworkAddress;
286
316
  const device = this.getDeviceByNetworkAddress(nwk);
287
- if (device && device.ieeeAddr) members.push( { device:device.ieeeAddr, model:device.modelID } );
317
+ if (device && device.ieeeAddr) members.push( { ieee:device.ieeeAddr, model:device.modelID, epid:epid, ep:member } );
288
318
  }
289
319
  }
290
320
  else {
@@ -525,6 +555,13 @@ class ZigbeeController extends EventEmitter {
525
555
  const entity = await this.resolveEntity(message.device || message.ieeeAddr);
526
556
  const friendlyName = entity.name;
527
557
  this.warn(`Device '${friendlyName}' announced itself`);
558
+
559
+ if (entity && entity.mapped) {
560
+ this.callExtensionMethod(
561
+ 'onZigbeeEvent',
562
+ [ {'device': message.device, 'type': 'deviceAnnounce'}, (entity ? entity.mapped : null)]);
563
+ }
564
+
528
565
  this.emit('pairing', `Device '${friendlyName}' announced itself`);
529
566
  if (!this.herdsman.getPermitJoin()) this.callExtensionMethod('registerDevicePing', [message.device, entity]);
530
567
  // if has modelID so can create device
@@ -534,6 +571,7 @@ class ZigbeeController extends EventEmitter {
534
571
  }
535
572
  }
536
573
 
574
+
537
575
  async handleDeviceJoined(message) {
538
576
  this.debug('handleDeviceJoined', message);
539
577
  //const entity = await this.resolveEntity(message.device || message.ieeeAddr);
@@ -686,7 +724,7 @@ class ZigbeeController extends EventEmitter {
686
724
  }
687
725
  }
688
726
 
689
- async publish(deviceID, cid, cmd, zclData, cfg, ep, type, callback) {
727
+ async publish(deviceID, cid, cmd, zclData, cfg, ep, type, callback, zclSeqNum) {
690
728
  const entity = await this.resolveEntity(deviceID, ep);
691
729
  const device = entity.device;
692
730
  const endpoint = entity.endpoint;
@@ -727,20 +765,57 @@ class ZigbeeController extends EventEmitter {
727
765
  result = await endpoint[cmd](cid, zclData, cfg);
728
766
  }
729
767
  if (callback) callback(undefined, result);
730
- } else {
768
+ }
769
+ else if(type === 'functionalResp'){
770
+ cfg.disableDefaultResponse = false;
771
+ const result = await endpoint.commandResponse(cid, cmd, zclData, cfg, zclSeqNum);
772
+ if (callback) callback(undefined, result);
773
+ }
774
+ else {
731
775
  cfg.disableDefaultResponse = false;
732
776
  const result = await endpoint.command(cid, cmd, zclData, cfg);
733
777
  if (callback) callback(undefined, result);
734
778
  }
735
779
  }
736
780
 
737
- async addDevToGroup(devId, groupId) {
781
+ async addDevToGroup(devId, groupId, epid) {
738
782
  try {
739
783
  const entity = await this.resolveEntity(devId);
740
784
  const group = await this.resolveEntity(groupId);
741
- this.debug(`entity: ${safeJsonStringify(entity)}`);
742
- this.debug(`group: ${safeJsonStringify(group)}`);
743
- await entity.endpoint.addToGroup(group.mapped);
785
+ this.debug(`addDevFromGroup - entity: ${safeJsonStringify(entity)}`);
786
+ this.debug(`addDevFromGroup - group: ${safeJsonStringify(group)}`);
787
+ if (epid != undefined) {
788
+ for (const ep of entity.endpoints) {
789
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
790
+ {
791
+ this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`)
792
+ await(ep.addToGroup(group.mapped));
793
+ }
794
+ }
795
+
796
+ }
797
+ else
798
+ {
799
+ if (entity.endpoint.inputClusters.includes(4))
800
+ {
801
+ this.debug(`adding endpoint ${entity.endpoint.ID} to group`)
802
+ await entity.endpoint.addToGroup(group.mapped);
803
+ }
804
+ else {
805
+ let added = false;
806
+ for (const ep of entity.endpoints)
807
+ {
808
+ if (ep.inputClusters.includes(4))
809
+ {
810
+ this.debug(`adding endpoint ${ep.ID} to group`)
811
+ await ep.addToGroup(group.mapped);
812
+ added = true;
813
+ break;
814
+ }
815
+ }
816
+ if (!added) throw ('cluster genGroups not supported');
817
+ }
818
+ }
744
819
  } catch (error) {
745
820
  this.sendError(error);
746
821
  this.error(`Exception when trying to Add ${devId} to group ${groupId}`, error);
@@ -749,11 +824,38 @@ class ZigbeeController extends EventEmitter {
749
824
  return {};
750
825
  }
751
826
 
827
+ async removeDevFromGroup(devId, groupId, epid) {
828
+ try {
829
+ const entity = await this.resolveEntity(devId);
830
+ const group = await this.resolveEntity(groupId);
831
+ this.debug(`removeDevFromGroup - entity: ${safeJsonStringify(entity)}`);
832
+ this.debug(`removeDevFromGroup - group: ${safeJsonStringify(group)}`);
833
+ if (epid != undefined) {
834
+ for (const ep of entity.endpoints) {
835
+ if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)))
836
+ {
837
+ this.debug(`removing endpoint ${ep.ID} (${epid}) group ${groupId}`)
838
+ await(ep.removeFromGroup(group.mapped))
839
+ }
840
+ }
841
+ } else await entity.endpoint.removeFromGroup(group.mapped);
842
+ } catch (error) {
843
+ this.sendError(error);
844
+ this.error(`Exception when trying remove ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`, error);
845
+ return { error: `Failed to remove dev ${devId} (ep ${epid?epid:entity.endpoint.ID}) from group ${devId}`};
846
+ }
847
+ return {};
848
+ }
849
+
752
850
  async removeDevFromAllGroups(devId) {
753
851
  try {
754
852
  const entity = await this.resolveEntity(devId);
755
853
  this.debug(`entity: ${safeJsonStringify(entity)}`);
756
- await entity.endpoint.removeFromAllGroups();
854
+ for (const ep of entity.endpoints) {
855
+ if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))
856
+ await ep.removefromAllGroups();
857
+ }
858
+ //await entity.endpoint.removeFromAllGroups();
757
859
  } catch (error) {
758
860
  this.sendError(error);
759
861
  this.error(`Exception when trying remove ${devId} from all groups`, error);
package/main.js CHANGED
@@ -159,7 +159,7 @@ class Zigbee extends utils.Adapter {
159
159
  this.log.error(`${message}: Code ${error.code} (${ecode.message})`);
160
160
  this.sendError(error, `${message}: Code ${error.code} (${ecode.message})`);
161
161
  break;
162
- default:
162
+ default:
163
163
  this.log.error(`${message}: Code ${error.code} (malformed error)`);
164
164
  this.sendError(error, `${message}: Code ${error.code} (malformed error)`);
165
165
  }
@@ -431,7 +431,7 @@ class Zigbee extends utils.Adapter {
431
431
  delete msgForState['endpoint'];
432
432
  msgForState['endpoint_id'] = message.endpoint.ID;
433
433
  this.publishToState(devId, model, {msg_from_zigbee: safeJsonStringify(msgForState)});
434
-
434
+
435
435
  if (!entity.mapped) {
436
436
  return;
437
437
  }
@@ -771,8 +771,8 @@ class Zigbee extends utils.Adapter {
771
771
  getZigbeeOptions() {
772
772
  // file path for db
773
773
  let dbDir = path.join(utils.getAbsoluteInstanceDataDir(this), '');
774
- dbDir = dbDir.replace('.', '_');
775
-
774
+ dbDir = dbDir.replace('.', '_');
775
+
776
776
  if (this.systemConfig && !fs.existsSync(dbDir)) {
777
777
  try {
778
778
  fs.mkdirSync(dbDir);
@@ -837,6 +837,10 @@ class Zigbee extends utils.Adapter {
837
837
  this.setState('info.pairingMessage', message, true);
838
838
  }
839
839
 
840
+ expandFileName(fn) {
841
+ return path.join(utils.getAbsoluteInstanceDataDir(this), fn);
842
+ }
843
+
840
844
  onLog(level, msg, data) {
841
845
  if (msg) {
842
846
  let logger = this.log.info;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "1.6.6",
3
+ "version": "1.6.15",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -18,24 +18,27 @@
18
18
  "node": ">=10"
19
19
  },
20
20
  "dependencies": {
21
- "zigbee-herdsman": "0.13.169",
22
- "zigbee-herdsman-converters": "14.0.316",
21
+ "zigbee-herdsman": "0.14.14",
22
+ "zigbee-herdsman-converters": "14.0.421",
23
23
  "@iobroker/adapter-core": "^2.4.0",
24
24
  "tar": "^6.0.5",
25
25
  "typescript": "^4.0.5"
26
26
  },
27
27
  "description": "Zigbee devices",
28
28
  "devDependencies": {
29
- "@alcalzone/release-script": "^2.2.0",
30
- "@iobroker/testing": "^2.5.1",
29
+ "@alcalzone/release-script": "~3.4.2",
30
+ "@iobroker/testing": "^2.5.4",
31
31
  "axios": "^0.21.1",
32
32
  "mixin-deep": "^1.3.2",
33
- "chai": "^4.2.0",
34
33
  "eslint": "^7.18.0",
35
34
  "eslint-config-google": "*",
36
- "gulp": "^4.0.0",
37
35
  "lint-diff": "*",
38
- "mocha": "^6.0.2"
36
+ "chai": "^4.3.4",
37
+ "chai-as-promised": "^7.1.1",
38
+ "gulp": "^4.0.2",
39
+ "gulp-jsdoc3": "^3.0.0",
40
+ "gulp-replace": "^1.1.3",
41
+ "mocha": "^9.1.3"
39
42
  },
40
43
  "homepage": "https://github.com/ioBroker/ioBroker.zigbee",
41
44
  "keywords": [
@@ -1,36 +0,0 @@
1
- // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
2
- // https://github.com/microsoft/vscode-dev-containers/tree/v0.101.1/containers/docker-existing-docker-compose
3
- // If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
4
- {
5
- "name": "ioBroker Docker Compose",
6
-
7
- // Update the 'dockerComposeFile' list if you have more compose files or use different names.
8
- // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
9
- "dockerComposeFile": ["docker-compose.yml"],
10
-
11
- // The 'service' property is the name of the service for the container that VS Code should
12
- // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
13
- "service": "iobroker",
14
-
15
- // The optional 'workspaceFolder' property is the path VS Code should open by default when
16
- // connected. This is typically a file mount in .devcontainer/docker-compose.yml
17
- "workspaceFolder": "/workspace",
18
-
19
- // Set *default* container specific settings.json values on container create.
20
- "settings": {},
21
-
22
- // Add the IDs of extensions you want installed when the container is created.
23
- "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
24
-
25
- // Uncomment the next line if you want start specific services in your Docker Compose config.
26
- // "runServices": [],
27
-
28
- // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
29
- // "shutdownAction": "none",
30
-
31
- // When creating the container, delete unnecessary adapters, disable error reporting, set the license as confirmed, and install/update this adapter
32
- "postCreateCommand": "iob del discovery && iob plugin disable sentry && iob object set system.config common.licenseConfirmed=true && NPM_PACK=$(npm pack) && iob url \"$(pwd)/$NPM_PACK\" --debug && rm \"$NPM_PACK\""
33
-
34
- // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
35
- //"remoteUser": "iobroker"
36
- }
@@ -1,51 +0,0 @@
1
- version: '3'
2
-
3
- services:
4
- iobroker:
5
- build: ./iobroker
6
- container_name: iobroker-zigbee-d
7
- hostname: iobroker-zigbee-d
8
- # This port is only internal, so we can work on this while another instance of ioBroker is running on the host
9
- expose:
10
- - 8081
11
- volumes:
12
- - ..:/workspace
13
- - iobrokerdata-zigbee-d:/opt/iobroker
14
- environment:
15
- - LANG=en_US.UTF-8
16
- - LANGUAGE=en_US:en
17
- - LC_ALL=en_US.UTF-8
18
- - TZ=Europe/Berlin
19
- - SETGID=1000
20
-
21
- parcel:
22
- container_name: parcel-i2c
23
- build: ./parcel
24
- expose:
25
- - 1234
26
- ports:
27
- - '1235:1235'
28
- volumes:
29
- - ..:/workspace
30
- environment:
31
- - CHOKIDAR_USEPOLLING=1
32
-
33
- # Reverse proxy to load up-to-date admin sources from the repo
34
- nginx:
35
- image: nginx:latest
36
- depends_on:
37
- - iobroker
38
- - parcel
39
- links:
40
- - iobroker
41
- - parcel
42
- container_name: nginx-dvlp
43
- volumes:
44
- - ./nginx/nginx.conf:/etc/nginx/nginx.conf
45
- - ..:/workspace
46
- ports:
47
- # Make the ioBroker admin available under http://localhost:8082
48
- - 8082:80
49
-
50
- volumes:
51
- iobrokerdata-zigbee-d:
@@ -1,2 +0,0 @@
1
- FROM buanet/iobroker:latest
2
- RUN ln -s /opt/iobroker/node_modules/ /root/.node_modules
@@ -1,33 +0,0 @@
1
-
2
- worker_processes 1;
3
- events { worker_connections 1024; }
4
-
5
- http {
6
- sendfile on;
7
- keepalive_timeout 65;
8
-
9
- server {
10
- listen 80;
11
-
12
- location / {
13
- proxy_redirect off;
14
- proxy_pass http://iobroker:8081;
15
- }
16
-
17
- location /socket.io/ {
18
- proxy_pass http://iobroker:8081;
19
- proxy_http_version 1.1;
20
- proxy_set_header Upgrade $http_upgrade;
21
- proxy_set_header Connection "Upgrade";
22
- }
23
-
24
- location /adapter/i2c/ {
25
- alias /workspace/admin/;
26
- }
27
-
28
- location /adapter/i2c/build/ {
29
- proxy_redirect off;
30
- proxy_pass http://parcel:1234/;
31
- }
32
- }
33
- }
@@ -1,9 +0,0 @@
1
- FROM node:12
2
-
3
- RUN mkdir -p /usr/app
4
-
5
- COPY *.sh /usr/app/
6
-
7
- RUN chmod +x /usr/app/*.sh
8
-
9
- CMD /bin/bash -c "/usr/app/run.sh"
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- cd /workspace
3
-
4
- echo "Installing all dependencies..."
5
- npm install
6
-
7
- npm run watch:parcel