iobroker.zigbee 1.6.3 → 1.6.14

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/devices.js CHANGED
@@ -730,6 +730,7 @@ const devices = [
730
730
  states: [states.contact, states.opened, states.voltage, states.battery],
731
731
  },
732
732
  {
733
+ // MCCGQ14LM is a opple brand. not works here
733
734
  models: ['MCCGQ11LM'],
734
735
  icon: 'img/sensor_magnet_aq2.png',
735
736
  states: [states.contact, states.opened, states.voltage, states.battery],
@@ -2327,6 +2328,12 @@ const devices = [
2327
2328
  icon: 'img/nue_hgzb-02a.png',
2328
2329
  states: [states.state],
2329
2330
  },
2331
+ {
2332
+ models: ['HGZB-02A'],
2333
+ icon: 'img/nue_hgzb-02a.png',
2334
+ states: lightStates,
2335
+ linkedStates: [comb.brightnessAndState],
2336
+ },
2330
2337
  {
2331
2338
  models: ['HGZB-41', 'HGZB-20-UK'],
2332
2339
  icon: 'img/nue_switch_single.png',
@@ -3036,7 +3043,45 @@ const devices = [
3036
3043
  icon: 'img/ICZB-RM11S.png',
3037
3044
  states: generator.icasa_remote,
3038
3045
  },
3039
-
3046
+
3047
+ /* images only for admin */
3048
+ {
3049
+ models: ['E1812'],
3050
+ icon: 'img/ikea_E1812.png',
3051
+ },
3052
+ {
3053
+ models: ['WHD02'],
3054
+ icon: 'img/WHD02.png',
3055
+ },
3056
+ {
3057
+ models: ['R7060'],
3058
+ icon: 'img/R7060.png',
3059
+ },
3060
+ {
3061
+ models: ['929001821618'],
3062
+ icon: 'img/philips_hue_ambiance.png',
3063
+ },
3064
+ {
3065
+ models: ['14153905L'],
3066
+ icon: 'img/14153905L.png',
3067
+ },
3068
+ {
3069
+ models: ['HG06338'],
3070
+ icon: 'img/HG06338.png',
3071
+ },
3072
+ {
3073
+ models: ['81855'],
3074
+ icon: 'img/81855.png',
3075
+ },
3076
+ {
3077
+ models: ['TI0001-cover'],
3078
+ icon: 'img/TI0001-cover.png',
3079
+ },
3080
+ {
3081
+ models: ['E1603/E1702/E1708'],
3082
+ icon: 'img/ikea_control_outlet.png',
3083
+ },
3084
+
3040
3085
  ];
3041
3086
 
3042
3087
  const commonStates = [
package/lib/exposes.js CHANGED
@@ -116,10 +116,12 @@ function createFromExposes(model, def) {
116
116
  // .withFeature(exposes.binary('some_option', ea.SET, true, false).withDescription('Some Option'))
117
117
  //in this case one state - `some_option` has two different exposes for set an get, we have to combine it ...
118
118
  //
119
+
119
120
  function pushToStates(state, access) {
120
121
  if (state === undefined) {
121
122
  return 0;
122
123
  }
124
+ if (access === undefined) access = ea.ALL;
123
125
  state.readable = (access & ea.STATE) > 0;
124
126
  state.writable = (access & ea.SET) > 0;
125
127
  const stateExists = states.findIndex( (element, index, array) => (element.id === state.id ));
@@ -758,7 +760,7 @@ function createFromExposes(model, def) {
758
760
  };
759
761
  // make the function code printable in log
760
762
  //console.log(`Created mapping for device ${model}: ${JSON.stringify(newDev, function(key, value) {
761
- // if (typeof value === 'function') {return value.toString() } else { return value } }, ' ')}`);
763
+ // if (typeof value === 'function') {return value.toString() } else { return value } }, ' ')}`);
762
764
  return newDev;
763
765
  }
764
766
 
package/lib/groups.js CHANGED
@@ -15,7 +15,11 @@ class Groups {
15
15
  this.adapter.getStateAsync('info.groups')
16
16
  .then((groupsState) => {
17
17
  const groups = (groupsState && groupsState.val) ? JSON.parse(groupsState.val) : {};
18
- this.syncGroups(groups);
18
+ for (const gid in groups) {
19
+ stController.storeDeviceName(`group_${gid}`, groups[gid]);
20
+ }
21
+ // this.Adapter.deleteState('info.groups');
22
+ this.syncGroups();
19
23
  });
20
24
  }
21
25
 
@@ -90,16 +94,17 @@ class Groups {
90
94
  async getGroups(obj) {
91
95
  const response = { groups: {} };
92
96
  try {
93
- const groupsState = await this.adapter.getStateAsync('info.groups');
97
+ // const groupsState = await this.adapter.getStateAsync('info.groups');
94
98
  const herdsmanGroups = await this.zbController.getGroups();
95
99
 
96
- const groups = (groupsState && groupsState.val) ? JSON.parse(groupsState.val) : {};
100
+ // const groups = (groupsState && groupsState.val) ? JSON.parse(groupsState.val) : {};
97
101
 
102
+ const groups = {};
98
103
  if (typeof herdsmanGroups === 'object') {
99
104
  for (const group of herdsmanGroups) {
100
105
  const gid = group.groupID;
101
- if (gid && groups[gid]=== undefined) {
102
- groups[gid] = `Auto Group ${gid}`;
106
+ if (gid) {
107
+ groups[gid]=this.stController.verifyDeviceName(`group_${gid}`,`Group ${gid}`);
103
108
  }
104
109
  }
105
110
  }
@@ -115,34 +120,44 @@ class Groups {
115
120
  this.adapter.sendTo(obj.from, obj.command, response, obj.callback);
116
121
 
117
122
  }
123
+ return response.groups;
118
124
  }
119
125
 
120
126
  async updateGroupMembership(from, command, message, callback) {
121
127
  try {
122
- const groups = (message && message.groups ? message.groups : []);
128
+ const groups = (message && message.groups ? message.groups : {});
123
129
  const devId = (message && message.id ? message.id : undefined);
124
130
  if (devId === undefined) {
125
131
  this.adapter.sendTo(from, command, {error: 'No device specified'}, callback);
126
132
  }
127
133
  const sysid = devId.replace(this.adapter.namespace + '.', '0x');
128
- const id = `${devId}.groups`;
134
+ // Keeping this for reference. State update or state removal needs to be decided upon
135
+ //const id = `${devId}.groups`;
136
+ // this.adapter.setState(id, JSON.stringify(groups), true);
129
137
 
130
- this.adapter.setState(id, JSON.stringify(groups), true);
131
- let response = await this.zbController.removeDevFromAllGroups(sysid);
132
- if (response && response.error)
133
- {
134
- this.adapter.sendTo(from, command, response, callback);
135
- return;
136
- }
137
- for (const groupId of groups) {
138
- response = await this.zbController.addDevToGroup(sysid, parseInt(groupId));
139
- if (response && response.error)
140
- {
141
- this.adapter.sendTo(from, command, response, callback);
142
- return;
138
+ //const current = await this.zbController.getGroupMembersFromController(sysid);
139
+ const errors = []
140
+ for (const epid in groups) {
141
+ for (const gpid of groups[epid]) {
142
+ const gpidn = parseInt(gpid);
143
+ if (gpidn < 0) {
144
+ let response = await this.zbController.removeDevFromGroup(sysid,(-gpidn), epid);
145
+ if (response && response.error) {
146
+ errors.push(response.error);
147
+ this.error("remove dev from group Error: "+ JSON.stringify(response.error));
148
+ }
149
+ }
150
+ else if (gpidn > 0){
151
+ let response = await this.zbController.addDevToGroup(sysid,(gpidn), epid);
152
+ if (response && response.error) {
153
+ errors.push(response.error);
154
+ this.error("add dev to group Error: "+ JSON.stringify(response.error));
155
+ }
156
+
157
+ }
158
+ else this.warn('illegal group id 0');
143
159
  }
144
160
  }
145
-
146
161
  } catch (e) {
147
162
  this.adapter.sendTo(from, command, {error: e}, callback);
148
163
  return;
@@ -177,7 +192,6 @@ class Groups {
177
192
  }
178
193
  }
179
194
  if (result.unsupported.length>0) {
180
- // this.warn('unsupported ' + stateDesc.id + ' change for group members ' + JSON.stringify(result.unsupported));
181
195
  const error = {
182
196
  code: 134,
183
197
  message: `unsupported ${stateDesc.id} change for group members ${result.unsupported.join()}`
@@ -190,6 +204,7 @@ class Groups {
190
204
  }
191
205
 
192
206
  async deleteGroup(from, command, message) {
207
+ /*
193
208
  const members = await this.getGroupMembersFromController(parseInt(message));
194
209
  if (members && members.length) {
195
210
  for (const member of members) {
@@ -212,17 +227,27 @@ class Groups {
212
227
  const objGroups = (groupsEntry && groupsEntry.val ? JSON.parse(groupsEntry.val) : {});
213
228
  delete objGroups[message.toString()];
214
229
  await this.adapter.setStateAsync('info.groups', JSON.stringify(objGroups), true);
230
+ */
215
231
  await this.zbController.removeGroupById(message);
216
- this.stController.deleteDeviceStates(`group_${parseInt(message)}`);
232
+ await this.stController.deleteDeviceStatesAsync(`group_${parseInt(message)}`);
217
233
  }
218
234
 
219
235
  async renameGroup(from, command, message) {
220
- const groupsEntry = await this.adapter.getStateAsync('info.groups');
221
- const objGroups = (groupsEntry && groupsEntry.val ? JSON.parse(groupsEntry.val) : {});
236
+
237
+ // const groupsEntry = await this.adapter.getStateAsync('info.groups');
238
+ // const objGroups = (groupsEntry && groupsEntry.val ? JSON.parse(groupsEntry.val) : {});
222
239
  const name = message.name;
223
240
  const id = `group_${message.id}`;
224
- objGroups[message.id.toString()] = message.name;
225
- await this.adapter.setStateAsync('info.groups', JSON.stringify(objGroups), true);
241
+ this.stController.storeDeviceName(id, name);
242
+ try {
243
+ await this.zbController.verifyGroupExists(message.id);
244
+ }
245
+ catch (e)
246
+ {
247
+ if (e && e.hasOwnProperty('code')) this.warn('renameGroup caught error ' + JSON.stringify(e.code));
248
+ }
249
+ // objGroups[message.id.toString()] = message.name;
250
+ // await this.adapter.setStateAsync('info.groups', JSON.stringify(objGroups), true);
226
251
 
227
252
  const group = await this.adapter.getStateAsync(id);
228
253
  if (!group) {
@@ -255,7 +280,8 @@ class Groups {
255
280
  }
256
281
 
257
282
 
258
- syncGroups(groups) {
283
+ async syncGroups() {
284
+ const groups = await this.getGroups();
259
285
  const chain = [];
260
286
  const usedGroupsIds = [];
261
287
  for (const j in groups) {
package/lib/ota.js CHANGED
@@ -62,6 +62,20 @@ class Ota {
62
62
  this.warn(`Update or check already in progress for '${device.name}', skipping...`);
63
63
  return;
64
64
  }
65
+ // do not attempt update for a device which has been deactivated or is unavailable
66
+ const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
67
+ if (stateObj && stateObj.common && stateObj.common.deactivated) {
68
+ this.warn(`Device ${obj.message.devId} is deactivated, skipping...`);
69
+ this.adapter.sendTo(obj.from, obj.command, {status: 'fail', device: getZbId(obj.message.devId), msg: 'Device is deactivated'}, obj.callback);
70
+ return;
71
+ }
72
+ const availablestate = await this.adapter.getStateAsync(obj.message.devId.replace(this.namespace + '.', '') + '.available');
73
+ const lqi = await this.adapter.getStateAsync(obj.message.devId.replace(this.namespace + '.', '') + '.link_quality');
74
+ if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
75
+ this.warn(`Device ${obj.message.devId} is marked unavailable, skipping...`);
76
+ this.adapter.sendTo(obj.from, obj.command, {status: 'fail', device: getZbId(obj.message.devId), msg: 'Device is marked unavailable'}, obj.callback);
77
+ return;
78
+ }
65
79
  this.inProgress.add(device.device.ieeeAddr);
66
80
  const result = {status: 'unknown', device: device ? device.name : null};
67
81
  try {
@@ -96,6 +110,18 @@ class Ota {
96
110
  this.error(`Update or check already in progress for '${device.name}', skipping...`);
97
111
  return;
98
112
  }
113
+ // do not attempt update for a device which has been deactivated or is unavailable
114
+ const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
115
+ if (stateObj && stateObj.common && stateObj.common.deactivated) {
116
+ this.warn(`Device ${obj.message.devId} is deactivated, skipping...`);
117
+ return;
118
+ }
119
+ const availablestate = await this.adapter.getStateAsync(obj.message.devId.replace(this.namespace + '.', '') + '.available');
120
+ const lqi = await this.adapter.getStateAsync(obj.message.devId.replace(this.namespace + '.', '') + '.link_quality');
121
+ if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
122
+ this.warn(`Device ${obj.message.devId} is marked unavailable, skipping...`);
123
+ return;
124
+ }
99
125
  this.inProgress.add(device.device.ieeeAddr);
100
126
  const result = {status: 'unknown', device: device ? device.name : null};
101
127
  try {
package/lib/rgb.js CHANGED
@@ -212,14 +212,44 @@ function colorArrayFromString(value) {
212
212
  return [{r:0,g:128,b:255}];
213
213
  }
214
214
 
215
+ function colorStringFromRGBArray(payload)
216
+ {
217
+ let rv = []
218
+ payload.forEach(element => {
219
+ rv.push(rgb_to_rgbstring(element));
220
+ });
221
+ return rv.toString();
222
+ }
223
+
215
224
  function hsv_to_cie(h,s,v){
216
225
  const rgb = hsvToRGB(h,s,v);
217
226
  return rgb_to_cie(rgb.r, rgb.g, rgb.b);
218
227
  }
219
228
 
229
+ function rgb_to_rgbstring(element) {
230
+ let col = '#';
231
+ if (element && element.hasOwnProperty("r"))
232
+ col = col + element.r.toString(16).padStart(2, '0');
233
+ else col = col + '00';
234
+ if (element && element.hasOwnProperty("g"))
235
+ col = col + element.g.toString(16).padStart(2, '0');
236
+ else col = col + '00';
237
+ if (element && element.hasOwnProperty("b"))
238
+ col = col + element.b.toString(16).padStart(2, '0');
239
+ else col = col + '00';
240
+ return col;
241
+ }
242
+
243
+
244
+ function hsvToRGBString(h,s,v) {
245
+ return rgb_to_rgbstring(hsvToRGB(h,s,v))
246
+ }
247
+
220
248
  exports.hsv_to_cie = hsv_to_cie;
221
249
  exports.rgb_to_cie = rgb_to_cie;
222
250
  exports.cie_to_rgb = cie_to_rgb;
223
251
  exports.hsvToRGB = hsvToRGB;
224
252
  exports.rgbToHSV = rgbToHSV;
225
253
  exports.colorArrayFromString = colorArrayFromString;
254
+ exports.colorStringFromRGBArray = colorStringFromRGBArray;
255
+ exports.hsvToRGBString = hsvToRGBString;
package/lib/states.js CHANGED
@@ -60,7 +60,7 @@ const unitLookup = {
60
60
  const timers = {};
61
61
 
62
62
  const states = {
63
- groups: {
63
+ /* groups: {
64
64
  id: 'groups',
65
65
  name: 'Groups',
66
66
  icon: undefined,
@@ -70,6 +70,7 @@ const states = {
70
70
  type: 'string',
71
71
  isOption: true,
72
72
  },
73
+ */
73
74
  link_quality: {
74
75
  id: 'link_quality',
75
76
  prop: 'linkquality',
@@ -4547,10 +4548,11 @@ const states = {
4547
4548
  name: 'Button ROW 2',
4548
4549
  icon: undefined,
4549
4550
  role: 'button',
4550
- write: false,
4551
+ write: true,
4551
4552
  read: true,
4552
4553
  type: 'boolean',
4553
4554
  getter: payload => (payload.action === 'row_2_on') ? true : (payload.action === 'row_2_off') ? false : undefined,
4555
+ setter: (value) => (value) ? 'row_2_on' : 'row_2_off',
4554
4556
  },
4555
4557
  rm01_row_3: {
4556
4558
  id: 'rm01_row_3',
@@ -4558,10 +4560,11 @@ const states = {
4558
4560
  name: 'Button ROW 3',
4559
4561
  icon: undefined,
4560
4562
  role: 'button',
4561
- write: false,
4563
+ write: true,
4562
4564
  read: true,
4563
4565
  type: 'boolean',
4564
4566
  getter: payload => (payload.action === 'row_3_on') ? true : (payload.action === 'row_3_off') ? false : undefined,
4567
+ setter: (value) => (value) ? 'row_3_on' : 'row_3_off',
4565
4568
  },
4566
4569
  rm01_row_4: {
4567
4570
  id: 'rm01_row_4',
@@ -4569,10 +4572,11 @@ const states = {
4569
4572
  name: 'Button ROW 4',
4570
4573
  icon: undefined,
4571
4574
  role: 'button',
4572
- write: false,
4575
+ write: true,
4573
4576
  read: true,
4574
4577
  type: 'boolean',
4575
4578
  getter: payload => (payload.action === 'row_4_on') ? true : (payload.action === 'row_4_off') ? false : undefined,
4579
+ setter: (value) => (value) ? 'row_4_on' : 'row_4_off',
4576
4580
  },
4577
4581
  left_top_click: {
4578
4582
  id: 'left_top_click',
@@ -5800,16 +5804,21 @@ const states = {
5800
5804
  speed:10,
5801
5805
  effect:'glow',
5802
5806
  };
5803
- if (options.hasOwnProperty('effect_speed'))
5807
+ if (options && options.hasOwnProperty('effect_speed'))
5804
5808
  effectjson.speed = options.effect_speed;
5805
- if (options.hasOwnProperty('effect_colors'))
5809
+ if (options && options.hasOwnProperty('effect_colors'))
5806
5810
  {
5807
5811
  effectjson.colors = rgb.colorArrayFromString(options.effect_colors);
5808
5812
  }
5809
5813
  effectjson.effect = value;
5810
5814
  return effectjson;
5815
+ },
5816
+ getter: (payload) => {
5817
+ if (payload && payload.effect && payload.effect.hasOwnProperty('effect')) return payload.effect.effect;
5818
+ return "steady";
5811
5819
  }
5812
- },
5820
+
5821
+ },
5813
5822
  effect_json: {
5814
5823
  id: 'effect_json',
5815
5824
  name: 'Effect',
@@ -5829,11 +5838,11 @@ const states = {
5829
5838
  speed:10,
5830
5839
  effect:'glow',
5831
5840
  };
5832
- if (options.hasOwnProperty('effect_speed'))
5841
+ if (options && options.hasOwnProperty('effect_speed'))
5833
5842
  effectjson.speed = options.effect_speed;
5834
- if (options.hasOwnProperty('effect_colors'))
5843
+ if (options && options.hasOwnProperty('effect_colors'))
5835
5844
  effectjson.colors = rgb.colorArrayFromString(options.effect_colors);
5836
- if (options.hasOwnProperty('effect_type'))
5845
+ if (options && options.hasOwnProperty('effect_type'))
5837
5846
  effectjson.effect = options.effect_type;
5838
5847
  value = JSON.stringify(effectjson);
5839
5848
  return effectjson;
@@ -5859,12 +5868,16 @@ const states = {
5859
5868
  speed:10,
5860
5869
  effect:'snake',
5861
5870
  };
5862
- if (options.hasOwnProperty('effect_type'))
5871
+ if (options && options.hasOwnProperty('effect_type'))
5863
5872
  effectjson.effect = options.effect_type;
5864
- if (options.hasOwnProperty('effect_colors'))
5873
+ if (options && options.hasOwnProperty('effect_colors'))
5865
5874
  effectjson.colors = rgb.colorArrayFromString(options.effect_colors);
5866
5875
  effectjson.speed = value;
5867
5876
  return effectjson;
5877
+ },
5878
+ getter: (payload) => {
5879
+ if (payload && payload.effect && payload.effect.hasOwnProperty('speed')) return payload.effect.speed;
5880
+ return 1;
5868
5881
  }
5869
5882
  },
5870
5883
 
@@ -5885,12 +5898,16 @@ const states = {
5885
5898
  effect:'sparkle',
5886
5899
  };
5887
5900
 
5888
- if (options.hasOwnProperty('effect_speed'))
5901
+ if (options && options.hasOwnProperty('effect_speed'))
5889
5902
  effectjson.speed = options.effect_speed;
5890
- if (options.hasOwnProperty('effect_type'))
5903
+ if (options && options.hasOwnProperty('effect_type'))
5891
5904
  effectjson.effect = options.effect_type;
5892
5905
  effectjson.colors = rgb.colorArrayFromString(value);
5893
5906
  return effectjson;
5907
+ },
5908
+ getter: (payload) => {
5909
+ if (payload && payload.effect && payload.effect.hasOwnProperty('colors')) return rgb.colorStringFromRGBArray(payload.effect.colors);
5910
+ return '#ffff00,#ff00ff,#00ffff,#0000ff,#00ff00,#ff0000';
5894
5911
  }
5895
5912
  },
5896
5913
 
@@ -5925,6 +5942,15 @@ const states = {
5925
5942
 
5926
5943
  };
5927
5944
  },
5945
+ getter: (payload) => {
5946
+ if (payload.color) {
5947
+ const c = payload.color;
5948
+ if (c.hasOwnProperty("h") && c.hasOwnProperty("s") && c.hasOwnProperty("b"))
5949
+ return rgb.hsvToRGBString(c.h, c.s, c.b * 100 / 255);
5950
+ if (c.hasOwnProperty("h") && c.hasOwnProperty("s") && c.hasOwnProperty("v"))
5951
+ return rgb.hsvToRGBString(c.h, c.s, c.v * 100);
5952
+ }
5953
+ },
5928
5954
  setterOpt: (value, options) => {
5929
5955
  const hasTransitionTime = options && options.hasOwnProperty('transition_time');
5930
5956
  const transitionTime = hasTransitionTime ? options.transition_time : 0;