iobroker.zigbee2mqtt 1.0.0 → 2.1.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.
@@ -1,14 +1,16 @@
1
1
  const states = require('./states').states;
2
2
  const defineDeviceFromExposes = require('./exposes').defineDeviceFromExposes;
3
3
  const utils = require('./utils');
4
+ const colors = require('./colors.js');
5
+ const rgb = require('./rgb.js');
4
6
  const createCache = {};
5
7
 
6
8
  class DeviceController {
7
- constructor(adapter, deviceCache, groupCache, useKelvin) {
9
+ constructor(adapter, deviceCache, groupCache, config) {
8
10
  this.adapter = adapter;
9
11
  this.groupCache = groupCache;
10
12
  this.deviceCache = deviceCache;
11
- this.useKelvin = useKelvin;
13
+ this.config = config;
12
14
  }
13
15
 
14
16
  async createDeviceDefinitions(exposes) {
@@ -22,13 +24,15 @@ class DeviceController {
22
24
  scenes = scenes.concat(expose.endpoints[key].scenes);
23
25
  }
24
26
  }
25
- await defineDeviceFromExposes(this.deviceCache, expose.friendly_name, expose.ieee_address, expose.definition, expose.power_source, scenes, this.useKelvin);
27
+ // if the device is already present in the cache, remove it
28
+ this.removeDeviceByIeee(this.deviceCache, expose.ieee_address);
29
+ defineDeviceFromExposes(this.deviceCache, expose.friendly_name, expose.ieee_address, expose.definition, expose.power_source, scenes, this.config);
26
30
  }
27
31
  }
28
32
  }
29
33
 
30
34
 
31
- async defineGroupDevice(devices, groupID, ieee_address, scenes, useKelvin) {
35
+ async defineGroupDevice(groupID, ieee_address, scenes) {
32
36
  const newDevice = {
33
37
  id: groupID,
34
38
  ieee_address: ieee_address,
@@ -36,12 +40,46 @@ class DeviceController {
36
40
  states: [
37
41
  states.state,
38
42
  states.brightness,
39
- states.color,
43
+ //states.color,
40
44
  states.brightness_move,
41
45
  states.colortemp_move,
42
46
  ],
43
47
  };
44
48
 
49
+ const color = {
50
+ id: 'color',
51
+ prop: 'color',
52
+ name: 'Color',
53
+ icon: undefined,
54
+ role: 'level.color.rgb',
55
+ write: true,
56
+ read: true,
57
+ type: 'string',
58
+ setter: (value) => {
59
+ let xy = [0, 0];
60
+ const rgbcolor = colors.ParseColor(value);
61
+ xy = rgb.rgb_to_cie(rgbcolor.r, rgbcolor.g, rgbcolor.b);
62
+ return {
63
+ x: xy[0],
64
+ y: xy[1]
65
+ };
66
+ },
67
+ getter: payload => {
68
+ if (payload.color_mode != 'xy' && this.config.colorTempSyncColor == false) {
69
+ return undefined;
70
+ }
71
+ if (payload.color && payload.color.x && payload.color.y) {
72
+ const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
73
+ return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
74
+ } else {
75
+ return undefined;
76
+ }
77
+ },
78
+ };
79
+
80
+ // @ts-ignore
81
+ newDevice.states.push(color);
82
+
45
83
  const colortemp = {
46
84
  id: 'colortemp',
47
85
  prop: 'color_temp',
@@ -51,15 +89,19 @@ class DeviceController {
51
89
  write: true,
52
90
  read: true,
53
91
  type: 'number',
54
- unit: useKelvin == true ? 'K' : 'mired',
92
+ min: this.config.useKelvin == true ? utils.miredKelvinConversion(500) : 150,
93
+ max: this.config.useKelvin == true ? utils.miredKelvinConversion(150) : 500,
94
+ unit: this.config.useKelvin == true ? 'K' : 'mired',
55
95
  setter: (value) => {
56
96
  return utils.toMired(value);
57
97
  },
58
98
  getter: (payload) => {
59
- if (useKelvin == true) {
60
- return utils.miredKelvinConversion(payload.color_temp);
99
+ if (payload.color_mode != 'color_temp') {
100
+ return undefined;
61
101
  }
62
- else {
102
+ if (this.config.useKelvin == true) {
103
+ return utils.miredKelvinConversion(payload.color_temp);
104
+ } else {
63
105
  return payload.color_temp;
64
106
  }
65
107
  },
@@ -86,13 +128,14 @@ class DeviceController {
86
128
  }
87
129
 
88
130
  // if the device is already present in the cache, remove it
89
- utils.removeDeviceByIeee(devices, ieee_address);
90
- devices.push(newDevice);
131
+ this.removeDeviceByIeee(this.groupCache, ieee_address);
132
+ this.groupCache.push(newDevice);
91
133
  }
134
+
92
135
  async createGroupDefinitions(exposes) {
93
136
  utils.clearArray(this.groupCache);
94
137
  for (const expose of exposes) {
95
- await this.defineGroupDevice(this.groupCache, expose.friendly_name, `group_${expose.id}`, expose.scenes, this.useKelvin);
138
+ await this.defineGroupDevice(expose.friendly_name, `group_${expose.id}`, expose.scenes);
96
139
  }
97
140
  }
98
141
 
@@ -147,7 +190,9 @@ class DeviceController {
147
190
 
148
191
  async renameDeviceInCache(messageObj) {
149
192
  const renamedDevice = this.groupCache.concat(this.deviceCache).find(x => x.id == messageObj.payload.data.from);
150
- renamedDevice.id = messageObj.payload.data.to;
193
+ if (renamedDevice) {
194
+ renamedDevice.id = messageObj.payload.data.to;
195
+ }
151
196
  }
152
197
 
153
198
  async processRemoveEvent(messageObj) {
@@ -157,6 +202,13 @@ class DeviceController {
157
202
  }
158
203
  }
159
204
 
205
+ removeDeviceByIeee(devices, ieee_address) {
206
+ const idx = devices.findIndex(x => x.ieee_address == ieee_address);
207
+ if (idx > -1) {
208
+ devices.splice(idx, 1);
209
+ }
210
+ }
211
+
160
212
  async copyAndCleanStateObj(state) {
161
213
  const iobState = { ...state };
162
214
  const blacklistedKeys = [
package/lib/exposes.js CHANGED
@@ -38,8 +38,7 @@ function genState(expose, role, name, desc) {
38
38
 
39
39
  if (readable) {
40
40
  state.getter = (payload) => (payload[propName] === (expose.value_on || 'ON'));
41
- }
42
- else {
41
+ } else {
43
42
  state.getter = (_payload) => (undefined);
44
43
  }
45
44
 
@@ -121,7 +120,7 @@ function genState(expose, role, name, desc) {
121
120
  return state;
122
121
  }
123
122
 
124
- function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
123
+ function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, config) {
125
124
  const states = [];
126
125
  // make the different (set and get) part of state is updatable if different exposes is used for get and set
127
126
  // as example:
@@ -161,8 +160,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
161
160
  }
162
161
 
163
162
  return states.push(state);
164
- }
165
- else {
163
+ } else {
166
164
 
167
165
  if ((state.readable) && (!states[stateExists].readable)) {
168
166
  states[stateExists].read = state.read;
@@ -192,8 +190,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
192
190
  }
193
191
  delete states[stateExists].prop;
194
192
  }
195
- }
196
- else if (state.hasOwnProperty('prop')) {
193
+ } else if (state.hasOwnProperty('prop')) {
197
194
  states[stateExists].prop = state.prop;
198
195
  }
199
196
  states[stateExists].readable = true;
@@ -220,16 +217,14 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
220
217
  // or remove it
221
218
  if (((!state.hasOwnProperty('isOption')) || (state.isOptions === false)) && (states[stateExists].hasOwnProperty('isOption'))) {
222
219
  delete states[stateExists].isOption;
223
- }
224
- else {
220
+ } else {
225
221
  states[stateExists].isOption = state.isOption;
226
222
  }
227
223
 
228
224
  // use new `setattr` or `prop` as `setattr`
229
225
  if (state.hasOwnProperty('setattr')) {
230
226
  states[stateExists].setattr = state.setattr;
231
- }
232
- else if (state.hasOwnProperty('prop')) {
227
+ } else if (state.hasOwnProperty('prop')) {
233
228
  states[stateExists].setattr = state.prop;
234
229
  }
235
230
 
@@ -322,22 +317,24 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
322
317
  write: true,
323
318
  read: true,
324
319
  type: 'number',
325
- min: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_min),
326
- max: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_max),
327
- unit: useKelvin == true ? 'K' : 'mired',
320
+ min: config.useKelvin == true ? utils.miredKelvinConversion(prop.value_max) : prop.value_min,
321
+ max: config.useKelvin == true ? utils.miredKelvinConversion(prop.value_min) : prop.value_max,
322
+ unit: config.useKelvin == true ? 'K' : 'mired',
328
323
  setter: (value) => {
329
324
  return utils.toMired(value);
330
325
  },
331
- setterOpt: (_value, options) => {
332
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
333
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
334
- return { ...options, transition: transitionTime };
335
- },
326
+ // setterOpt: (_value, options) => {
327
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
328
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
329
+ // return { ...options, transition: transitionTime };
330
+ // },
336
331
  getter: (payload) => {
337
- if (useKelvin == true) {
338
- return utils.miredKelvinConversion(payload.color_temp);
332
+ if (payload.color_mode != 'color_temp') {
333
+ return undefined;
339
334
  }
340
- else {
335
+ if (config.useKelvin == true) {
336
+ return utils.miredKelvinConversion(payload.color_temp);
337
+ } else {
341
338
  return payload.color_temp;
342
339
  }
343
340
  },
@@ -370,12 +367,10 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
370
367
  };
371
368
 
372
369
  },
373
- setterOpt: (_value, options) => {
374
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
375
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
376
- return { ...options, transition: transitionTime };
377
- },
378
370
  getter: payload => {
371
+ if (payload.color_mode != 'xy' && config.colorTempSyncColor == false) {
372
+ return undefined;
373
+ }
379
374
  if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
380
375
  const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
381
376
  return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
@@ -578,6 +573,10 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
578
573
  state = statesDefs.temperature;
579
574
  break;
580
575
 
576
+ case 'device_temperature':
577
+ state = statesDefs.device_temperature;
578
+ break;
579
+
581
580
  case 'humidity':
582
581
  state = statesDefs.humidity;
583
582
  break;
@@ -598,6 +597,24 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
598
597
  state = statesDefs.load_power;
599
598
  break;
600
599
 
600
+ case 'current':
601
+ state = statesDefs.load_current;
602
+ break;
603
+
604
+ case 'voltage':
605
+ state = statesDefs.voltage;
606
+ if (power_source == 'Battery') {
607
+ state = statesDefs.battery_voltage;
608
+ }
609
+ if (expose.unit == 'mV') {
610
+ state.getter = payload => payload.voltage / 1000;
611
+ }
612
+ break;
613
+
614
+ case 'energy':
615
+ state = statesDefs.energy;
616
+ break;
617
+
601
618
  default:
602
619
  state = genState(expose);
603
620
  break;
@@ -761,13 +778,14 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
761
778
  case 'running_mode':
762
779
  pushToStates(statesDefs.climate_running_mode, prop.access);
763
780
  break;
764
- default: {
765
- if (prop.name.includes('heating_setpoint')) {
766
- pushToStates(genState(prop, 'level.temperature'), prop.access);
767
- } else {
768
- pushToStates(genState(prop), prop.access);
781
+ default:
782
+ {
783
+ if (prop.name.includes('heating_setpoint')) {
784
+ pushToStates(genState(prop, 'level.temperature'), prop.access);
785
+ } else {
786
+ pushToStates(genState(prop), prop.access);
787
+ }
769
788
  }
770
- }
771
789
  break;
772
790
  }
773
791
  }
@@ -800,13 +818,11 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
800
818
  st.getter = payload => {
801
819
  if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
802
820
  return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined;
803
- }
804
- else {
821
+ } else {
805
822
  return undefined;
806
823
  }
807
824
  };
808
- }
809
- else {
825
+ } else {
810
826
  st.getter = _payload => { return undefined; };
811
827
  }
812
828
  pushToStates(st, prop.access);
@@ -850,15 +866,13 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
850
866
  return newDevice;
851
867
  }
852
868
 
853
- function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
854
- // if the device is already present in the cache, remove it
855
- utils.removeDeviceByIeee(devices, ieee_address);
869
+ function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source, scenes, config) {
856
870
  if (definitions.hasOwnProperty('exposes')) {
857
- const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin);
871
+ const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, config);
858
872
  devices.push(newDevice);
859
873
  }
860
874
  }
861
875
 
862
876
  module.exports = {
863
877
  defineDeviceFromExposes: defineDeviceFromExposes,
864
- };
878
+ };
package/lib/messages.js CHANGED
@@ -1,18 +1,39 @@
1
1
  async function adapterInfo(config, log) {
2
- log.info(`Zigbee2MQTT Frontend Server: ${config.server}`);
3
- log.info(`Zigbee2MQTT Frontend Port: ${config.port}`);
4
- log.info(`Zigbee2MQTT Debug Log: ${config.debugLogEnabled ? 'activated' : 'deactivated'}`);
5
- log.info(`Proxy Zigbee2MQTT Logs to ioBroker Logs: ${config.proxyZ2MLogs ? 'activated' : 'deactivated'}`);
6
- log.info(`Use Kelvin: ${config.useKelvin ? 'yes' : 'no'}`);
2
+ log.info('================================= Adapter Config =================================');
3
+ log.info(`|| Zigbee2MQTT Frontend Scheme: ${config.webUIScheme}`);
4
+ log.info(`|| Zigbee2MQTT Frontend Server: ${config.webUIServer}`);
5
+ log.info(`|| Zigbee2MQTT Frontend Port: ${config.webUIPort}`);
6
+ log.info(`|| Zigbee2MQTT Connection Type: ${config.connectionType}`);
7
+ if (config.connectionType == 'ws') {
8
+ log.info(`|| Zigbee2MQTT Websocket Server: ${config.wsServerIP}`);
9
+ log.info(`|| Zigbee2MQTT Websocket Port: ${config.wsServerPort}`);
10
+ log.info(`|| Zigbee2MQTT Websocket Dummy MQTT-Server: ${config.dummyMqtt ? 'activated' : 'deactivated'}`);
11
+ if (config.dummyMqtt == true) {
12
+ log.info(`|| Zigbee2MQTT Dummy MQTT IP-Bind: ${config.mqttServerIPBind}`);
13
+ log.info(`|| Zigbee2MQTT Dummy MQTT Port: ${config.mqttServerPort}`);
14
+ }
15
+ } else if (config.connectionType == 'exmqtt') {
16
+ log.info(`|| Zigbee2MQTT Externanl MQTT Server: ${config.externalMqttServerIP}`);
17
+ log.info(`|| Zigbee2MQTT Externanl MQTT Port: ${config.externalMqttServerPort}`);
18
+ } else if (config.connectionType == 'intmqtt') {
19
+ log.info(`|| Zigbee2MQTT Internal MQTT IP-Bind: ${config.mqttServerIPBind}`);
20
+ log.info(`|| Zigbee2MQTT Internal MQTT Port: ${config.mqttServerPort}`);
21
+ }
22
+ log.info(`|| Zigbee2MQTT Debug Log: ${config.debugLogEnabled ? 'activated' : 'deactivated'}`);
23
+ log.info(`|| Proxy Zigbee2MQTT Logs to ioBroker Logs: ${config.proxyZ2MLogs ? 'activated' : 'deactivated'}`);
24
+ log.info(`|| Use Kelvin: ${config.useKelvin ? 'yes' : 'no'}`);
25
+ log.info('==================================================================================');
7
26
  }
8
27
 
9
28
  async function zigbee2mqttInfo(payload, log) {
10
- log.info(`Zigbee2MQTT Version: ${payload.version} `);
11
- log.info(`Coordinator type: ${payload.coordinator.type} Version: ${payload.coordinator.meta.revision} Serial: ${payload.config.serial.port}`);
12
- log.info(`Network panid ${payload.network.pan_id} channel: ${payload.network.channel} ext_pan_id: ${payload.network.extended_pan_id}`);
29
+ log.info('============================ Zigbee2MQTT Information =============================');
30
+ log.info(`|| Zigbee2MQTT Version: ${payload.version} `);
31
+ log.info(`|| Coordinator type: ${payload.coordinator.type} Version: ${payload.coordinator.meta.revision} Serial: ${payload.config.serial.port}`);
32
+ log.info(`|| Network panid ${payload.network.pan_id} channel: ${payload.network.channel} ext_pan_id: ${payload.network.extended_pan_id}`);
33
+ log.info('==================================================================================');
13
34
  }
14
35
 
15
36
  module.exports = {
16
- adapterInfo: adapterInfo,
17
- zigbee2mqttInfo: zigbee2mqttInfo,
37
+ adapterInfo,
38
+ zigbee2mqttInfo,
18
39
  };
@@ -0,0 +1,42 @@
1
+ const core = require('@iobroker/adapter-core');
2
+ const Aedes = require('aedes');
3
+ const net = require('net');
4
+
5
+
6
+ class MqttServerController {
7
+ constructor(adapter) {
8
+ this.adapter = adapter;
9
+ }
10
+
11
+ async createMQTTServer() {
12
+ try {
13
+ const NedbPersistence = require('aedes-persistence-nedb');
14
+ const db = new NedbPersistence({ path: `${core.getAbsoluteInstanceDataDir(this.adapter)}/mqttData`, prefix: '' });
15
+ // @ts-ignore
16
+ const aedes = Aedes({ persistence: db });
17
+ const mqttServer = net.createServer(aedes.handle);
18
+ mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
19
+ this.adapter.log.info(`Statring MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`);
20
+ });
21
+ } catch (err) {
22
+ this.adapter.log.error(err);
23
+ }
24
+ }
25
+
26
+ async createDummyMQTTServer() {
27
+ try {
28
+ // @ts-ignore
29
+ const aedes = Aedes();
30
+ const mqttServer = net.createServer(aedes.handle);
31
+ mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
32
+ this.adapter.log.info(`Statring DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`);
33
+ });
34
+ } catch (err) {
35
+ this.adapter.log.error(err);
36
+ }
37
+ }
38
+ }
39
+
40
+ module.exports = {
41
+ MqttServerController
42
+ };
package/lib/rgb.js CHANGED
@@ -73,14 +73,12 @@ function cie_to_rgb(x, y, brightness) {
73
73
  green = green / red;
74
74
  blue = blue / red;
75
75
  red = 1.0;
76
- }
77
- else if (green > blue && green > red && green > 1.0) {
76
+ } else if (green > blue && green > red && green > 1.0) {
78
77
 
79
78
  red = red / green;
80
79
  blue = blue / green;
81
80
  green = 1.0;
82
- }
83
- else if (blue > red && blue > green && blue > 1.0) {
81
+ } else if (blue > red && blue > green && blue > 1.0) {
84
82
 
85
83
  red = red / blue;
86
84
  green = green / blue;
@@ -157,7 +155,9 @@ function hsvToRGB(h, s, v) {
157
155
  s = s / 100;
158
156
  v = v / 100;
159
157
 
160
- let r; let g; let b;
158
+ let r;
159
+ let g;
160
+ let b;
161
161
  if (arguments.length === 1) {
162
162
  s = h.s, v = h.v, h = h.h;
163
163
  }
@@ -167,12 +167,24 @@ function hsvToRGB(h, s, v) {
167
167
  const q = v * (1 - f * s);
168
168
  const t = v * (1 - (1 - f) * s);
169
169
  switch (i % 6) {
170
- case 0: r = v, g = t, b = p; break;
171
- case 1: r = q, g = v, b = p; break;
172
- case 2: r = p, g = v, b = t; break;
173
- case 3: r = p, g = q, b = v; break;
174
- case 4: r = t, g = p, b = v; break;
175
- case 5: r = v, g = p, b = q; break;
170
+ case 0:
171
+ r = v, g = t, b = p;
172
+ break;
173
+ case 1:
174
+ r = q, g = v, b = p;
175
+ break;
176
+ case 2:
177
+ r = p, g = v, b = t;
178
+ break;
179
+ case 3:
180
+ r = p, g = q, b = v;
181
+ break;
182
+ case 4:
183
+ r = t, g = p, b = v;
184
+ break;
185
+ case 5:
186
+ r = v, g = p, b = q;
187
+ break;
176
188
  }
177
189
  return {
178
190
  r: Math.round(r * 255),
@@ -185,17 +197,29 @@ function rgbToHSV(r, g, b, numeric) {
185
197
  if (arguments.length === 1) {
186
198
  g = r.g, b = r.b, r = r.r;
187
199
  }
188
- const max = Math.max(r, g, b); const min = Math.min(r, g, b);
200
+ const max = Math.max(r, g, b);
201
+ const min = Math.min(r, g, b);
189
202
  const d = max - min;
190
203
  let h;
191
204
  const s = (max === 0 ? 0 : d / max);
192
205
  const v = max / 255;
193
206
 
194
207
  switch (max) {
195
- case min: h = 0; break;
196
- case r: h = (g - b) + d * (g < b ? 6 : 0); h /= 6 * d; break;
197
- case g: h = (b - r) + d * 2; h /= 6 * d; break;
198
- case b: h = (r - g) + d * 4; h /= 6 * d; break;
208
+ case min:
209
+ h = 0;
210
+ break;
211
+ case r:
212
+ h = (g - b) + d * (g < b ? 6 : 0);
213
+ h /= 6 * d;
214
+ break;
215
+ case g:
216
+ h = (b - r) + d * 2;
217
+ h /= 6 * d;
218
+ break;
219
+ case b:
220
+ h = (r - g) + d * 4;
221
+ h /= 6 * d;
222
+ break;
199
223
  }
200
224
  if (numeric) return {
201
225
  // @ts-ignore
@@ -210,6 +234,7 @@ function rgbToHSV(r, g, b, numeric) {
210
234
  v: (v * 100).toFixed(3),
211
235
  };
212
236
  }
237
+
213
238
  function colorArrayFromString(value) {
214
239
  if (typeof (value) === 'string') {
215
240
  const rv = [];
@@ -260,4 +285,4 @@ exports.hsvToRGB = hsvToRGB;
260
285
  exports.rgbToHSV = rgbToHSV;
261
286
  exports.colorArrayFromString = colorArrayFromString;
262
287
  exports.colorStringFromRGBArray = colorStringFromRGBArray;
263
- exports.hsvToRGBString = hsvToRGBString;
288
+ exports.hsvToRGBString = hsvToRGBString;
package/lib/states.js CHANGED
@@ -274,17 +274,16 @@ const states = {
274
274
  },
275
275
  voltage: {
276
276
  id: 'voltage',
277
- name: 'Battery voltage',
277
+ name: 'Voltage',
278
278
  icon: undefined,
279
- role: 'battery.voltage',
279
+ role: 'value.voltage',
280
280
  write: false,
281
281
  read: true,
282
282
  type: 'number',
283
283
  unit: 'V',
284
- getter: payload => payload.voltage / 1000,
285
284
  def: 0,
286
285
  },
287
- ecozy_voltage: {
286
+ battery_voltage: {
288
287
  id: 'voltage',
289
288
  name: 'Battery voltage',
290
289
  icon: undefined,
@@ -293,9 +292,18 @@ const states = {
293
292
  read: true,
294
293
  type: 'number',
295
294
  unit: 'V',
296
- getter: payload => payload.voltage * 10,
297
295
  def: 0,
298
296
  },
297
+ energy: {
298
+ id: 'energy',
299
+ name: 'Sum of consumed energy',
300
+ icon: undefined,
301
+ role: 'value.power.consumption',
302
+ write: false,
303
+ read: true,
304
+ type: 'number',
305
+ unit: 'kWh'
306
+ },
299
307
  battery: {
300
308
  id: 'battery',
301
309
  prop: 'battery',
@@ -546,6 +554,17 @@ const states = {
546
554
  type: 'boolean',
547
555
  getter: payload => (payload.button_right === 'hold'),
548
556
  },
557
+ device_temperature: {
558
+ id: 'device_temperature',
559
+ name: 'Temperature of the device',
560
+ icon: undefined,
561
+ role: 'value.temperature',
562
+ write: false,
563
+ read: true,
564
+ type: 'number',
565
+ unit: '°C',
566
+ def: 0,
567
+ },
549
568
  temperature: {
550
569
  id: 'temperature',
551
570
  name: 'Temperature',
@@ -736,7 +755,7 @@ const states = {
736
755
  type: 'boolean',
737
756
  def: false,
738
757
  },
739
- smoke_detected2: { // for Heiman
758
+ smoke_detected2: { // for Heiman
740
759
  id: 'smoke',
741
760
  prop: 'smoke',
742
761
  name: 'Smoke leak detected',
@@ -747,7 +766,7 @@ const states = {
747
766
  type: 'boolean',
748
767
  def: false,
749
768
  },
750
- co_detected: { // for Heiman
769
+ co_detected: { // for Heiman
751
770
  id: 'carbon_monoxide',
752
771
  prop: 'carbon_monoxide',
753
772
  name: 'CO leak detected',
@@ -1074,11 +1093,11 @@ const states = {
1074
1093
  unit: 'V'
1075
1094
  },
1076
1095
  load_current: {
1077
- id: 'current',
1096
+ id: 'load_current',
1078
1097
  prop: 'current',
1079
1098
  name: 'Load current',
1080
1099
  icon: undefined,
1081
- role: 'value',
1100
+ role: 'value.current',
1082
1101
  write: false,
1083
1102
  read: true,
1084
1103
  type: 'number',
@@ -1232,12 +1251,15 @@ const states = {
1232
1251
  y: xy[1]
1233
1252
  };
1234
1253
  },
1235
- setterOpt: (value, options) => {
1236
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
1237
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
1238
- return { ...options, transition: transitionTime };
1239
- },
1254
+ // setterOpt: (value, options) => {
1255
+ // const hasTransitionTime = options && options.hasOwnProperty('transition_time');
1256
+ // const transitionTime = hasTransitionTime ? options.transition_time : 0;
1257
+ // return { ...options, transition: transitionTime };
1258
+ // },
1240
1259
  getter: payload => {
1260
+ if (payload.color_mode != 'xy') {
1261
+ return undefined;
1262
+ }
1241
1263
  if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
1242
1264
  const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
1243
1265
  return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
@@ -2625,8 +2647,7 @@ const states = {
2625
2647
  max: 1,
2626
2648
  type: 'number',
2627
2649
  },
2628
- thermostat_keypad_lockout:
2629
- {
2650
+ thermostat_keypad_lockout: {
2630
2651
  id: 'keypad_lockout',
2631
2652
  name: 'Keypad Lockout',
2632
2653
  prop: 'keypad_lockout',
@@ -5844,8 +5865,7 @@ const states = {
5844
5865
  setter: (value, options) => {
5845
5866
  try {
5846
5867
  return JSON.parse(value);
5847
- }
5848
- catch (err) {
5868
+ } catch (err) {
5849
5869
  const effectjson = {
5850
5870
  colors: [{ r: 255, g: 0, b: 0 }, { r: 0, g: 255, b: 0 }, { r: 0, g: 0, b: 255 }],
5851
5871
  speed: 10,
@@ -6419,4 +6439,4 @@ module.exports = {
6419
6439
  states: states,
6420
6440
  unitLookup: unitLookup,
6421
6441
  nameLookup: nameLookup,
6422
- };
6442
+ };