iobroker.zigbee2mqtt 0.2.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.
package/lib/check.js ADDED
@@ -0,0 +1,36 @@
1
+ function checkConfig(config, log) {
2
+ const checkAPIOptions = {
3
+ legacy_api_enabled: config.advanced.legacy_api != false,
4
+ legacy_availability_payload_enabled: config.advanced.legacy_availability_payload != false,
5
+ device_legacy_enabled: config.device_options.legacy != false
6
+ };
7
+
8
+ if (Object.values(checkAPIOptions).filter(x => x == true).length > 0) {
9
+ log.error('===================================================');
10
+ log.error('===================================================');
11
+ if (checkAPIOptions.legacy_api_enabled == true) {
12
+ log.error('Legacy api is activated, so the adapter can not work correctly!!!');
13
+ log.error('Please add the following lines to your Zigbee2MQTT configuration.yaml:');
14
+ log.error('legacy_api: false');
15
+ log.error('');
16
+ }
17
+ if (checkAPIOptions.legacy_availability_payload_enabled == true) {
18
+ log.error('Legacy Availability Payload is activated, thus the adapter cannot represent the availability of the devices!!!');
19
+ log.error('Please add the following lines to your Zigbee2MQTT configuration.yaml:');
20
+ log.error('legacy_availability_payload: false');
21
+ log.error('');
22
+ }
23
+ if (checkAPIOptions.device_legacy_enabled == true) {
24
+ log.error('Device Legacy Payload is activated, therefore the adapter may process the states of the devices correctly!!!');
25
+ log.error('Please add the following lines to your Zigbee2MQTT configuration.yaml:');
26
+ log.error('device_options:');
27
+ log.error(' legacy: false');
28
+ }
29
+ log.error('===================================================');
30
+ log.error('===================================================');
31
+ }
32
+ }
33
+
34
+ module.exports = {
35
+ checkConfig: checkConfig,
36
+ };
package/lib/colors.js CHANGED
@@ -453,6 +453,8 @@ function NamedColorToRGB(name) {
453
453
  return { r: 0, g: 128, b: 255 };
454
454
  }
455
455
 
456
- exports.NamedColorToRGB = NamedColorToRGB;
457
- exports.NamedCOlorToRGBString = NamedColorToRGBstring;
458
- exports.ParseColor = ParseColor;
456
+ module.exports = {
457
+ NamedColorToRGB,
458
+ NamedColorToRGBstring,
459
+ ParseColor,
460
+ };
@@ -0,0 +1,234 @@
1
+ const states = require('./states').states;
2
+ const defineDeviceFromExposes = require('./exposes').defineDeviceFromExposes;
3
+ const utils = require('./utils');
4
+ const colors = require('./colors.js');
5
+ const rgb = require('./rgb.js');
6
+ const createCache = {};
7
+
8
+ class DeviceController {
9
+ constructor(adapter, deviceCache, groupCache, config) {
10
+ this.adapter = adapter;
11
+ this.groupCache = groupCache;
12
+ this.deviceCache = deviceCache;
13
+ this.config = config;
14
+ }
15
+
16
+ async createDeviceDefinitions(exposes) {
17
+ utils.clearArray(this.deviceCache);
18
+ for (const expose of exposes) {
19
+ if (expose.definition != null) {
20
+ // search for scenes in the endpoints and build them into an array
21
+ let scenes = [];
22
+ for (const key in expose.endpoints) {
23
+ if (expose.endpoints[key].scenes) {
24
+ scenes = scenes.concat(expose.endpoints[key].scenes);
25
+ }
26
+ }
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);
30
+ }
31
+ }
32
+ }
33
+
34
+
35
+ async defineGroupDevice(groupID, ieee_address, scenes) {
36
+ const newDevice = {
37
+ id: groupID,
38
+ ieee_address: ieee_address,
39
+ icon: undefined,
40
+ states: [
41
+ states.state,
42
+ states.brightness,
43
+ //states.color,
44
+ states.brightness_move,
45
+ states.colortemp_move,
46
+ ],
47
+ };
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
+
83
+ const colortemp = {
84
+ id: 'colortemp',
85
+ prop: 'color_temp',
86
+ name: 'Color temperature',
87
+ icon: undefined,
88
+ role: 'level.color.temperature',
89
+ write: true,
90
+ read: true,
91
+ type: 'number',
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',
95
+ setter: (value) => {
96
+ return utils.toMired(value);
97
+ },
98
+ getter: (payload) => {
99
+ if (payload.color_mode != 'color_temp') {
100
+ return undefined;
101
+ }
102
+ if (this.config.useKelvin == true) {
103
+ return utils.miredKelvinConversion(payload.color_temp);
104
+ } else {
105
+ return payload.color_temp;
106
+ }
107
+ },
108
+ };
109
+
110
+ // @ts-ignore
111
+ newDevice.states.push(colortemp);
112
+
113
+ // Create buttons for scenes
114
+ for (const scene of scenes) {
115
+ const sceneSate = {
116
+ id: `scene_${scene.id}`,
117
+ prop: `scene_recall`,
118
+ name: scene.name,
119
+ icon: undefined,
120
+ role: 'button',
121
+ write: true,
122
+ read: true,
123
+ type: 'boolean',
124
+ setter: (value) => (value) ? scene.id : undefined
125
+ };
126
+ // @ts-ignore
127
+ newDevice.states.push(sceneSate);
128
+ }
129
+
130
+ // if the device is already present in the cache, remove it
131
+ this.removeDeviceByIeee(this.groupCache, ieee_address);
132
+ this.groupCache.push(newDevice);
133
+ }
134
+
135
+ async createGroupDefinitions(exposes) {
136
+ utils.clearArray(this.groupCache);
137
+ for (const expose of exposes) {
138
+ await this.defineGroupDevice(expose.friendly_name, `group_${expose.id}`, expose.scenes);
139
+ }
140
+ }
141
+
142
+ async createOrUpdateDevices() {
143
+ for (const device of this.groupCache.concat(this.deviceCache)) {
144
+ const deviceName = device.id == device.ieee_address ? '' : device.id;
145
+ if (!createCache[device.ieee_address] || createCache[device.ieee_address].common.name != deviceName) {
146
+ const deviceObj = {
147
+ type: 'device',
148
+ common: {
149
+ name: deviceName,
150
+ },
151
+
152
+ native: {}
153
+ };
154
+
155
+ if (!device.ieee_address.includes('group_')) {
156
+ deviceObj.common.statusStates = {
157
+ onlineId: `${this.adapter.name}.${this.adapter.instance}.${device.ieee_address}.available`
158
+ };
159
+ }
160
+
161
+ //@ts-ignore
162
+ await this.adapter.extendObjectAsync(device.ieee_address, deviceObj);
163
+ createCache[device.ieee_address] = deviceObj;
164
+ }
165
+
166
+ // Here it is checked whether the scenes match the current data from z2m.
167
+ // If necessary, scenes are automatically deleted from ioBroker.
168
+ const sceneStates = await this.adapter.getStatesAsync(`${device.ieee_address}.scene_*`);
169
+ const sceneIDs = Object.keys(sceneStates);
170
+ for (const sceneID of sceneIDs) {
171
+ const stateID = sceneID.split('.')[3];
172
+ if (device.states.find(x => x.id == stateID) == null) {
173
+ this.adapter.delObject(sceneID);
174
+ }
175
+ }
176
+
177
+ 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 = await this.copyAndCleanStateObj(state);
180
+ await this.adapter.extendObjectAsync(`${device.ieee_address}.${state.id}`, {
181
+ type: 'state',
182
+ common: iobState,
183
+ native: {},
184
+ });
185
+ createCache[device.ieee_address][state.id] = state.name;
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ async renameDeviceInCache(messageObj) {
192
+ const renamedDevice = this.groupCache.concat(this.deviceCache).find(x => x.id == messageObj.payload.data.from);
193
+ if (renamedDevice) {
194
+ renamedDevice.id = messageObj.payload.data.to;
195
+ }
196
+ }
197
+
198
+ async processRemoveEvent(messageObj) {
199
+ if (messageObj.payload && messageObj.payload.type == 'device_leave') {
200
+ this.adapter.setStateAsync(`${messageObj.payload.data.ieee_address}.available`, false, true);
201
+ this.adapter.extendObject(`${messageObj.payload.data.ieee_address}`, { common: { name: 'Device removed!', } });
202
+ }
203
+ }
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
+
212
+ async copyAndCleanStateObj(state) {
213
+ const iobState = { ...state };
214
+ const blacklistedKeys = [
215
+ 'setter',
216
+ 'setterOpt',
217
+ 'getter',
218
+ 'setattr',
219
+ 'readable',
220
+ 'writable',
221
+ 'isOption',
222
+ 'inOptions',
223
+ 'isEvent',
224
+ ];
225
+ for (const blacklistedKey of blacklistedKeys) {
226
+ delete iobState[blacklistedKey];
227
+ }
228
+ return iobState;
229
+ }
230
+ }
231
+
232
+ module.exports = {
233
+ DeviceController
234
+ };
package/lib/exposes.js CHANGED
@@ -7,6 +7,8 @@ const rgb = require('./rgb');
7
7
  const utils = require('./utils');
8
8
  const colors = require('./colors');
9
9
 
10
+ const blacklistSimulatedBrightness = ['MFKZQ01LM'];
11
+
10
12
  function genState(expose, role, name, desc) {
11
13
  let state;
12
14
  const readable = true; //expose.access > 0;
@@ -36,8 +38,7 @@ function genState(expose, role, name, desc) {
36
38
 
37
39
  if (readable) {
38
40
  state.getter = (payload) => (payload[propName] === (expose.value_on || 'ON'));
39
- }
40
- else {
41
+ } else {
41
42
  state.getter = (_payload) => (undefined);
42
43
  }
43
44
 
@@ -119,7 +120,7 @@ function genState(expose, role, name, desc) {
119
120
  return state;
120
121
  }
121
122
 
122
- function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
123
+ function createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, config) {
123
124
  const states = [];
124
125
  // make the different (set and get) part of state is updatable if different exposes is used for get and set
125
126
  // as example:
@@ -159,8 +160,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
159
160
  }
160
161
 
161
162
  return states.push(state);
162
- }
163
- else {
163
+ } else {
164
164
 
165
165
  if ((state.readable) && (!states[stateExists].readable)) {
166
166
  states[stateExists].read = state.read;
@@ -190,8 +190,7 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
190
190
  }
191
191
  delete states[stateExists].prop;
192
192
  }
193
- }
194
- else if (state.hasOwnProperty('prop')) {
193
+ } else if (state.hasOwnProperty('prop')) {
195
194
  states[stateExists].prop = state.prop;
196
195
  }
197
196
  states[stateExists].readable = true;
@@ -218,16 +217,14 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
218
217
  // or remove it
219
218
  if (((!state.hasOwnProperty('isOption')) || (state.isOptions === false)) && (states[stateExists].hasOwnProperty('isOption'))) {
220
219
  delete states[stateExists].isOption;
221
- }
222
- else {
220
+ } else {
223
221
  states[stateExists].isOption = state.isOption;
224
222
  }
225
223
 
226
224
  // use new `setattr` or `prop` as `setattr`
227
225
  if (state.hasOwnProperty('setattr')) {
228
226
  states[stateExists].setattr = state.setattr;
229
- }
230
- else if (state.hasOwnProperty('prop')) {
227
+ } else if (state.hasOwnProperty('prop')) {
231
228
  states[stateExists].setattr = state.prop;
232
229
  }
233
230
 
@@ -320,22 +317,24 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
320
317
  write: true,
321
318
  read: true,
322
319
  type: 'number',
323
- min: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_min),
324
- max: undefined, //useKelvin == true ? expose.value_min : utils.miredKelvinConversion(expose.value_max),
325
- 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',
326
323
  setter: (value) => {
327
324
  return utils.toMired(value);
328
325
  },
329
- setterOpt: (_value, options) => {
330
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
331
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
332
- return { ...options, transition: transitionTime };
333
- },
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
+ // },
334
331
  getter: (payload) => {
335
- if (useKelvin == true) {
336
- return utils.miredKelvinConversion(payload.color_temp);
332
+ if (payload.color_mode != 'color_temp') {
333
+ return undefined;
337
334
  }
338
- else {
335
+ if (config.useKelvin == true) {
336
+ return utils.miredKelvinConversion(payload.color_temp);
337
+ } else {
339
338
  return payload.color_temp;
340
339
  }
341
340
  },
@@ -368,12 +367,10 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
368
367
  };
369
368
 
370
369
  },
371
- setterOpt: (_value, options) => {
372
- const hasTransitionTime = options && options.hasOwnProperty('transition_time');
373
- const transitionTime = hasTransitionTime ? options.transition_time : 0;
374
- return { ...options, transition: transitionTime };
375
- },
376
370
  getter: payload => {
371
+ if (payload.color_mode != 'xy' && config.colorTempSyncColor == false) {
372
+ return undefined;
373
+ }
377
374
  if (payload.color && payload.color.hasOwnProperty('x') && payload.color.hasOwnProperty('y')) {
378
375
  const colorval = rgb.cie_to_rgb(payload.color.x, payload.color.y);
379
376
  return '#' + utils.decimalToHex(colorval[0]) + utils.decimalToHex(colorval[1]) + utils.decimalToHex(colorval[2]);
@@ -576,6 +573,10 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
576
573
  state = statesDefs.temperature;
577
574
  break;
578
575
 
576
+ case 'device_temperature':
577
+ state = statesDefs.device_temperature;
578
+ break;
579
+
579
580
  case 'humidity':
580
581
  state = statesDefs.humidity;
581
582
  break;
@@ -596,6 +597,24 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
596
597
  state = statesDefs.load_power;
597
598
  break;
598
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
+
599
618
  default:
600
619
  state = genState(expose);
601
620
  break;
@@ -622,7 +641,6 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
622
641
  if (hasHold && hasRelease && actionName.includes('release')) continue;
623
642
  // is hold state ?
624
643
  if (hasHold && hasRelease && actionName.includes('hold')) {
625
- const releaseActionName = actionName.replace('hold', 'release');
626
644
  state = {
627
645
  id: actionName.replace(/\*/g, ''),
628
646
  prop: 'action',
@@ -631,8 +649,20 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
631
649
  role: 'button',
632
650
  write: false,
633
651
  read: true,
652
+ def: false,
634
653
  type: 'boolean',
635
- getter: payload => (payload.action === actionName) ? true : (payload.action === releaseActionName) ? false : undefined,
654
+ getter: (payload) => {
655
+ if (payload.action === actionName) {
656
+ return true;
657
+ }
658
+ if (payload.action === actionName.replace('hold', 'release')) {
659
+ return false;
660
+ }
661
+ if (payload.action === `${actionName}_release`) {
662
+ return false;
663
+ }
664
+ return undefined;
665
+ },
636
666
  };
637
667
  } else {
638
668
  state = {
@@ -644,12 +674,30 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
644
674
  write: false,
645
675
  read: true,
646
676
  type: 'boolean',
647
- getter: payload => (payload.action === actionName) ? true : undefined,
677
+ def: false,
648
678
  isEvent: true,
679
+ getter: payload => (payload.action === actionName) ? true : undefined,
649
680
  };
650
681
  }
651
682
  pushToStates(state, expose.access);
652
683
  }
684
+ if (!blacklistSimulatedBrightness.includes(definitions.model)) {
685
+ pushToStates({
686
+ id: 'simulated_brightness',
687
+ prop: 'brightness',
688
+ name: 'Simulated brightness',
689
+ icon: undefined,
690
+ role: 'level.dimmer',
691
+ write: true,
692
+ read: true,
693
+ type: 'number',
694
+ unit: '%',
695
+ def: 0,
696
+ getter: payload => {
697
+ return utils.bulbLevelToAdapterLevel(payload.brightness);
698
+ },
699
+ }, 1);
700
+ }
653
701
  state = null;
654
702
  break;
655
703
  }
@@ -730,13 +778,14 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
730
778
  case 'running_mode':
731
779
  pushToStates(statesDefs.climate_running_mode, prop.access);
732
780
  break;
733
- default: {
734
- if (prop.name.includes('heating_setpoint')) {
735
- pushToStates(genState(prop, 'level.temperature'), prop.access);
736
- } else {
737
- 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
+ }
738
788
  }
739
- }
740
789
  break;
741
790
  }
742
791
  }
@@ -769,13 +818,11 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
769
818
  st.getter = payload => {
770
819
  if ((payload.hasOwnProperty(expose.property)) && (payload[expose.property] !== null) && payload[expose.property].hasOwnProperty(prop.property)) {
771
820
  return !isNaN(payload[expose.property][prop.property]) ? payload[expose.property][prop.property] : undefined;
772
- }
773
- else {
821
+ } else {
774
822
  return undefined;
775
823
  }
776
824
  };
777
- }
778
- else {
825
+ } else {
779
826
  st.getter = _payload => { return undefined; };
780
827
  }
781
828
  pushToStates(st, prop.access);
@@ -819,15 +866,13 @@ function createFromExposes(deviceID, ieee_address, definitions, power_source, sc
819
866
  return newDevice;
820
867
  }
821
868
 
822
- function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source, scenes, useKelvin) {
823
- // if the device is already present in the cache, remove it
824
- utils.removeDeviceByIeee(devices, ieee_address);
869
+ function defineDeviceFromExposes(devices, deviceID, ieee_address, definitions, power_source, scenes, config) {
825
870
  if (definitions.hasOwnProperty('exposes')) {
826
- const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, useKelvin);
871
+ const newDevice = createFromExposes(deviceID, ieee_address, definitions, power_source, scenes, config);
827
872
  devices.push(newDevice);
828
873
  }
829
874
  }
830
875
 
831
876
  module.exports = {
832
877
  defineDeviceFromExposes: defineDeviceFromExposes,
833
- };
878
+ };
@@ -0,0 +1,39 @@
1
+ async function adapterInfo(config, log) {
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('==================================================================================');
26
+ }
27
+
28
+ async function zigbee2mqttInfo(payload, log) {
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('==================================================================================');
34
+ }
35
+
36
+ module.exports = {
37
+ adapterInfo,
38
+ zigbee2mqttInfo,
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
+ };