iobroker.zigbee2mqtt 3.0.13 → 3.0.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.
- package/README.md +6 -0
- package/io-package.json +27 -27
- package/lib/deviceController.js +7 -5
- package/lib/exposes.js +59 -34
- package/lib/mqttServerController.js +1 -3
- package/lib/rgb.js +7 -16
- package/lib/statesController.js +16 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,6 +22,12 @@ This adapter allows to control the data points of the devices of a Zigbee2MQTT i
|
|
|
22
22
|
[Adapter Documentation](https://github.com/arteck/ioBroker.zigbee2mqtt/blob/main/docs/wiki.md)
|
|
23
23
|
|
|
24
24
|
## Changelog
|
|
25
|
+
### 3.0.15 (2026-01-27)
|
|
26
|
+
* (arteck) update
|
|
27
|
+
|
|
28
|
+
### 3.0.14 (2026-01-27)
|
|
29
|
+
* (arteck) back to sharp 0.33.5
|
|
30
|
+
|
|
25
31
|
### 3.0.13 (2026-01-25)
|
|
26
32
|
* (arteck) add action dp
|
|
27
33
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee2mqtt",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.15",
|
|
5
5
|
"news": {
|
|
6
|
+
"3.0.15": {
|
|
7
|
+
"en": "update",
|
|
8
|
+
"de": "aktualisierung",
|
|
9
|
+
"ru": "обновление",
|
|
10
|
+
"pt": "atualizar",
|
|
11
|
+
"nl": "bijwerken",
|
|
12
|
+
"fr": "mise à jour",
|
|
13
|
+
"it": "aggiornamento",
|
|
14
|
+
"es": "actualización",
|
|
15
|
+
"pl": "aktualizacja",
|
|
16
|
+
"uk": "оновлення",
|
|
17
|
+
"zh-cn": "更新"
|
|
18
|
+
},
|
|
19
|
+
"3.0.14": {
|
|
20
|
+
"en": "back to sharp 0.33.5",
|
|
21
|
+
"de": "zurück zu sharp 0,33,5",
|
|
22
|
+
"ru": "вернуться к sharp 0.33.5",
|
|
23
|
+
"pt": "voltar ao valor nítido 0,33,5",
|
|
24
|
+
"nl": "terug naar sharp 0,335",
|
|
25
|
+
"fr": "retour à la version 0.33.5",
|
|
26
|
+
"it": "torna a 0,33,5 tagliente",
|
|
27
|
+
"es": "de nuevo al 0,33,5",
|
|
28
|
+
"pl": "powrót do sharp 0,33,5",
|
|
29
|
+
"uk": "назад до sharp 0.33.5",
|
|
30
|
+
"zh-cn": "回到清晰的 0.33.5"
|
|
31
|
+
},
|
|
6
32
|
"3.0.13": {
|
|
7
33
|
"en": "add action dp",
|
|
8
34
|
"de": "aktion dp hinzufügen",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "kolejka w górę wiadomości parsing\nWsparcie dla niedomyślnych tematów bazowych MQTT",
|
|
68
94
|
"uk": "чергування повідомлень\nПідтримка нерозголошення MQTT базових тем",
|
|
69
95
|
"zh-cn": "排队分析信件\n支持非默认 MQTT 基础主题"
|
|
70
|
-
},
|
|
71
|
-
"3.0.8": {
|
|
72
|
-
"en": "fix device is deleted\nfix translation",
|
|
73
|
-
"de": "fix device wird gelöscht\nbersetzung",
|
|
74
|
-
"ru": "фиксировать устройство удалено\nперевод",
|
|
75
|
-
"pt": "dispositivo de correção é excluído\ncorrigir tradução",
|
|
76
|
-
"nl": "fix apparaat wordt verwijderd\nfix vertaling",
|
|
77
|
-
"fr": "le dispositif de correction est supprimé\ncorriger la traduction",
|
|
78
|
-
"it": "dispositivo di correzione viene eliminato\ncorrezione della traduzione",
|
|
79
|
-
"es": "dispositivo de solución se elimina\ntraducción",
|
|
80
|
-
"pl": "urządzenie naprawcze zostaje usunięte\ntłumaczenie",
|
|
81
|
-
"uk": "видалити пристрій\nфіксувати переклад",
|
|
82
|
-
"zh-cn": "固定设备被删除\n固定翻译"
|
|
83
|
-
},
|
|
84
|
-
"3.0.7": {
|
|
85
|
-
"en": "fix jsconconf",
|
|
86
|
-
"de": "fix jsconf",
|
|
87
|
-
"ru": "исправить jsconconf",
|
|
88
|
-
"pt": "corrigir jsconconf",
|
|
89
|
-
"nl": "jsconconf repareren",
|
|
90
|
-
"fr": "corriger jsconconf",
|
|
91
|
-
"it": "correzione jsconconf",
|
|
92
|
-
"es": "jsconf",
|
|
93
|
-
"pl": "fix jsconconf",
|
|
94
|
-
"uk": "закріпити jsconconf",
|
|
95
|
-
"zh-cn": "修复 jsconconconf"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"messages": [
|
package/lib/deviceController.js
CHANGED
|
@@ -235,7 +235,6 @@ class DeviceController {
|
|
|
235
235
|
type: 'boolean',
|
|
236
236
|
setter: (value) => (value ? scene.id : undefined),
|
|
237
237
|
};
|
|
238
|
-
|
|
239
238
|
newDevice.states.push(sceneSate);
|
|
240
239
|
}
|
|
241
240
|
|
|
@@ -299,12 +298,15 @@ class DeviceController {
|
|
|
299
298
|
if (device.ieee_address.includes('group_')) {
|
|
300
299
|
deviceObj.native.groupDevice = true;
|
|
301
300
|
deviceObj.common.statusStates.onlineId = `${this.adapter.name}.${this.adapter.instance}.${device.ieee_address}.available`;
|
|
302
|
-
}
|
|
301
|
+
}
|
|
302
|
+
// Disabled Device
|
|
303
|
+
else if (device.disabled || device.disabled == true) {
|
|
303
304
|
// Placeholder for possible later logic
|
|
304
|
-
} else { // Only the onlineId is set if the device is not disabled
|
|
305
|
-
deviceObj.common.statusStates.onlineId = `${this.adapter.name}.${this.adapter.instance}.${device.ieee_address}.available`;
|
|
306
305
|
}
|
|
307
|
-
|
|
306
|
+
// Only the onlineId is set if the device is not disabled
|
|
307
|
+
else {
|
|
308
|
+
deviceObj.common.statusStates.onlineId = `${this.adapter.name}.${this.adapter.instance}.${device.ieee_address}.available`;
|
|
309
|
+
}
|
|
308
310
|
await this.adapter.extendObjectAsync(device.ieee_address, deviceObj);
|
|
309
311
|
this.createCache[device.ieee_address] = { name: deviceName, description: description };
|
|
310
312
|
}
|
package/lib/exposes.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
'use strict';
|
|
4
2
|
|
|
5
3
|
const statesDefs = require('./states').states;
|
|
@@ -622,7 +620,7 @@ access = z2mAccess.ALL;
|
|
|
622
620
|
if (
|
|
623
621
|
payload[stateName] &&
|
|
624
622
|
payload[stateName].hasOwnProperty('h') &&
|
|
625
|
-
payload[stateName].hasOwnProperty('s')
|
|
623
|
+
payload[stateName].hasOwnProperty('s') &&
|
|
626
624
|
payload[stateName].hasOwnProperty('b')
|
|
627
625
|
) {
|
|
628
626
|
return rgb.hsvToRGBString(
|
|
@@ -757,18 +755,13 @@ access = z2mAccess.ALL;
|
|
|
757
755
|
}
|
|
758
756
|
}
|
|
759
757
|
if (state) {
|
|
760
|
-
|
|
761
|
-
|
|
758
|
+
pushToStates(state, expose.access);
|
|
759
|
+
}
|
|
762
760
|
break;
|
|
763
761
|
|
|
764
|
-
case 'enum':
|
|
762
|
+
case 'enum':
|
|
765
763
|
switch (expose.name) {
|
|
766
764
|
case 'action': {
|
|
767
|
-
//generate an 'action' state\
|
|
768
|
-
state = genState(expose);
|
|
769
|
-
state.isEvent = true;
|
|
770
|
-
pushToStates(state, expose.access);
|
|
771
|
-
|
|
772
765
|
if (!Array.isArray(expose.values)) {
|
|
773
766
|
break;
|
|
774
767
|
}
|
|
@@ -806,8 +799,8 @@ access = z2mAccess.ALL;
|
|
|
806
799
|
// is release -> hold state? - skip
|
|
807
800
|
if (
|
|
808
801
|
config.simpleHoldReleaseState == true &&
|
|
809
|
-
|
|
810
|
-
|
|
802
|
+
actionName.endsWith('release') &&
|
|
803
|
+
expose.values.find((x) => x == actionName.replace('release', 'hold'))
|
|
811
804
|
) {
|
|
812
805
|
continue;
|
|
813
806
|
}
|
|
@@ -815,8 +808,8 @@ access = z2mAccess.ALL;
|
|
|
815
808
|
// is stop - move state? - skip
|
|
816
809
|
if (
|
|
817
810
|
config.simpleMoveStopState == true &&
|
|
818
|
-
|
|
819
|
-
|
|
811
|
+
actionName.endsWith('stop') &&
|
|
812
|
+
expose.values.find((x) => x.includes(actionName.replace('stop', 'move')))
|
|
820
813
|
) {
|
|
821
814
|
continue;
|
|
822
815
|
}
|
|
@@ -824,16 +817,17 @@ access = z2mAccess.ALL;
|
|
|
824
817
|
// is release -> press state? - skip
|
|
825
818
|
if (
|
|
826
819
|
config.simplePressReleaseState == true &&
|
|
827
|
-
|
|
828
|
-
|
|
820
|
+
actionName.endsWith('release') &&
|
|
821
|
+
expose.values.find((x) => x == actionName.replace('release', 'press'))
|
|
829
822
|
) {
|
|
830
823
|
continue;
|
|
831
824
|
}
|
|
832
825
|
|
|
833
826
|
// is hold -> release state ?
|
|
834
|
-
if (
|
|
835
|
-
|
|
836
|
-
|
|
827
|
+
if (
|
|
828
|
+
config.simpleHoldReleaseState == true &&
|
|
829
|
+
actionName.endsWith('hold') &&
|
|
830
|
+
expose.values.find((x) => x == actionName.replace('hold', 'release'))
|
|
837
831
|
) {
|
|
838
832
|
pushToStates(
|
|
839
833
|
{
|
|
@@ -861,10 +855,12 @@ access = z2mAccess.ALL;
|
|
|
861
855
|
},
|
|
862
856
|
expose.access
|
|
863
857
|
);
|
|
864
|
-
}
|
|
858
|
+
}
|
|
859
|
+
// is move -> stop state ?
|
|
860
|
+
else if (
|
|
865
861
|
config.simpleMoveStopState == true &&
|
|
866
|
-
|
|
867
|
-
|
|
862
|
+
actionName.includes('move') &&
|
|
863
|
+
expose.values.find((x) => x == `${actionName.split('_')[0]}_stop`)
|
|
868
864
|
) {
|
|
869
865
|
pushToStates(
|
|
870
866
|
{
|
|
@@ -889,10 +885,12 @@ access = z2mAccess.ALL;
|
|
|
889
885
|
},
|
|
890
886
|
expose.access
|
|
891
887
|
);
|
|
892
|
-
}
|
|
888
|
+
}
|
|
889
|
+
// is press -> release state ?
|
|
890
|
+
else if (
|
|
893
891
|
config.simplePressReleaseState == true &&
|
|
894
|
-
|
|
895
|
-
|
|
892
|
+
actionName.endsWith('press') &&
|
|
893
|
+
expose.values.find((x) => x == actionName.replace('press', 'release'))
|
|
896
894
|
) {
|
|
897
895
|
pushToStates(
|
|
898
896
|
{
|
|
@@ -971,8 +969,8 @@ access = z2mAccess.ALL;
|
|
|
971
969
|
|
|
972
970
|
if (
|
|
973
971
|
payload.action_color &&
|
|
974
|
-
|
|
975
|
-
|
|
972
|
+
payload.action_color.hasOwnProperty('x') &&
|
|
973
|
+
payload.action_color.hasOwnProperty('y')
|
|
976
974
|
) {
|
|
977
975
|
const colorval = rgb.cie_to_rgb(
|
|
978
976
|
payload.action_color.x,
|
|
@@ -980,9 +978,9 @@ access = z2mAccess.ALL;
|
|
|
980
978
|
);
|
|
981
979
|
return (
|
|
982
980
|
`#${
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
981
|
+
utils.decimalToHex(colorval[0])
|
|
982
|
+
}${utils.decimalToHex(colorval[1])
|
|
983
|
+
}${utils.decimalToHex(colorval[2])}`
|
|
986
984
|
);
|
|
987
985
|
}
|
|
988
986
|
return undefined;
|
|
@@ -1077,7 +1075,34 @@ access = z2mAccess.ALL;
|
|
|
1077
1075
|
},
|
|
1078
1076
|
expose.access
|
|
1079
1077
|
);
|
|
1080
|
-
}
|
|
1078
|
+
}
|
|
1079
|
+
// else if (actionName == 'hue_move') {
|
|
1080
|
+
// pushToStates({
|
|
1081
|
+
// id: 'hue_move',
|
|
1082
|
+
// name: 'Hue move rate',
|
|
1083
|
+
// icon: undefined,
|
|
1084
|
+
// role: 'level.color.hue',
|
|
1085
|
+
// write: false,
|
|
1086
|
+
// read: true,
|
|
1087
|
+
// type: 'number',
|
|
1088
|
+
// min: 0,
|
|
1089
|
+
// max: 360,
|
|
1090
|
+
// def: 0,
|
|
1091
|
+
// isEvent: true,
|
|
1092
|
+
// getter: (payload) => {
|
|
1093
|
+
// if (payload.action != 'hue_move') {
|
|
1094
|
+
// return undefined;
|
|
1095
|
+
// }
|
|
1096
|
+
|
|
1097
|
+
// if (payload.action_level) {
|
|
1098
|
+
// return payload.action_level;
|
|
1099
|
+
// } else {
|
|
1100
|
+
// return undefined;
|
|
1101
|
+
// }
|
|
1102
|
+
// }
|
|
1103
|
+
// }, expose.access);
|
|
1104
|
+
// }
|
|
1105
|
+
else {
|
|
1081
1106
|
pushToStates(
|
|
1082
1107
|
{
|
|
1083
1108
|
id: actionName.replace(/\*/g, ''),
|
|
@@ -1099,7 +1124,7 @@ access = z2mAccess.ALL;
|
|
|
1099
1124
|
// Can the device simulated_brightness?
|
|
1100
1125
|
if (
|
|
1101
1126
|
definition.options &&
|
|
1102
|
-
|
|
1127
|
+
definition.options.find((x) => x.property == 'simulated_brightness')
|
|
1103
1128
|
) {
|
|
1104
1129
|
pushToStates(statesDefs.simulated_brightness, z2mAccess.STATE);
|
|
1105
1130
|
}
|
|
@@ -1114,7 +1139,7 @@ access = z2mAccess.ALL;
|
|
|
1114
1139
|
pushToStates(state, expose.access);
|
|
1115
1140
|
}
|
|
1116
1141
|
break;
|
|
1117
|
-
|
|
1142
|
+
|
|
1118
1143
|
case 'binary':
|
|
1119
1144
|
if (expose.endpoint) {
|
|
1120
1145
|
state = genState(expose);
|
|
@@ -24,8 +24,7 @@ class MqttServerController {
|
|
|
24
24
|
const db = new NedbPersistence({
|
|
25
25
|
path: `${core.getAbsoluteInstanceDataDir(this.adapter)}/mqttData`,
|
|
26
26
|
prefix: '',
|
|
27
|
-
});
|
|
28
|
-
|
|
27
|
+
});
|
|
29
28
|
const aedes = Aedes({ persistence: db });
|
|
30
29
|
mqttServer = net.createServer(aedes.handle);
|
|
31
30
|
mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
|
|
@@ -43,7 +42,6 @@ class MqttServerController {
|
|
|
43
42
|
*/
|
|
44
43
|
async createDummyMQTTServer() {
|
|
45
44
|
try {
|
|
46
|
-
|
|
47
45
|
const aedes = Aedes();
|
|
48
46
|
mqttServer = net.createServer(aedes.handle);
|
|
49
47
|
mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
|
package/lib/rgb.js
CHANGED
|
@@ -58,17 +58,12 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
58
58
|
|
|
59
59
|
const z = 1.0 - x - y;
|
|
60
60
|
const Y = (brightness / 254).toFixed(2);
|
|
61
|
-
|
|
62
61
|
const X = (Y / y) * x;
|
|
63
|
-
|
|
64
62
|
const Z = (Y / y) * z;
|
|
65
63
|
|
|
66
64
|
//Convert to RGB using Wide RGB D65 conversion
|
|
67
|
-
|
|
68
65
|
let red = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
|
|
69
|
-
|
|
70
66
|
let green = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
|
|
71
|
-
|
|
72
67
|
let blue = X * 0.051713 - Y * 0.121364 + Z * 1.01153;
|
|
73
68
|
|
|
74
69
|
//If red, green or blue is larger than 1.0 set it back to the maximum of 1.0
|
|
@@ -134,15 +129,11 @@ function rgb_to_cie(red, green, blue) {
|
|
|
134
129
|
let x = (X / (X + Y + Z)).toFixed(4);
|
|
135
130
|
let y = (Y / (X + Y + Z)).toFixed(4);
|
|
136
131
|
|
|
137
|
-
|
|
138
132
|
if (isNaN(x)) {
|
|
139
|
-
|
|
140
133
|
x = 0;
|
|
141
134
|
}
|
|
142
135
|
|
|
143
|
-
|
|
144
136
|
if (isNaN(y)) {
|
|
145
|
-
|
|
146
137
|
y = 0;
|
|
147
138
|
}
|
|
148
139
|
|
|
@@ -234,20 +225,20 @@ function rgbToHSV(r, g, b, numeric) {
|
|
|
234
225
|
break;
|
|
235
226
|
}
|
|
236
227
|
if (numeric) {
|
|
237
|
-
return {
|
|
238
|
-
|
|
228
|
+
return {
|
|
229
|
+
|
|
239
230
|
h: Math.round(h * 360),
|
|
240
231
|
s: Math.round(s * 100),
|
|
241
232
|
v: Math.round(v * 100),
|
|
242
233
|
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
|
|
246
237
|
h: (h * 360).toFixed(3),
|
|
247
238
|
s: (s * 100).toFixed(3),
|
|
248
239
|
v: (v * 100).toFixed(3),
|
|
249
|
-
|
|
250
|
-
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
251
242
|
|
|
252
243
|
/**
|
|
253
244
|
*
|
package/lib/statesController.js
CHANGED
|
@@ -123,15 +123,19 @@ class StatesController {
|
|
|
123
123
|
// Is an action
|
|
124
124
|
if (state.prop && state.prop == 'action') {
|
|
125
125
|
actionStates.push(state);
|
|
126
|
-
}
|
|
127
|
-
|
|
126
|
+
}
|
|
127
|
+
// Is not an action
|
|
128
128
|
// check if its a motion sensor (occupancy state) and if configuration is set to update state every time
|
|
129
129
|
// if yes, use setStateSafelyAsync instead of setStateChangedSafelyAsync
|
|
130
|
-
|
|
130
|
+
else if (
|
|
131
|
+
this.adapter.config.allwaysUpdateOccupancyState === true &&
|
|
132
|
+
state.id === 'occupancy' &&
|
|
133
|
+
value === true
|
|
131
134
|
) {
|
|
132
135
|
await this.setStateSafelyAsync(stateName, value);
|
|
133
|
-
}
|
|
134
|
-
|
|
136
|
+
}
|
|
137
|
+
// end section for motion sensor update
|
|
138
|
+
else {
|
|
135
139
|
if (state.getter) {
|
|
136
140
|
await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
|
|
137
141
|
} else {
|
|
@@ -150,20 +154,19 @@ class StatesController {
|
|
|
150
154
|
|
|
151
155
|
try {
|
|
152
156
|
if (state.isEvent && state.isEvent == true) {
|
|
153
|
-
const gettr = state.getter(messageObj.payload);
|
|
154
157
|
if (state.type == 'boolean') {
|
|
155
|
-
await this.setStateWithTimeoutAsync(stateName,
|
|
158
|
+
await this.setStateWithTimeoutAsync(stateName, state.getter(messageObj.payload), 450);
|
|
156
159
|
} else {
|
|
157
|
-
await this.setStateSafelyAsync(stateName,
|
|
160
|
+
await this.setStateSafelyAsync(stateName, state.getter(messageObj.payload));
|
|
158
161
|
}
|
|
159
|
-
// publish the action into action dp
|
|
160
|
-
if (state.prop && state.prop == 'action') {
|
|
161
|
-
await this.setStateSafelyAsync(`${device.ieee_address}.action`, messageObj.payload.action);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
162
|
} else {
|
|
165
163
|
await this.setStateChangedSafelyAsync(stateName, state.getter(messageObj.payload));
|
|
166
164
|
}
|
|
165
|
+
|
|
166
|
+
// publish the action into action dp
|
|
167
|
+
if (state.prop && state.prop == 'action') {
|
|
168
|
+
await this.setStateSafelyAsync(`${device.ieee_address}.action`, messageObj.payload.action);
|
|
169
|
+
}
|
|
167
170
|
} catch (err) {
|
|
168
171
|
incStatsQueue[incStatsQueue.length] = messageObj;
|
|
169
172
|
this.adapter.log.debug(`Can not set ${stateName}, queue state in incStatsQueue!`);
|
|
@@ -212,7 +215,6 @@ class StatesController {
|
|
|
212
215
|
}
|
|
213
216
|
timeOutCache[stateName] = setTimeout(() => {
|
|
214
217
|
this.adapter.setStateAsync(stateName, !value, true);
|
|
215
|
-
|
|
216
218
|
}, timeout);
|
|
217
219
|
}
|
|
218
220
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee2mqtt",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.15",
|
|
4
4
|
"description": "Zigbee2MQTT adapter for ioBroker",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Dennis Rathjen and Arthur Rupp",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"mqtt": "^5.14.1",
|
|
32
32
|
"net": "^1.0.2",
|
|
33
33
|
"node-schedule": "^2.1.1",
|
|
34
|
-
"sharp": "^0.
|
|
34
|
+
"sharp": "^0.33.5",
|
|
35
35
|
"ws": "^8.18.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|