iobroker.zigbee2mqtt 2.2.0 → 2.3.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 +12 -1
- package/admin/i18n/de/translations.json +1 -1
- package/io-package.json +27 -25
- package/lib/deviceController.js +17 -10
- package/lib/exposes.js +173 -61
- package/lib/states.js +109 -77
- package/lib/statesController.js +9 -1
- package/lib/z2mController.js +4 -4
- package/main.js +3 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -30,11 +30,22 @@ This adapter allows to control the data points of the devices of a Zigbee2MQTT i
|
|
|
30
30
|
Placeholder for the next version (at the beginning of the line):
|
|
31
31
|
### **WORK IN PROGRESS**
|
|
32
32
|
-->
|
|
33
|
+
### 2.3.0 (2022-10-30)
|
|
34
|
+
|
|
35
|
+
- (o0shojo0o) added support for the `toggle` of states that support this.
|
|
36
|
+
- (o0shojo0o) added correct handling of `color_move` and `color_temperature_move`
|
|
37
|
+
|
|
38
|
+
### 2.2.1 (2022-10-25)
|
|
39
|
+
|
|
40
|
+
- (o0shojo0o) fix state roles and access
|
|
41
|
+
- (o0shojo0o) fix state handling
|
|
42
|
+
- (o0shojo0o) fix createZ2MMessage
|
|
43
|
+
|
|
33
44
|
### 2.2.0 (2022-10-20)
|
|
34
45
|
|
|
35
46
|
- (o0shojo0o) added support for [Lidl HG06467 effects](https://www.zigbee2mqtt.io/devices/HG06467.html#trigger-effects)
|
|
36
47
|
- (o0shojo0o) added support for hs color
|
|
37
|
-
- (o0shojo0o) simulated_brightness data point is added only for supported devices
|
|
48
|
+
- (o0shojo0o) `simulated_brightness` data point is added only for supported devices
|
|
38
49
|
|
|
39
50
|
### 2.1.1 (2022-10-16)
|
|
40
51
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"External MQTT-Server Port": "Externer MQTT-Server Port",
|
|
14
14
|
"MQTT-Server IP-Address bind": "MQTT-Server IP-Adresse binden",
|
|
15
15
|
"MQTT-Server Port": "MQTT-Server-Port",
|
|
16
|
-
"Configure your Zigbee2MQTT WebUi connection": "Zigbee2MQTT WebUi Verbindung
|
|
16
|
+
"Configure your Zigbee2MQTT WebUi connection": "Konfiguration der Zigbee2MQTT WebUi Verbindung",
|
|
17
17
|
"WebUi Address": "WebUi Adresse",
|
|
18
18
|
"WebUi Port": "WebUi Port",
|
|
19
19
|
"Color configurations": "Farbkonfigurationen",
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee2mqtt",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"2.3.0": {
|
|
7
|
+
"en": "added support for the `toggle` of states that support this.\nadded correct handling of `color_move` and `color_temperature_move`",
|
|
8
|
+
"de": "zusätzliche unterstützung für den kippen von staaten, die dies unterstützen.\nkorrekte handhabung von color_move und color_temperature_move",
|
|
9
|
+
"ru": "добавлена поддержка в отношении государств, которые поддерживают это.\nдобавлена правильная обработка color_move и color_temperature_move",
|
|
10
|
+
"pt": "acrescentou apoio para o conjunto de estados que apoiam isso.\nadicionado manuseio correto de color_move e color_temperature_move",
|
|
11
|
+
"nl": "steun toegevoegd voor de toggle van staten die dit ondersteunen.\nvoegde de juiste kleding en kleurtemperatuur toe",
|
|
12
|
+
"fr": "a ajouté un soutien pour la lutte des etats qui appuient cela.\nla manipulation correcte de color_move et color_temperature_move",
|
|
13
|
+
"it": "ha aggiunto il sostegno per la lotta di stati che sostengono questo.\naggiunto corretto trattamento di colore_move e colore_temperature_move",
|
|
14
|
+
"es": "agregó apoyo para la lucha de estados que apoyan esto.\nañadido correcto manejo de color_move y color_temperature_move",
|
|
15
|
+
"pl": "dodał wsparcie dla porozumień stanów, które to wspierają.\ndodano poprawne zachowanie koloru i kolor_temperature_move",
|
|
16
|
+
"uk": "додана підтримка для тягових станів, які підтримують це.\nдодано правильну обробку кольором_move та color_ infrastructure_move",
|
|
17
|
+
"zh-cn": "此外,还支持支持这一国家。.\n· 删除白色、流血和色色色色色彩。"
|
|
18
|
+
},
|
|
19
|
+
"2.2.1": {
|
|
20
|
+
"en": "fix state roles and access\nfix state handling\nfix createZ2MMessage",
|
|
21
|
+
"de": "zustandsrollen und zugriff beheben\nmanuelle zustandsbearbeitung\nfix erstellenZ2MMessage",
|
|
22
|
+
"ru": "исправить государственные роли и доступ\nисправить государственную обработку\nисправить CreateZ2MMessage",
|
|
23
|
+
"pt": "corrigir funções estaduais e acesso\ncorrigir o manuseio do estado\ncorrigir createZ2MMessage",
|
|
24
|
+
"nl": "vertaling:\nvertaling:\nvertaling:",
|
|
25
|
+
"fr": "fixer les rôles de l'état et l'accès\nmaniement de l ' état\nfix createZ2MMessage",
|
|
26
|
+
"it": "fissare i ruoli dello stato e l'accesso\ncorretta gestione dello stato\nfix createZ2MMessage",
|
|
27
|
+
"es": "fijar funciones estatales y acceso\ncorrección del estado\nfix createZ2MMessage",
|
|
28
|
+
"pl": "uchwała rola państwowa i dostęp\nnaprawa\ntworzenie Z2MM",
|
|
29
|
+
"uk": "фіксувати державні ролі і доступ\nфіксувати стан обробки\nфіксатор творуZ2MMessage",
|
|
30
|
+
"zh-cn": "fix 国家作用和准入\nfix 国家处理\nfix 建立Z2MMessage"
|
|
31
|
+
},
|
|
6
32
|
"2.2.0": {
|
|
7
33
|
"en": "added support for [Lidl HG06467 effects](https://www.zigbee2mqtt.io/devices/HG06467.html#trigger-effects)\nadded support for hs color\nsimulated_brightness data point is added only for supported devices",
|
|
8
34
|
"de": "unterstützung für [Lidl HG06467-Effekte](https://www.zigbee2mqt.io/devices/HG06467.html#trigger-Effekte)\nunterstützung für hs farbe\nsimuld_brightness-datenpunkt wird nur für unterstützte geräte hinzugefügt",
|
|
@@ -66,30 +92,6 @@
|
|
|
66
92
|
"es": "*! ¡CAMBIANDO\n\nopciones adicionales para MQTT-Server externo\nconexión a zigbe2mqtt completamente rediseñado y cambiado a MQTT\nmuchos bugfixes\nautomáticamente poner las acciones del botón de nuevo a falso\nsoporte añadido para función Zigbee2MQTT simulado_brightness\ncontrol de configuración añadido\nproducción de registro agregada sobre detalles de coordinadores",
|
|
67
93
|
"pl": "! BREAKING CHANGE! (ANG.)\n\nobsługa MQTT-Server\nzigbe2mqtt całkowicie przerobił i zmienił MQTT\nwiele błędów\nautomatycznie ustawione akcje przycisku\ndodano obsługę Zigbee2MQTT\nsprawdzać\ndokładna produkcja logów na temat szczegółów koordynacji",
|
|
68
94
|
"zh-cn": "页:1 BREAKREANGE*\n\n外贸总协定\n与zigbe2mqt完全重新工作,并改装到外贸总协定\n批发\n自动建立但顿行动回到虚假的行动\n对Zigbee2MQTT特征的增援\n增幅检查\n协调员的产出"
|
|
69
|
-
},
|
|
70
|
-
"0.2.0": {
|
|
71
|
-
"en": "group states corrected\nadded option 'Use Kelvin instead of mired for the color temps'\nremove available logic, now will use the information from z2m\nrename noLogDevices to logfilter\nlots of bugfixes\nadded noLogDevices functionality\nadded debugmessage for specific device functionality\nadded some states are default false\nadded support for scenes defined on a device\nfix available state role\nfix subscribeWritableStates",
|
|
72
|
-
"de": "gruppenzustände korrigiert\nzusatzoption 'Use Kelvin anstelle von mired für die Farbe Tempos '\ndie verfügbare logik entfernen, jetzt die informationen von z2m verwenden\numbenennen noLogDevices zum Logfilter\nviele bugfixes\nnoLogDevices Funktionalität hinzugefügt\ndebugmessage für spezifische gerätefunktionalität\neinige zustände standardmäßig falsch hinzugefügt\nunterstützung für szenen, die auf einem gerät definiert sind\nfix verfügbare zustandsrolle\nabonnierenWritableState",
|
|
73
|
-
"ru": "исправлены состояния группы\nдобавлена опция 'Используйте Kelvin вместо mired для цветовых темп « »\nудалить доступную логику, теперь будет использовать информацию из z2m\nпереименовать noLogDevices для logfilter\nмного багфиксов\nдобавлена функция noLogDevices\nдобавлено debugmessage для конкретной функциональности устройства\nдобавлены некоторые государства по умолчанию false\nдобавлена поддержка сцен, определенных на устройстве\nисправить доступную государственную роль\nисправить подпискуWritableStates",
|
|
74
|
-
"pt": "estados do grupo corrigidos\nopção adicionada 'Use Kelvin em vez de mired para os temps de cor '\nremover a lógica disponível, agora usará as informações do z2m\nrenomear noLogDevices para logfilter\nlotes de correções de bugs\nadicionado noLogDevices funcionalidade\nadicionado debugmessage para funcionalidade específica do dispositivo\nadicionado alguns estados são padrão falso\nsuporte adicionado para cenas definidas em um dispositivo\ncorrigir a função estadual disponível\ncorrigir assinantesEstados disponíveis",
|
|
75
|
-
"nl": "de groep zegt:\nvoegde optie 'Use Kelvin' in plaats van de kleuren tempen '\nverwijder de logica, nu zal de informatie van z2m gebruiken\nnoLog Devices\nveel insectenfixen\nnoLog Devices functionaliteit\nvoegde debugmesage toe voor specifieke apparaat functionaliteit\nsommige staten zijn vals\nsteun voor scènes gedefinieerd op een apparaat\nbeschikbare staatsrol\nvertaling:",
|
|
76
|
-
"fr": "états de groupe corrigés\noption ajoutée 'Utiliser Kelvin au lieu de mired pour le temps de couleur '\nsupprimer la logique disponible, maintenant utilisera les informations de z2m\nrenommer noLogDevices to logfilter\nbeaucoup de bugfixes\najout de fonctionnalité noLogDevices\najout debugmessage pour la fonctionnalité de périphérique spécifique\ncertains états ajoutés sont par défaut faux\nsupport ajouté pour les scènes définies sur un appareil\nle rôle de l ' état\nfixer souscrire",
|
|
77
|
-
"it": "gruppo stati corretti\nopzione aggiunta 'Usa Kelvin invece di mired per le tentazioni di colore '\nrimuovere la logica disponibile, ora userà le informazioni da z2m\nrinominare noLogDevices per logfilter\nmolti bugfix\naggiunto noLogDevices funzionalità\ndebugmessage aggiunto per funzionalità specifiche del dispositivo\naggiunto alcuni stati sono falsi di default\nsupporto aggiunto per scene definite su un dispositivo\ncorrezione del ruolo di stato disponibile\nfissare abbonamentiWritableStates",
|
|
78
|
-
"es": "estados del grupo corregidos\nopción agregada 'Use Kelvin en lugar de mired para el color temps '\neliminar la lógica disponible, ahora utilizará la información de z2m\nnoLogDevices to logfilter\nmuchos bugfixes\nnoLogDevices funcionalidad\ndebugmesage añadido para la funcionalidad específica del dispositivo\nañadido algunos estados son falsos\nsoporte añadido para escenas definidas en un dispositivo\nfijar la función estatal disponible\nfijar suscriptosEstados disponibles",
|
|
79
|
-
"pl": "państwa grupowe poprawiły\ndodał opcję 'Use Kelvin' zamiast śmiać kolorowe tempo. '\nzdejmowanie dostępnej logiki wykorzystuje obecnie informacje z 2 m\nnazwa NoLogDevices (ang.)\nwiele błędów\ndodano obsługę NoLogDevices\ndodanie debugmessage dla konkretnej funkcjonalności\ndodanie niektórych stanów jest fałszywe\ndodano wsparcie dla scen zdefiniowanych na urządzenie\nfunkcja stanowa\nrecovery",
|
|
80
|
-
"zh-cn": "更正\n加上“Use Kelvin”的备选办法,而不是对色彩的诱惑。 评 注\n删除现有逻辑,现在将使用兹2m的信息。\n目 录\n批发\n增加无车辆功能\n增加特定装置功能的碎片\n另有一些国家的违约情况\n对一个装置所界定的场地的更多支持\nf 现有国家作用\nfix 有线性的国家"
|
|
81
|
-
},
|
|
82
|
-
"0.1.0": {
|
|
83
|
-
"en": "first release",
|
|
84
|
-
"de": "erste veröffentlichung",
|
|
85
|
-
"ru": "первый релиз",
|
|
86
|
-
"pt": "primeiro lançamento",
|
|
87
|
-
"nl": "eerste vrijlating",
|
|
88
|
-
"fr": "première version",
|
|
89
|
-
"it": "primo rilascio",
|
|
90
|
-
"es": "primera liberación",
|
|
91
|
-
"pl": "pierwsze wydanie",
|
|
92
|
-
"zh-cn": "首次释放"
|
|
93
95
|
}
|
|
94
96
|
},
|
|
95
97
|
"titleLang": {
|
package/lib/deviceController.js
CHANGED
|
@@ -3,14 +3,16 @@ const defineDeviceFromExposes = require('./exposes').defineDeviceFromExposes;
|
|
|
3
3
|
const utils = require('./utils');
|
|
4
4
|
const colors = require('./colors.js');
|
|
5
5
|
const rgb = require('./rgb.js');
|
|
6
|
-
const createCache = {};
|
|
6
|
+
//const createCache = {};
|
|
7
7
|
|
|
8
8
|
class DeviceController {
|
|
9
|
-
constructor(adapter, deviceCache, groupCache, config) {
|
|
9
|
+
constructor(adapter, deviceCache, groupCache, config, logCustomizations, createCache) {
|
|
10
10
|
this.adapter = adapter;
|
|
11
11
|
this.groupCache = groupCache;
|
|
12
12
|
this.deviceCache = deviceCache;
|
|
13
13
|
this.config = config;
|
|
14
|
+
this.logCustomizations = logCustomizations;
|
|
15
|
+
this.createCache = createCache;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
async createDeviceDefinitions(exposes) {
|
|
@@ -24,6 +26,9 @@ class DeviceController {
|
|
|
24
26
|
scenes = scenes.concat(expose.endpoints[key].scenes);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
29
|
+
if (this.logCustomizations.debugDevices.includes(expose.ieee_address)) {
|
|
30
|
+
this.adapter.log.warn(`--->>> fromZ2M -> ${expose.ieee_address} exposes: ${JSON.stringify(expose)}`);
|
|
31
|
+
}
|
|
27
32
|
// if the device is already present in the cache, remove it
|
|
28
33
|
this.removeDeviceByIeee(this.deviceCache, expose.ieee_address);
|
|
29
34
|
defineDeviceFromExposes(this.deviceCache, expose.friendly_name, expose.ieee_address, expose.definition, expose.power_source, scenes, this.config);
|
|
@@ -142,7 +147,7 @@ class DeviceController {
|
|
|
142
147
|
async createOrUpdateDevices() {
|
|
143
148
|
for (const device of this.groupCache.concat(this.deviceCache)) {
|
|
144
149
|
const deviceName = device.id == device.ieee_address ? '' : device.id;
|
|
145
|
-
if (!createCache[device.ieee_address] || createCache[device.ieee_address].
|
|
150
|
+
if (!this.createCache[device.ieee_address] || this.createCache[device.ieee_address].name != deviceName) {
|
|
146
151
|
const deviceObj = {
|
|
147
152
|
type: 'device',
|
|
148
153
|
common: {
|
|
@@ -160,7 +165,7 @@ class DeviceController {
|
|
|
160
165
|
|
|
161
166
|
//@ts-ignore
|
|
162
167
|
await this.adapter.extendObjectAsync(device.ieee_address, deviceObj);
|
|
163
|
-
createCache[device.ieee_address] =
|
|
168
|
+
this.createCache[device.ieee_address] = { name: deviceName };
|
|
164
169
|
}
|
|
165
170
|
|
|
166
171
|
// Here it is checked whether the scenes match the current data from z2m.
|
|
@@ -175,14 +180,15 @@ class DeviceController {
|
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
for (const state of device.states) {
|
|
178
|
-
if (!createCache[device.ieee_address][state.id] || createCache[device.ieee_address][state.id].name != state.name) {
|
|
179
|
-
const iobState =
|
|
180
|
-
await this.adapter.extendObjectAsync(`${device.ieee_address}.${state.id}`, {
|
|
183
|
+
if (!this.createCache[device.ieee_address][state.id] || this.createCache[device.ieee_address][state.id].name != state.name) {
|
|
184
|
+
const iobState = {
|
|
181
185
|
type: 'state',
|
|
182
|
-
common:
|
|
186
|
+
common: await this.copyAndCleanStateObj(state),
|
|
183
187
|
native: {},
|
|
184
|
-
}
|
|
185
|
-
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
await this.adapter.extendObjectAsync(`${device.ieee_address}.${state.id}`, iobState);
|
|
191
|
+
this.createCache[device.ieee_address][state.id] = { name: state.name, created: true };
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
}
|
|
@@ -212,6 +218,7 @@ class DeviceController {
|
|
|
212
218
|
if (ieee_address != undefined) {
|
|
213
219
|
this.adapter.setStateAsync(`${ieee_address}.available`, false, true);
|
|
214
220
|
this.adapter.extendObject(`${ieee_address}`, { common: { name: 'Device removed!', } });
|
|
221
|
+
delete this.createCache[ieee_address];
|
|
215
222
|
}
|
|
216
223
|
}
|
|
217
224
|
|
package/lib/exposes.js
CHANGED
|
@@ -8,10 +8,38 @@ const utils = require('./utils');
|
|
|
8
8
|
const colors = require('./colors');
|
|
9
9
|
const getNonGenDevStatesDefs = require('./nonGenericDevicesExtension').getStateDefinition;
|
|
10
10
|
|
|
11
|
+
// https://www.zigbee2mqtt.io/guide/usage/exposes.html#access
|
|
12
|
+
const z2mAccess = {
|
|
13
|
+
/**
|
|
14
|
+
* Bit 0: The property can be found in the published state of this device
|
|
15
|
+
*/
|
|
16
|
+
STATE: 1,
|
|
17
|
+
/**
|
|
18
|
+
* Bit 1: The property can be set with a /set command
|
|
19
|
+
*/
|
|
20
|
+
SET: 2,
|
|
21
|
+
/**
|
|
22
|
+
* Bit 2: The property can be retrieved with a /get command
|
|
23
|
+
*/
|
|
24
|
+
GET: 4,
|
|
25
|
+
/**
|
|
26
|
+
* Bitwise inclusive OR of STATE and SET : 0b001 | 0b010
|
|
27
|
+
*/
|
|
28
|
+
STATE_SET: 3,
|
|
29
|
+
/**
|
|
30
|
+
* Bitwise inclusive OR of STATE and GET : 0b001 | 0b100
|
|
31
|
+
*/
|
|
32
|
+
STATE_GET: 5,
|
|
33
|
+
/**
|
|
34
|
+
* Bitwise inclusive OR of STATE and GET and SET : 0b001 | 0b100 | 0b010
|
|
35
|
+
*/
|
|
36
|
+
ALL: 7,
|
|
37
|
+
};
|
|
38
|
+
|
|
11
39
|
function genState(expose, role, name, desc) {
|
|
12
40
|
let state;
|
|
13
|
-
const readable =
|
|
14
|
-
const writable = expose.access >
|
|
41
|
+
const readable = (expose.access & z2mAccess.STATE) > 0;
|
|
42
|
+
const writable = (expose.access & z2mAccess.SET) > 0;
|
|
15
43
|
const stname = (name || expose.property);
|
|
16
44
|
|
|
17
45
|
if (typeof stname !== 'string') {
|
|
@@ -121,22 +149,13 @@ function genState(expose, role, name, desc) {
|
|
|
121
149
|
|
|
122
150
|
function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, config) {
|
|
123
151
|
const states = [];
|
|
124
|
-
// make the different (set and get) part of state is updatable if different exposes is used for get and set
|
|
125
|
-
// as example:
|
|
126
|
-
// ...
|
|
127
|
-
// exposes.binary('some_option', ea.STATE, true, false).withDescription('Some Option'),
|
|
128
|
-
// exposes.composite('options', 'options')
|
|
129
|
-
// .withDescription('Some composite Options')
|
|
130
|
-
// .withFeature(exposes.binary('some_option', ea.SET, true, false).withDescription('Some Option'))
|
|
131
|
-
//in this case one state - `some_option` has two different exposes for set an get, we have to combine it ...
|
|
132
|
-
|
|
133
152
|
function pushToStates(state, access) {
|
|
134
153
|
if (state === undefined) {
|
|
135
154
|
return 0;
|
|
136
155
|
}
|
|
137
|
-
|
|
138
|
-
state.readable =
|
|
139
|
-
state.writable = access >
|
|
156
|
+
if (access === undefined) access = z2mAccess.ALL;
|
|
157
|
+
state.readable = (access & z2mAccess.STATE) > 0;
|
|
158
|
+
state.writable = (access & z2mAccess.SET) > 0;
|
|
140
159
|
const stateExists = states.findIndex((x, _index, _array) => (x.id === state.id));
|
|
141
160
|
|
|
142
161
|
if (stateExists < 0) {
|
|
@@ -264,6 +283,21 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
264
283
|
epname: expose.endpoint,
|
|
265
284
|
setattr: 'state',
|
|
266
285
|
}, prop.access);
|
|
286
|
+
// features contains TOGGLE?
|
|
287
|
+
if (prop.value_toggle) {
|
|
288
|
+
pushToStates({
|
|
289
|
+
id: `${prop.property}_toggle`,
|
|
290
|
+
prop: `${prop.property}_toggle`,
|
|
291
|
+
name: `Toggle state of the ${prop.property}`,
|
|
292
|
+
icon: undefined,
|
|
293
|
+
role: 'button',
|
|
294
|
+
write: true,
|
|
295
|
+
read: true,
|
|
296
|
+
type: 'boolean',
|
|
297
|
+
setattr: prop.property,
|
|
298
|
+
setter: (value) => (value) ? prop.value_toggle : undefined
|
|
299
|
+
});
|
|
300
|
+
}
|
|
267
301
|
break;
|
|
268
302
|
}
|
|
269
303
|
case 'brightness': {
|
|
@@ -379,7 +413,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
379
413
|
},
|
|
380
414
|
epname: expose.endpoint,
|
|
381
415
|
setattr: 'color',
|
|
382
|
-
},
|
|
416
|
+
}, prop.access);
|
|
383
417
|
break;
|
|
384
418
|
}
|
|
385
419
|
case 'color_hs': {
|
|
@@ -415,7 +449,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
415
449
|
},
|
|
416
450
|
epname: expose.endpoint,
|
|
417
451
|
setattr: 'color',
|
|
418
|
-
},
|
|
452
|
+
}, prop.access);
|
|
419
453
|
// pushToStates({
|
|
420
454
|
// id: expose.endpoint ? `hue_${expose.endpoint}` : 'hue',
|
|
421
455
|
// prop: expose.endpoint ? `color_${expose.endpoint}` : 'color',
|
|
@@ -539,7 +573,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
539
573
|
break;
|
|
540
574
|
}
|
|
541
575
|
default:
|
|
542
|
-
pushToStates(genState(prop),
|
|
576
|
+
pushToStates(genState(prop), prop.access);
|
|
543
577
|
break;
|
|
544
578
|
}
|
|
545
579
|
}
|
|
@@ -552,6 +586,21 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
552
586
|
switch (prop.name) {
|
|
553
587
|
case 'state':
|
|
554
588
|
pushToStates(genState(prop, 'switch'), prop.access);
|
|
589
|
+
// features contains TOGGLE?
|
|
590
|
+
if (prop.value_toggle) {
|
|
591
|
+
pushToStates({
|
|
592
|
+
id: `${prop.property}_toggle`,
|
|
593
|
+
prop: `${prop.property}_toggle`,
|
|
594
|
+
name: `Toggle state of the ${prop.property}`,
|
|
595
|
+
icon: undefined,
|
|
596
|
+
role: 'button',
|
|
597
|
+
write: true,
|
|
598
|
+
read: true,
|
|
599
|
+
type: 'boolean',
|
|
600
|
+
setattr: prop.property,
|
|
601
|
+
setter: (value) => (value) ? prop.value_toggle : undefined
|
|
602
|
+
});
|
|
603
|
+
}
|
|
555
604
|
break;
|
|
556
605
|
default:
|
|
557
606
|
pushToStates(genState(prop), prop.access);
|
|
@@ -631,21 +680,22 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
631
680
|
switch (expose.name) {
|
|
632
681
|
case 'action': {
|
|
633
682
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
// Action (bekommt text ausser hold und release, auto reset nach 250 ms)
|
|
638
|
-
// Hold: wird gesetzt bei hold, gelöscht bei passendem Release
|
|
683
|
+
if (!Array.isArray(expose.values)) {
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
639
686
|
|
|
640
|
-
if (!Array.isArray(expose.values)) break;
|
|
641
687
|
const hasHold = expose.values.find((actionName) => actionName.includes('hold'));
|
|
642
688
|
const hasRelease = expose.values.find((actionName) => actionName.includes('release'));
|
|
689
|
+
|
|
643
690
|
for (const actionName of expose.values) {
|
|
644
691
|
// is release state ? - skip
|
|
645
|
-
if (hasHold && hasRelease && actionName.includes('release'))
|
|
692
|
+
if (hasHold && hasRelease && actionName.includes('release')) {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
|
|
646
696
|
// is hold state ?
|
|
647
697
|
if (hasHold && hasRelease && actionName.includes('hold')) {
|
|
648
|
-
|
|
698
|
+
pushToStates({
|
|
649
699
|
id: actionName.replace(/\*/g, ''),
|
|
650
700
|
prop: 'action',
|
|
651
701
|
name: actionName,
|
|
@@ -667,9 +717,67 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
667
717
|
}
|
|
668
718
|
return undefined;
|
|
669
719
|
},
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
|
|
720
|
+
}, expose.access);
|
|
721
|
+
}
|
|
722
|
+
else if (actionName.includes('color_temperature_move')) {
|
|
723
|
+
pushToStates({
|
|
724
|
+
id: 'color_temperature_move',
|
|
725
|
+
prop: 'action',
|
|
726
|
+
name: 'Color temperature move value',
|
|
727
|
+
icon: undefined,
|
|
728
|
+
role: 'level.color.temperature',
|
|
729
|
+
write: false,
|
|
730
|
+
read: true,
|
|
731
|
+
type: 'number',
|
|
732
|
+
def: config.useKelvin == true ? utils.miredKelvinConversion(150) : 500,
|
|
733
|
+
min: config.useKelvin == true ? utils.miredKelvinConversion(500) : 150,
|
|
734
|
+
max: config.useKelvin == true ? utils.miredKelvinConversion(150) : 500,
|
|
735
|
+
unit: config.useKelvin == true ? 'K' : 'mired',
|
|
736
|
+
getter: (payload) => {
|
|
737
|
+
if (payload.action != 'color_temperature_move') {
|
|
738
|
+
return undefined;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (payload.action_color_temperature) {
|
|
742
|
+
if (config.useKelvin == true) {
|
|
743
|
+
return utils.miredKelvinConversion(payload.action_color_temperature);
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
return payload.action_color_temperature;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
}, expose.access);
|
|
751
|
+
|
|
752
|
+
}
|
|
753
|
+
else if (actionName.includes('color_move')) {
|
|
754
|
+
pushToStates({
|
|
755
|
+
id: 'color_move',
|
|
756
|
+
prop: 'action',
|
|
757
|
+
name: 'Color move value',
|
|
758
|
+
icon: undefined,
|
|
759
|
+
role: 'level.color.rgb',
|
|
760
|
+
write: false,
|
|
761
|
+
read: true,
|
|
762
|
+
type: 'string',
|
|
763
|
+
def: '#ffffff',
|
|
764
|
+
getter: (payload) => {
|
|
765
|
+
if (payload.action != 'color_move') {
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (payload.action_color && payload.action_color.hasOwnProperty('x') && payload.action_color.hasOwnProperty('y')) {
|
|
770
|
+
const colorval = rgb.cie_to_rgb(payload.action_color.x, payload.action_color.y);
|
|
771
|
+
return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}, expose.access);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
pushToStates({
|
|
673
781
|
id: actionName.replace(/\*/g, ''),
|
|
674
782
|
prop: 'action',
|
|
675
783
|
name: actionName,
|
|
@@ -681,27 +789,12 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
681
789
|
def: false,
|
|
682
790
|
isEvent: true,
|
|
683
791
|
getter: payload => (payload.action === actionName) ? true : undefined,
|
|
684
|
-
};
|
|
792
|
+
}, expose.access);
|
|
685
793
|
}
|
|
686
|
-
pushToStates(state, expose.access);
|
|
687
794
|
}
|
|
688
795
|
// Can the device simulated_brightness?
|
|
689
796
|
if (definitions.options && definitions.options.find(x => x.property == 'simulated_brightness')) {
|
|
690
|
-
pushToStates(
|
|
691
|
-
id: 'simulated_brightness',
|
|
692
|
-
prop: 'brightness',
|
|
693
|
-
name: 'Simulated brightness',
|
|
694
|
-
icon: undefined,
|
|
695
|
-
role: 'level.dimmer',
|
|
696
|
-
write: true,
|
|
697
|
-
read: true,
|
|
698
|
-
type: 'number',
|
|
699
|
-
unit: '%',
|
|
700
|
-
def: 0,
|
|
701
|
-
getter: payload => {
|
|
702
|
-
return utils.bulbLevelToAdapterLevel(payload.brightness);
|
|
703
|
-
},
|
|
704
|
-
}, 1);
|
|
797
|
+
pushToStates(statesDefs.simulated_brightness, z2mAccess.STATE);
|
|
705
798
|
}
|
|
706
799
|
state = null;
|
|
707
800
|
break;
|
|
@@ -720,7 +813,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
720
813
|
switch (expose.name) {
|
|
721
814
|
case 'contact':
|
|
722
815
|
state = statesDefs.contact;
|
|
723
|
-
pushToStates(statesDefs.opened,
|
|
816
|
+
pushToStates(statesDefs.opened, expose.access);
|
|
724
817
|
break;
|
|
725
818
|
|
|
726
819
|
case 'battery_low':
|
|
@@ -763,6 +856,21 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
763
856
|
switch (prop.name) {
|
|
764
857
|
case 'state':
|
|
765
858
|
pushToStates(genState(prop, 'switch'), prop.access);
|
|
859
|
+
// features contains TOGGLE?
|
|
860
|
+
if (prop.value_toggle) {
|
|
861
|
+
pushToStates({
|
|
862
|
+
id: `${prop.property}_toggle`,
|
|
863
|
+
prop: `${prop.property}_toggle`,
|
|
864
|
+
name: `Toggle state of the ${prop.property}`,
|
|
865
|
+
icon: undefined,
|
|
866
|
+
role: 'button',
|
|
867
|
+
write: true,
|
|
868
|
+
read: true,
|
|
869
|
+
type: 'boolean',
|
|
870
|
+
setattr: prop.property,
|
|
871
|
+
setter: (value) => (value) ? prop.value_toggle : undefined
|
|
872
|
+
});
|
|
873
|
+
}
|
|
766
874
|
break;
|
|
767
875
|
default:
|
|
768
876
|
pushToStates(genState(prop), prop.access);
|
|
@@ -783,6 +891,12 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
783
891
|
case 'running_mode':
|
|
784
892
|
pushToStates(statesDefs.climate_running_mode, prop.access);
|
|
785
893
|
break;
|
|
894
|
+
case 'local_temperature':
|
|
895
|
+
pushToStates(statesDefs.hvacThermostat_local_temp, prop.access);
|
|
896
|
+
break;
|
|
897
|
+
case 'local_temperature_calibration':
|
|
898
|
+
pushToStates(statesDefs.hvacThermostat_local_temp_calibration, prop.access);
|
|
899
|
+
break;
|
|
786
900
|
default:
|
|
787
901
|
{
|
|
788
902
|
if (prop.name.includes('heating_setpoint')) {
|
|
@@ -809,7 +923,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
809
923
|
return result;
|
|
810
924
|
};
|
|
811
925
|
// if we have a composite expose, the value have to be an object {expose.property : {prop.property: value}}
|
|
812
|
-
if (prop.access &
|
|
926
|
+
if (prop.access & z2mAccess.SET) {
|
|
813
927
|
st.setter = (value, options) => {
|
|
814
928
|
const result = {};
|
|
815
929
|
options[prop.property] = value;
|
|
@@ -819,7 +933,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
819
933
|
st.setattr = expose.property;
|
|
820
934
|
}
|
|
821
935
|
// if we have a composite expose, the payload will be an object {expose.property : {prop.property: value}}
|
|
822
|
-
if (prop.access &
|
|
936
|
+
if (prop.access & z2mAccess.STATE) {
|
|
823
937
|
st.getter = payload => {
|
|
824
938
|
if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
|
|
825
939
|
return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined;
|
|
@@ -841,22 +955,15 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
841
955
|
// If necessary, add states defined for this device model.
|
|
842
956
|
// Unfortunately this is necessary for some device models because they do not adhere to the standard
|
|
843
957
|
for (const state of getNonGenDevStatesDefs(definitions.model)) {
|
|
844
|
-
pushToStates(state, state.write ?
|
|
958
|
+
pushToStates(state, state.write ? z2mAccess.SET : z2mAccess.STATE);
|
|
845
959
|
}
|
|
846
960
|
|
|
847
961
|
// Add default states
|
|
848
|
-
pushToStates(statesDefs.available,
|
|
849
|
-
|
|
850
|
-
const newDevice = {
|
|
851
|
-
id: deviceID,
|
|
852
|
-
ieee_address: ieee_address,
|
|
853
|
-
power_source: power_source,
|
|
854
|
-
states: states,
|
|
855
|
-
};
|
|
962
|
+
pushToStates(statesDefs.available, z2mAccess.STATE);
|
|
856
963
|
|
|
857
964
|
// Create buttons for scenes
|
|
858
965
|
for (const scene of scenes) {
|
|
859
|
-
|
|
966
|
+
pushToStates({
|
|
860
967
|
id: `scene_${scene.id}`,
|
|
861
968
|
prop: `scene_recall`,
|
|
862
969
|
name: scene.name,
|
|
@@ -866,11 +973,16 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
|
|
|
866
973
|
read: true,
|
|
867
974
|
type: 'boolean',
|
|
868
975
|
setter: (value) => (value) ? scene.id : undefined
|
|
869
|
-
};
|
|
870
|
-
// @ts-ignore
|
|
871
|
-
newDevice.states.push(sceneSate);
|
|
976
|
+
});
|
|
872
977
|
}
|
|
873
978
|
|
|
979
|
+
const newDevice = {
|
|
980
|
+
id: deviceID,
|
|
981
|
+
ieee_address: ieee_address,
|
|
982
|
+
power_source: power_source,
|
|
983
|
+
states: states,
|
|
984
|
+
};
|
|
985
|
+
|
|
874
986
|
return newDevice;
|
|
875
987
|
}
|
|
876
988
|
|
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,108 @@ 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
|
+
getter: payload => (payload.state === 'ON'),
|
|
140
|
+
setter: (value) => (value) ? 'ON' : 'OFF',
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
brightness: {
|
|
144
|
+
id: 'brightness',
|
|
145
|
+
name: 'Brightness',
|
|
146
|
+
icon: undefined,
|
|
147
|
+
role: 'level.dimmer',
|
|
148
|
+
write: true,
|
|
149
|
+
read: true,
|
|
150
|
+
type: 'number',
|
|
151
|
+
unit: '%',
|
|
152
|
+
min: 0,
|
|
153
|
+
max: 100,
|
|
154
|
+
getter: payload => {
|
|
155
|
+
return utils.bulbLevelToAdapterLevel(payload.brightness);
|
|
156
|
+
},
|
|
157
|
+
setter: (value) => {
|
|
158
|
+
return utils.adapterLevelToBulbLevel(value);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
brightness_move: {
|
|
163
|
+
id: 'brightness_move',
|
|
164
|
+
prop: 'brightness_move',
|
|
165
|
+
name: 'Dimming',
|
|
166
|
+
icon: undefined,
|
|
167
|
+
role: 'state',
|
|
168
|
+
write: true,
|
|
169
|
+
read: false,
|
|
170
|
+
type: 'number',
|
|
171
|
+
min: -50,
|
|
172
|
+
max: 50,
|
|
173
|
+
def: 0
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
colortemp_move: {
|
|
177
|
+
id: 'colortemp_move',
|
|
178
|
+
prop: 'color_temp_move',
|
|
179
|
+
name: 'Colortemp change',
|
|
180
|
+
icon: undefined,
|
|
181
|
+
role: 'state',
|
|
182
|
+
write: true,
|
|
183
|
+
read: false,
|
|
184
|
+
type: 'number',
|
|
185
|
+
min: -50,
|
|
186
|
+
max: 50,
|
|
187
|
+
def: 0
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
//#################################################################
|
|
89
191
|
device_query: { // button to trigger device read
|
|
90
192
|
id: 'device_query',
|
|
91
193
|
prop: 'device_query',
|
|
@@ -462,22 +564,7 @@ const states = {
|
|
|
462
564
|
isEvent: true,
|
|
463
565
|
getter: payload => (payload.click === 'both_double') ? true : undefined,
|
|
464
566
|
},
|
|
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
|
-
},
|
|
567
|
+
|
|
481
568
|
stateEp: {
|
|
482
569
|
id: 'state',
|
|
483
570
|
name: 'Switch state',
|
|
@@ -1182,37 +1269,7 @@ const states = {
|
|
|
1182
1269
|
return utils.bulbLevelToAdapterLevel(payload.brightness);
|
|
1183
1270
|
},
|
|
1184
1271
|
},
|
|
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
|
-
},
|
|
1272
|
+
|
|
1216
1273
|
colortemp: {
|
|
1217
1274
|
id: 'colortemp',
|
|
1218
1275
|
prop: 'color_temp',
|
|
@@ -2153,7 +2210,7 @@ const states = {
|
|
|
2153
2210
|
|
|
2154
2211
|
// hvac Thermostat cluster - generic states
|
|
2155
2212
|
hvacThermostat_local_temp: {
|
|
2156
|
-
id: '
|
|
2213
|
+
id: 'local_temperature',
|
|
2157
2214
|
prop: 'local_temperature',
|
|
2158
2215
|
name: 'Local Temperature',
|
|
2159
2216
|
icon: undefined,
|
|
@@ -2164,7 +2221,7 @@ const states = {
|
|
|
2164
2221
|
unit: '°C',
|
|
2165
2222
|
},
|
|
2166
2223
|
hvacThermostat_local_temp_calibration: {
|
|
2167
|
-
id: '
|
|
2224
|
+
id: 'local_temperature_calibration',
|
|
2168
2225
|
prop: 'local_temperature_calibration',
|
|
2169
2226
|
name: 'Temperature Calibration',
|
|
2170
2227
|
icon: undefined,
|
|
@@ -2173,6 +2230,7 @@ const states = {
|
|
|
2173
2230
|
read: true,
|
|
2174
2231
|
type: 'number',
|
|
2175
2232
|
unit: '°C',
|
|
2233
|
+
def: 0
|
|
2176
2234
|
},
|
|
2177
2235
|
hvacThermostat_remote_sensing: {
|
|
2178
2236
|
id: 'remote_sensing',
|
|
@@ -5292,32 +5350,6 @@ const states = {
|
|
|
5292
5350
|
min: -50,
|
|
5293
5351
|
max: 50
|
|
5294
5352
|
},
|
|
5295
|
-
brightness_move: {
|
|
5296
|
-
id: 'brightness_move',
|
|
5297
|
-
prop: 'brightness_move',
|
|
5298
|
-
name: 'Dimming',
|
|
5299
|
-
icon: undefined,
|
|
5300
|
-
role: 'state',
|
|
5301
|
-
write: true,
|
|
5302
|
-
read: false,
|
|
5303
|
-
type: 'number',
|
|
5304
|
-
min: -50,
|
|
5305
|
-
max: 50,
|
|
5306
|
-
def: 0
|
|
5307
|
-
},
|
|
5308
|
-
colortemp_move: {
|
|
5309
|
-
id: 'colortemp_move',
|
|
5310
|
-
prop: 'color_temp_move',
|
|
5311
|
-
name: 'Colortemp change',
|
|
5312
|
-
icon: undefined,
|
|
5313
|
-
role: 'state',
|
|
5314
|
-
write: true,
|
|
5315
|
-
read: false,
|
|
5316
|
-
type: 'number',
|
|
5317
|
-
min: -50,
|
|
5318
|
-
max: 50,
|
|
5319
|
-
def: 0
|
|
5320
|
-
},
|
|
5321
5353
|
hue_move: {
|
|
5322
5354
|
id: 'hue_move',
|
|
5323
5355
|
prop: 'hue_move',
|
package/lib/statesController.js
CHANGED
|
@@ -3,11 +3,12 @@ const incStatsQueue = [];
|
|
|
3
3
|
const timeOutCache = {};
|
|
4
4
|
|
|
5
5
|
class StatesController {
|
|
6
|
-
constructor(adapter, deviceCache, groupCache, logCustomizations) {
|
|
6
|
+
constructor(adapter, deviceCache, groupCache, logCustomizations, createCache) {
|
|
7
7
|
this.adapter = adapter;
|
|
8
8
|
this.groupCache = groupCache;
|
|
9
9
|
this.deviceCache = deviceCache;
|
|
10
10
|
this.logCustomizations = logCustomizations;
|
|
11
|
+
this.createCache = createCache;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
processDeviceMessage(messageObj) {
|
|
@@ -49,6 +50,13 @@ class StatesController {
|
|
|
49
50
|
|
|
50
51
|
const stateName = `${device.ieee_address}.${state.id}`;
|
|
51
52
|
|
|
53
|
+
// It may be that the state has not yet been created!
|
|
54
|
+
if (!this.createCache[device.ieee_address] || !this.createCache[device.ieee_address][state.id] || !this.createCache[device.ieee_address][state.id].created) {
|
|
55
|
+
incStatsQueue[incStatsQueue.length] = messageObj;
|
|
56
|
+
//this.adapter.log.debug(`State ${stateName} is not yet created, queue state in incStatsQueue!`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
try {
|
|
53
61
|
if (state.isEvent) {
|
|
54
62
|
if (state.getter) {
|
package/lib/z2mController.js
CHANGED
|
@@ -36,16 +36,16 @@ class Z2mController {
|
|
|
36
36
|
stateID = deviceState.prop;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
topic = `${device.id}/set`;
|
|
39
|
+
if (deviceState.setattr) {
|
|
40
|
+
stateID = deviceState.setattr;
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
|
|
44
44
|
const controlObj = {
|
|
45
45
|
payload: {
|
|
46
46
|
[stateID]: stateVal
|
|
47
47
|
},
|
|
48
|
-
topic:
|
|
48
|
+
topic: `${device.id}/set`
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
// set stats with the mentioned role or ids always immediately to ack = true, because these are not reported back by Zigbee2MQTT
|
package/main.js
CHANGED
|
@@ -23,6 +23,7 @@ let mqttClient;
|
|
|
23
23
|
let deviceCache = [];
|
|
24
24
|
// eslint-disable-next-line prefer-const
|
|
25
25
|
let groupCache = [];
|
|
26
|
+
const createCache = {};
|
|
26
27
|
const logCustomizations = { debugDevices: '', logfilter: [] };
|
|
27
28
|
let showInfo = true;
|
|
28
29
|
let statesController;
|
|
@@ -44,8 +45,8 @@ class Zigbee2mqtt extends core.Adapter {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
async onReady() {
|
|
47
|
-
statesController = new StatesController(this, deviceCache, groupCache, logCustomizations);
|
|
48
|
-
deviceController = new DeviceController(this, deviceCache, groupCache, this.config);
|
|
48
|
+
statesController = new StatesController(this, deviceCache, groupCache, logCustomizations, createCache);
|
|
49
|
+
deviceController = new DeviceController(this, deviceCache, groupCache, this.config, logCustomizations, createCache);
|
|
49
50
|
z2mController = new Z2mController(this, deviceCache, groupCache, logCustomizations);
|
|
50
51
|
|
|
51
52
|
// Initialize your adapter here
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee2mqtt",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Zigbee2MQTT adapter for ioBroker",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Dennis Rathjen",
|
|
@@ -24,25 +24,25 @@
|
|
|
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.7",
|
|
40
40
|
"@types/proxyquire": "^1.3.28",
|
|
41
41
|
"@types/sinon": "^10.0.13",
|
|
42
42
|
"@types/sinon-chai": "^3.2.8",
|
|
43
43
|
"chai": "^4.3.6",
|
|
44
44
|
"chai-as-promised": "^7.1.1",
|
|
45
|
-
"eslint": "^8.
|
|
45
|
+
"eslint": "^8.26.0",
|
|
46
46
|
"eslint-config-prettier": "^8.5.0",
|
|
47
47
|
"eslint-plugin-prettier": "^4.2.1",
|
|
48
48
|
"mocha": "^10.1.0",
|