iobroker.zigbee2mqtt 2.2.1 → 2.4.0

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/states.js CHANGED
@@ -56,8 +56,8 @@ const unitLookup = {
56
56
  'frequency': 'Hz',
57
57
  'power_factor': 'pf',
58
58
  'illuminance_lux': 'lx',
59
-
60
59
  };
60
+
61
61
  const timers = {};
62
62
 
63
63
  const states = {
@@ -72,7 +72,7 @@ const states = {
72
72
  type: 'number',
73
73
  min: 0,
74
74
  max: 255,
75
- def: 10,
75
+ def: 0,
76
76
  },
77
77
 
78
78
  available: {
@@ -86,6 +86,110 @@ const states = {
86
86
  type: 'boolean',
87
87
  def: false,
88
88
  },
89
+
90
+ color_read: {
91
+ id: 'color',
92
+ prop: 'action',
93
+ name: 'Color',
94
+ icon: undefined,
95
+ role: 'level.color.rgb',
96
+ write: false,
97
+ read: true,
98
+ type: 'string',
99
+ def: '#ffffff',
100
+ getter: (payload) => {
101
+ if (payload.action != 'color_wheel') {
102
+ return undefined;
103
+ }
104
+
105
+ if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
106
+ const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
107
+ return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
108
+ }
109
+ else {
110
+ return undefined;
111
+ }
112
+ },
113
+ },
114
+
115
+ simulated_brightness: {
116
+ id: 'simulated_brightness',
117
+ prop: 'brightness',
118
+ name: 'Simulated brightness',
119
+ icon: undefined,
120
+ role: 'level.dimmer',
121
+ write: true,
122
+ read: true,
123
+ type: 'number',
124
+ unit: '%',
125
+ def: 0,
126
+ getter: payload => {
127
+ return utils.bulbLevelToAdapterLevel(payload.brightness);
128
+ },
129
+ },
130
+
131
+ state: {
132
+ id: 'state',
133
+ name: 'Switch state',
134
+ icon: undefined,
135
+ role: 'switch',
136
+ write: true,
137
+ read: true,
138
+ type: 'boolean',
139
+ def: false,
140
+ getter: payload => (payload.state === 'ON'),
141
+ setter: (value) => (value) ? 'ON' : 'OFF',
142
+ },
143
+
144
+ brightness: {
145
+ id: 'brightness',
146
+ name: 'Brightness',
147
+ icon: undefined,
148
+ role: 'level.dimmer',
149
+ write: true,
150
+ read: true,
151
+ type: 'number',
152
+ unit: '%',
153
+ min: 0,
154
+ max: 100,
155
+ def: 100,
156
+ getter: payload => {
157
+ return utils.bulbLevelToAdapterLevel(payload.brightness);
158
+ },
159
+ setter: (value) => {
160
+ return utils.adapterLevelToBulbLevel(value);
161
+ }
162
+ },
163
+
164
+ brightness_move: {
165
+ id: 'brightness_move',
166
+ prop: 'brightness_move',
167
+ name: 'Dimming',
168
+ icon: undefined,
169
+ role: 'state',
170
+ write: true,
171
+ read: false,
172
+ type: 'number',
173
+ min: -50,
174
+ max: 50,
175
+ def: 0
176
+ },
177
+
178
+ colortemp_move: {
179
+ id: 'colortemp_move',
180
+ prop: 'color_temp_move',
181
+ name: 'Colortemp change',
182
+ icon: undefined,
183
+ role: 'state',
184
+ write: true,
185
+ read: false,
186
+ type: 'number',
187
+ min: -50,
188
+ max: 50,
189
+ def: 0
190
+ },
191
+
192
+ //#################################################################
89
193
  device_query: { // button to trigger device read
90
194
  id: 'device_query',
91
195
  prop: 'device_query',
@@ -462,22 +566,7 @@ const states = {
462
566
  isEvent: true,
463
567
  getter: payload => (payload.click === 'both_double') ? true : undefined,
464
568
  },
465
- state: {
466
- id: 'state',
467
- name: 'Switch state',
468
- icon: undefined,
469
- role: 'switch',
470
- write: true,
471
- read: true,
472
- type: 'boolean',
473
- getter: payload => (payload.state === 'ON'),
474
- setter: (value) => (value) ? 'ON' : 'OFF',
475
- setterOpt: (value, options) => {
476
- const stateValue = (value ? 'ON' : 'OFF');
477
- return { ...options, state: stateValue };
478
- },
479
- inOptions: true,
480
- },
569
+
481
570
  stateEp: {
482
571
  id: 'state',
483
572
  name: 'Switch state',
@@ -1182,37 +1271,7 @@ const states = {
1182
1271
  return utils.bulbLevelToAdapterLevel(payload.brightness);
1183
1272
  },
1184
1273
  },
1185
- brightness: {
1186
- id: 'brightness',
1187
- name: 'Brightness',
1188
- icon: undefined,
1189
- role: 'level.dimmer',
1190
- write: true,
1191
- read: true,
1192
- type: 'number',
1193
- unit: '%',
1194
- min: 0,
1195
- max: 100,
1196
- getter: payload => {
1197
- return utils.bulbLevelToAdapterLevel(payload.brightness);
1198
- },
1199
- setter: (value, options) => {
1200
- return utils.adapterLevelToBulbLevel(value);
1201
- },
1202
- setterOpt: (value, options) => {
1203
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
1204
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
1205
- const preparedOptions = { ...options, transition: transitionTime };
1206
- preparedOptions.brightness = utils.adapterLevelToBulbLevel(value);
1207
- return preparedOptions;
1208
- },
1209
- readResponse: (resp) => {
1210
- const respObj = resp[0];
1211
- if (respObj.status === 0 && respObj.attrData != undefined) {
1212
- return utils.bulbLevelToAdapterLevel(respObj.attrData);
1213
- }
1214
- },
1215
- },
1274
+
1216
1275
  colortemp: {
1217
1276
  id: 'colortemp',
1218
1277
  prop: 'color_temp',
@@ -5293,32 +5352,6 @@ const states = {
5293
5352
  min: -50,
5294
5353
  max: 50
5295
5354
  },
5296
- brightness_move: {
5297
- id: 'brightness_move',
5298
- prop: 'brightness_move',
5299
- name: 'Dimming',
5300
- icon: undefined,
5301
- role: 'state',
5302
- write: true,
5303
- read: false,
5304
- type: 'number',
5305
- min: -50,
5306
- max: 50,
5307
- def: 0
5308
- },
5309
- colortemp_move: {
5310
- id: 'colortemp_move',
5311
- prop: 'color_temp_move',
5312
- name: 'Colortemp change',
5313
- icon: undefined,
5314
- role: 'state',
5315
- write: true,
5316
- read: false,
5317
- type: 'number',
5318
- min: -50,
5319
- max: 50,
5320
- def: 0
5321
- },
5322
5355
  hue_move: {
5323
5356
  id: 'hue_move',
5324
5357
  prop: 'hue_move',
@@ -35,15 +35,47 @@ class StatesController {
35
35
  this.adapter.log.warn(`--->>> fromZ2M -> ${device.ieee_address} states: ${JSON.stringify(messageObj)}`);
36
36
  }
37
37
 
38
- for (const [key, value] of Object.entries(messageObj.payload)) {
39
- let states;
40
- if (key == 'action') {
41
- states = device.states.filter(x => (x.prop && x.prop == key));
42
- } else {
43
- states = device.states.filter(x => (x.prop && x.prop == key) || x.id == key);
44
- }
38
+ // Is an action
39
+ if (Object.keys(messageObj.payload).includes('action')) {
40
+ const states = device.states.filter(x => (x.prop && x.prop == 'action'));
45
41
 
46
42
  for (const state of states) {
43
+ const stateName = `${device.ieee_address}.${state.id}`;
44
+
45
+ // It may be that the state has not yet been created!
46
+ if (!this.createCache[device.ieee_address] || !this.createCache[device.ieee_address][state.id] || !this.createCache[device.ieee_address][state.id].created) {
47
+ incStatsQueue[incStatsQueue.length] = messageObj;
48
+ continue;
49
+ }
50
+
51
+ if (!state.getter) {
52
+ this.adapter.log.error(`Action ${stateName} has no getter, this must not be!`);
53
+ continue;
54
+ }
55
+
56
+ try {
57
+ if (state.isEvent && state.isEvent == true) {
58
+ if (state.type == 'boolean') {
59
+ await this.setStateWithTimeoutAsync(stateName, state.getter(messageObj.payload), 300);
60
+ }
61
+ else {
62
+ await this.setStateSafelyAsync(stateName, state.getter(messageObj.payload));
63
+ }
64
+ }
65
+ else {
66
+ await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
67
+ }
68
+ } catch (err) {
69
+ incStatsQueue[incStatsQueue.length] = messageObj;
70
+ this.adapter.log.debug(`Can not set ${stateName}, queue state in incStatsQueue!`);
71
+ }
72
+ }
73
+ }
74
+ // Is not an action
75
+ else {
76
+ for (const [key, value] of Object.entries(messageObj.payload)) {
77
+ const state = device.states.find(x => (x.prop && x.prop == key) || x.id == key);
78
+
47
79
  if (!state) {
48
80
  continue;
49
81
  }
@@ -53,28 +85,20 @@ class StatesController {
53
85
  // It may be that the state has not yet been created!
54
86
  if (!this.createCache[device.ieee_address] || !this.createCache[device.ieee_address][state.id] || !this.createCache[device.ieee_address][state.id].created) {
55
87
  incStatsQueue[incStatsQueue.length] = messageObj;
56
- //this.adapter.log.debug(`State ${stateName} is not yet created, queue state in incStatsQueue!`);
57
88
  continue;
58
89
  }
59
90
 
60
91
  try {
61
- if (state.isEvent) {
62
- if (state.getter) {
63
- await this.setStateWithTimeoutAsync(stateName, state.getter(messageObj.payload), 300);
64
- } else {
65
- await this.setStateWithTimeoutAsync(stateName, value, 300);
66
- }
92
+ if (state.getter) {
93
+ await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
67
94
  } else {
68
- if (state.getter) {
69
- await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
70
- } else {
71
- await this.setStateChangedSafelyAsync(stateName, value);
72
- }
95
+ await this.setStateChangedSafelyAsync(stateName, value);
73
96
  }
74
97
  } catch (err) {
75
98
  incStatsQueue[incStatsQueue.length] = messageObj;
76
99
  this.adapter.log.debug(`Can not set ${stateName}, queue state in incStatsQueue!`);
77
100
  }
101
+
78
102
  }
79
103
  }
80
104
  }
@@ -36,6 +36,11 @@ class Z2mController {
36
36
  stateID = deviceState.prop;
37
37
  }
38
38
 
39
+ if (deviceState.setattr) {
40
+ stateID = deviceState.setattr;
41
+ }
42
+
43
+
39
44
  const controlObj = {
40
45
  payload: {
41
46
  [stateID]: stateVal
@@ -44,7 +49,7 @@ class Z2mController {
44
49
  };
45
50
 
46
51
  // set stats with the mentioned role or ids always immediately to ack = true, because these are not reported back by Zigbee2MQTT
47
- if (['button'].includes(deviceState.role) || ['brightness_move', 'color_temp_move'].includes(stateID)) {
52
+ if (['button'].includes(deviceState.role) || ['brightness_move', 'colortemp_move', 'brightness_move', 'effect'].includes(deviceState.id)) {
48
53
  this.adapter.setState(id, state, true);
49
54
  }
50
55
 
package/main.js CHANGED
@@ -46,7 +46,7 @@ class Zigbee2mqtt extends core.Adapter {
46
46
 
47
47
  async onReady() {
48
48
  statesController = new StatesController(this, deviceCache, groupCache, logCustomizations, createCache);
49
- deviceController = new DeviceController(this, deviceCache, groupCache, this.config, createCache);
49
+ deviceController = new DeviceController(this, deviceCache, groupCache, this.config, logCustomizations, createCache);
50
50
  z2mController = new Z2mController(this, deviceCache, groupCache, logCustomizations);
51
51
 
52
52
  // Initialize your adapter here
@@ -128,7 +128,7 @@ class Zigbee2mqtt extends core.Adapter {
128
128
  wsClient.on('close', async () => {
129
129
  this.setStateChangedAsync('info.connection', false, true);
130
130
  await statesController.setAllAvailableToFalse();
131
- this.log.warn('Websocket disconnectet');
131
+ this.log.warn('Websocket disconnected');
132
132
  });
133
133
  }
134
134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee2mqtt",
3
- "version": "2.2.1",
3
+ "version": "2.4.0",
4
4
  "description": "Zigbee2MQTT adapter for ioBroker",
5
5
  "author": {
6
6
  "name": "Dennis Rathjen",
@@ -24,19 +24,19 @@
24
24
  "aedes-persistence-nedb": "^2.0.3",
25
25
  "mqtt": "^4.3.7",
26
26
  "net": "^1.0.2",
27
- "ws": "^8.9.0"
27
+ "ws": "^8.10.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
31
31
  "@alcalzone/release-script-plugin-license": "^3.5.9",
32
32
  "@alcalzone/release-script": "^3.5.9",
33
- "@iobroker/adapter-dev": "^1.1.0",
33
+ "@iobroker/adapter-dev": "^1.2.0",
34
34
  "@iobroker/testing": "^4.1.0",
35
35
  "@tsconfig/node14": "^1.0.3",
36
36
  "@types/chai": "^4.3.3",
37
37
  "@types/chai-as-promised": "^7.1.5",
38
38
  "@types/mocha": "^10.0.0",
39
- "@types/node": "^18.11.3",
39
+ "@types/node": "^18.11.9",
40
40
  "@types/proxyquire": "^1.3.28",
41
41
  "@types/sinon": "^10.0.13",
42
42
  "@types/sinon-chai": "^3.2.8",