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/README.md +13 -1
- package/admin/i18n/de/translations.json +2 -1
- package/admin/i18n/en/translations.json +2 -1
- package/admin/i18n/es/translations.json +2 -1
- package/admin/i18n/fr/translations.json +2 -1
- package/admin/i18n/it/translations.json +2 -1
- package/admin/i18n/nl/translations.json +2 -1
- package/admin/i18n/pl/translations.json +2 -1
- package/admin/i18n/pt/translations.json +2 -1
- package/admin/i18n/ru/translations.json +2 -1
- package/admin/i18n/uk/translations.json +25 -0
- package/admin/i18n/zh-cn/translations.json +2 -1
- package/admin/jsonConfig.json +5 -0
- package/io-package.json +33 -28
- package/lib/deviceController.js +90 -67
- package/lib/exposes.js +216 -224
- package/lib/states.js +108 -75
- package/lib/statesController.js +43 -19
- package/lib/z2mController.js +6 -1
- package/main.js +2 -2
- package/package.json +4 -4
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:
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
package/lib/statesController.js
CHANGED
|
@@ -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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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.
|
|
62
|
-
|
|
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
|
-
|
|
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
|
}
|
package/lib/z2mController.js
CHANGED
|
@@ -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', '
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|