homebridge-tasmota-control 1.6.15-beta.31 → 1.6.15-beta.33

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/index.js CHANGED
@@ -39,7 +39,7 @@ class tasmotaPlatform {
39
39
  const host = device.host;
40
40
  if (!deviceName || !host) {
41
41
  log.warn(`Device Name: ${deviceName ? 'OK' : deviceName}, host: ${host ? 'OK' : host}, in config wrong or missing.`);
42
- return;
42
+ continue;
43
43
  }
44
44
 
45
45
  //log config
@@ -48,7 +48,7 @@ class tasmotaPlatform {
48
48
  const user = device.user || '';
49
49
  const passwd = device.passwd || '';
50
50
  const loadNameFromDevice = device.loadNameFromDevice || false;
51
- const refreshInterval = device.refreshInterval * 1000 || 5000;
51
+ const refreshInterval = Number.isInteger(device.refreshInterval) && device.refreshInterval > 0 ? device.refreshInterval * 1000 : 5000;
52
52
  const enableDebugMode = device.enableDebugMode || false;
53
53
  const logLevel = {
54
54
  debug: device.enableDebugMode,
@@ -77,37 +77,39 @@ class tasmotaPlatform {
77
77
  const info = await deviceInfo.getInfo();
78
78
  if (!info.serialNumber) {
79
79
  log.warn(`Device: ${host} ${deviceName}, serial not found.`);
80
- return;
80
+ continue;
81
81
  }
82
82
 
83
83
  let i = 0;
84
84
  for (const type of info.deviceTypes) {
85
85
  const serialNumber = i === 0 ? info.serialNumber : `${info.serialNumber}${i}`;
86
86
 
87
+ //check files exists, if not then create it
88
+ if (type === 0) {
89
+ try {
90
+ const postFix = device.host.split('.').join('');
91
+ info.defaultHeatingSetTemperatureFile = `${prefDir}/defaultHeatingSetTemperature_${postFix}`;
92
+ info.defaultCoolingSetTemperatureFile = `${prefDir}/defaultCoolingSetTemperature_${postFix}`;
93
+ const files = [
94
+ info.defaultHeatingSetTemperatureFile,
95
+ info.defaultCoolingSetTemperatureFile
96
+ ];
97
+
98
+ files.forEach((file, index) => {
99
+ if (!existsSync(file)) {
100
+ const data = ['20', '23'][index];
101
+ writeFileSync(file, data);
102
+ }
103
+ });
104
+ } catch (error) {
105
+ if (logLevel.error) log.error(`Device: ${host} ${deviceName}, Prepare files error: ${error}`);
106
+ continue;
107
+ }
108
+ }
109
+
87
110
  let deviceType;
88
111
  switch (type) {
89
112
  case 0: //mielhvac
90
- //check files exists, if not then create it
91
- try {
92
- const postFix = device.host.split('.').join('');
93
- info.defaultHeatingSetTemperatureFile = `${prefDir}/defaultHeatingSetTemperature_${postFix}`;
94
- info.defaultCoolingSetTemperatureFile = `${prefDir}/defaultCoolingSetTemperature_${postFix}`;
95
- const files = [
96
- info.defaultHeatingSetTemperatureFile,
97
- info.defaultCoolingSetTemperatureFile
98
- ];
99
-
100
- files.forEach((file, index) => {
101
- if (!existsSync(file)) {
102
- const data = ['20', '23'][index]
103
- writeFileSync(file, data);
104
- }
105
- });
106
- } catch (error) {
107
- if (logLevel.error) log.error(`Device: ${host} ${deviceName}, Prepare files error: ${error}`);
108
- return;
109
- }
110
-
111
113
  deviceType = new MiElHvac(api, device, info, serialNumber, refreshInterval);
112
114
  break;
113
115
  case 1: //switches
@@ -124,7 +126,7 @@ class tasmotaPlatform {
124
126
  break;
125
127
  default:
126
128
  if (logLevel.warn) log.warn(`Device: ${host} ${deviceName}, unknown device: ${info.deviceTypes}.`);
127
- return;
129
+ continue;
128
130
  }
129
131
 
130
132
  deviceType.on('devInfo', (msg) => logLevel.devInfo && log.info(msg))
@@ -138,7 +140,7 @@ class tasmotaPlatform {
138
140
  const impulseGenerator = new ImpulseGenerator()
139
141
  .on('start', async () => {
140
142
  try {
141
- const accessory = await deviceType.start()
143
+ const accessory = await deviceType.start();
142
144
  if (accessory) {
143
145
  api.publishExternalAccessories(PluginName, [accessory]);
144
146
  if (logLevel.success) log.success(`Device: ${host} ${deviceName}, Published as external accessory.`);
@@ -160,6 +162,8 @@ class tasmotaPlatform {
160
162
  } catch (error) {
161
163
  if (logLevel.error) log.error(`Device: ${host} ${deviceName}, Did finish launching error: ${error}.`);
162
164
  }
165
+
166
+ await new Promise(resolve => setTimeout(resolve, 300));
163
167
  }
164
168
  });
165
169
  }
@@ -172,4 +176,4 @@ class tasmotaPlatform {
172
176
  export default (api) => {
173
177
  CustomCharacteristics(api);
174
178
  api.registerPlatform(PluginName, PlatformName, tasmotaPlatform);
175
- }
179
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Tasmota Control",
3
3
  "name": "homebridge-tasmota-control",
4
- "version": "1.6.15-beta.31",
4
+ "version": "1.6.15-beta.33",
5
5
  "description": "Homebridge plugin to control Tasmota flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/fans.js CHANGED
@@ -1,7 +1,7 @@
1
- import { promises as fsPromises } from 'fs';
2
1
  import axios from 'axios';
3
2
  import EventEmitter from 'events';
4
3
  import ImpulseGenerator from './impulsegenerator.js';
4
+ import Functions from './functions.js';
5
5
  import { ApiCommands } from './constants.js';
6
6
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
7
7
 
@@ -27,6 +27,7 @@ class Fans extends EventEmitter {
27
27
  this.disableLogInfo = config.disableLogInfo || false;
28
28
  this.disableLogDeviceInfo = config.disableLogDeviceInfo || false;
29
29
  this.refreshInterval = refreshInterval;
30
+ this.functions = new Functions();
30
31
 
31
32
  //axios instance
32
33
  const url = `http://${config.host}/cm?cmnd=`;
@@ -40,27 +41,33 @@ class Fans extends EventEmitter {
40
41
  }
41
42
  });
42
43
 
43
- //impulse generator
44
- this.call = false;
44
+ //lock flags
45
+ this.locks = {
46
+ checkState: false,
47
+ };
45
48
  this.impulseGenerator = new ImpulseGenerator()
46
- .on('checkDeviceState', async () => {
47
- if (this.call) return;
48
-
49
- try {
50
- this.call = true;
51
- await this.checkDeviceState();
52
- this.call = false;
53
- } catch (error) {
54
- this.call = false;
55
- this.emit('error', `Inpulse generator error: ${error}`);
56
- };
57
- })
49
+ .on('checkState', () => this.handleWithLock('checkState', async () => {
50
+ await this.checkState();
51
+ }))
58
52
  .on('state', (state) => {
59
53
  this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
60
54
  });
61
55
  }
62
56
 
63
- async checkDeviceState() {
57
+ async handleWithLock(lockKey, fn) {
58
+ if (this.locks[lockKey]) return;
59
+
60
+ this.locks[lockKey] = true;
61
+ try {
62
+ await fn();
63
+ } catch (error) {
64
+ this.emit('error', `Inpulse generator error: ${error}`);
65
+ } finally {
66
+ this.locks[lockKey] = false;
67
+ }
68
+ }
69
+
70
+ async checkState() {
64
71
  if (this.enableDebugMode) this.emit('debug', `Requesting status`);
65
72
  try {
66
73
  //power status
@@ -151,30 +158,10 @@ class Fans extends EventEmitter {
151
158
  }
152
159
  }
153
160
 
154
- async saveData(path, data) {
155
- try {
156
- data = JSON.stringify(data, null, 2);
157
- await fsPromises.writeFile(path, data);
158
- if (this.enableDebugMode) this.emit('debug', `Saved data: ${data}`);
159
- return true;
160
- } catch (error) {
161
- throw new Error(`Save data error: ${error}`);
162
- }
163
- }
164
-
165
- async readData(path) {
166
- try {
167
- const data = await fsPromises.readFile(path);
168
- return data;
169
- } catch (error) {
170
- throw new Error(`Read data error: ${error}`);
171
- }
172
- }
173
-
174
161
  async startImpulseGenerator() {
175
162
  try {
176
163
  //start impulse generator
177
- const timers = [{ name: 'checkDeviceState', sampling: this.refreshInterval }];
164
+ const timers = [{ name: 'checkState', sampling: this.refreshInterval }];
178
165
  await this.impulseGenerator.start(timers);
179
166
  return true;
180
167
  } catch (error) {
@@ -528,7 +515,7 @@ class Fans extends EventEmitter {
528
515
  async start() {
529
516
  try {
530
517
  //check device state
531
- await this.checkDeviceState();
518
+ await this.checkState();
532
519
 
533
520
  //connect to deice success
534
521
  this.emit('success', `Connect Success`)
@@ -0,0 +1,31 @@
1
+ import { promises as fsPromises } from 'fs';
2
+
3
+ class Functions {
4
+ constructor(config) {
5
+ }
6
+
7
+ async saveData(path, data) {
8
+ try {
9
+ data = JSON.stringify(data, null, 2);
10
+ await fsPromises.writeFile(path, data);
11
+ return true;
12
+ } catch (error) {
13
+ throw new Error(`Save data error: ${error}`);
14
+ }
15
+ }
16
+
17
+ async readData(path) {
18
+ try {
19
+ const data = await fsPromises.readFile(path);
20
+ return data;
21
+ } catch (error) {
22
+ throw new Error(`Read data error: ${error}`);
23
+ }
24
+ }
25
+
26
+ async scaleValue(value, inMin, inMax, outMin, outMax) {
27
+ const scaledValue = parseFloat((((Math.max(inMin, Math.min(inMax, value)) - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin).toFixed(0));
28
+ return scaledValue;
29
+ }
30
+ }
31
+ export default Functions
package/src/lights.js CHANGED
@@ -1,7 +1,7 @@
1
- import { promises as fsPromises } from 'fs';
2
1
  import axios from 'axios';
3
2
  import EventEmitter from 'events';
4
3
  import ImpulseGenerator from './impulsegenerator.js';
4
+ import Functions from './functions.js';
5
5
  import { ApiCommands } from './constants.js';
6
6
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
7
7
 
@@ -26,6 +26,7 @@ class Lights extends EventEmitter {
26
26
  this.disableLogInfo = config.disableLogInfo || false;
27
27
  this.disableLogDeviceInfo = config.disableLogDeviceInfo || false;
28
28
  this.refreshInterval = refreshInterval;
29
+ this.functions = new Functions();
29
30
 
30
31
  //axios instance
31
32
  const url = `http://${config.host}/cm?cmnd=`;
@@ -39,26 +40,33 @@ class Lights extends EventEmitter {
39
40
  }
40
41
  });
41
42
 
42
- this.call = false;
43
+ //lock flags
44
+ this.locks = {
45
+ checkState: false,
46
+ };
43
47
  this.impulseGenerator = new ImpulseGenerator()
44
- .on('checkDeviceState', async () => {
45
- if (this.call) return;
46
-
47
- try {
48
- this.call = true;
49
- await this.checkDeviceState();
50
- this.call = false;
51
- } catch (error) {
52
- this.call = false;
53
- this.emit('error', `Inpulse generator error: ${error}`);
54
- };
55
- })
48
+ .on('checkState', () => this.handleWithLock('checkState', async () => {
49
+ await this.checkState();
50
+ }))
56
51
  .on('state', (state) => {
57
52
  this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
58
53
  });
59
54
  }
60
55
 
61
- async checkDeviceState() {
56
+ async handleWithLock(lockKey, fn) {
57
+ if (this.locks[lockKey]) return;
58
+
59
+ this.locks[lockKey] = true;
60
+ try {
61
+ await fn();
62
+ } catch (error) {
63
+ this.emit('error', `Inpulse generator error: ${error}`);
64
+ } finally {
65
+ this.locks[lockKey] = false;
66
+ }
67
+ }
68
+
69
+ async checkState() {
62
70
  if (this.enableDebugMode) this.emit('debug', `Requesting status`);
63
71
  try {
64
72
  //power status
@@ -95,7 +103,7 @@ class Lights extends EventEmitter {
95
103
 
96
104
  //color temperature scale tasmota 153..500 to homekit 140..500
97
105
  const colorTemp = statusSts.CT ?? false;
98
- const colorTemperature = colorTemp !== false ? await this.scaleValue(colorTemp, 153, 500, 140, 500) : false;
106
+ const colorTemperature = colorTemp !== false ? await this.functions.scaleValue(colorTemp, 153, 500, 140, 500) : false;
99
107
 
100
108
  //hasb color map to array number
101
109
  const hsbColor = statusSts.HSBColor ? statusSts.HSBColor.split(',').map((value) => Number(value.trim())) : false;
@@ -158,35 +166,10 @@ class Lights extends EventEmitter {
158
166
  }
159
167
  }
160
168
 
161
- async scaleValue(value, inMin, inMax, outMin, outMax) {
162
- const scaledValue = parseFloat((((Math.max(inMin, Math.min(inMax, value)) - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin).toFixed(0));
163
- return scaledValue;
164
- }
165
-
166
- async saveData(path, data) {
167
- try {
168
- data = JSON.stringify(data, null, 2);
169
- await fsPromises.writeFile(path, data);
170
- if (this.enableDebugMode) this.emit('debug', `Saved data: ${data}`);
171
- return true;
172
- } catch (error) {
173
- throw new Error(`Save data error: ${error}`);
174
- }
175
- }
176
-
177
- async readData(path) {
178
- try {
179
- const data = await fsPromises.readFile(path);
180
- return data;
181
- } catch (error) {
182
- throw new Error(`Read data error: ${error}`);
183
- }
184
- }
185
-
186
169
  async startImpulseGenerator() {
187
170
  try {
188
171
  //start impulse generator
189
- const timers = [{ name: 'checkDeviceState', sampling: this.refreshInterval }];
172
+ const timers = [{ name: 'checkState', sampling: this.refreshInterval }];
190
173
  await this.impulseGenerator.start(timers);
191
174
  return true;
192
175
  } catch (error) {
@@ -280,7 +263,7 @@ class Lights extends EventEmitter {
280
263
  })
281
264
  .onSet(async (value) => {
282
265
  try {
283
- value = await this.scaleValue(value, 140, 500, 153, 500);
266
+ value = await this.functions.scaleValue(value, 140, 500, 153, 500);
284
267
  const colorTemperature = `${ApiCommands.ColorTemperature}${value}`; //153..500
285
268
  await this.axiosInstance.get(colorTemperature);
286
269
  if (!this.disableLogInfo) this.emit('info', `${friendlyName}, set color temperatur: ${value}`);
@@ -335,7 +318,7 @@ class Lights extends EventEmitter {
335
318
  async start() {
336
319
  try {
337
320
  //check device state
338
- await this.checkDeviceState();
321
+ await this.checkState();
339
322
 
340
323
  //connect to deice success
341
324
  this.emit('success', `Connect Success`)
package/src/mielhvac.js CHANGED
@@ -1,7 +1,7 @@
1
- import { promises as fsPromises } from 'fs';
2
1
  import axios from 'axios';
3
2
  import EventEmitter from 'events';
4
3
  import ImpulseGenerator from './impulsegenerator.js';
4
+ import Functions from './functions.js';
5
5
  import { ApiCommands, MiElHVAC, TemperatureDisplayUnits } from './constants.js';
6
6
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
7
7
 
@@ -40,8 +40,8 @@ class MiElHvac extends EventEmitter {
40
40
  const presets = miElHvac.presets || [];
41
41
  this.presetsConfigured = [];
42
42
  for (const preset of presets) {
43
- const displayType = preset.displayType ?? 0;
44
- if (displayType === 0) {
43
+ const displayType = preset.displayType;
44
+ if (!displayType) {
45
45
  continue;
46
46
  }
47
47
 
@@ -60,8 +60,8 @@ class MiElHvac extends EventEmitter {
60
60
  const buttons = miElHvac.buttons || [];
61
61
  this.buttonsConfigured = [];
62
62
  for (const button of buttons) {
63
- const displayType = button.displayType ?? 0;
64
- if (displayType === 0) {
63
+ const displayType = button.displayType;
64
+ if (!displayType) {
65
65
  continue;
66
66
  }
67
67
 
@@ -80,8 +80,8 @@ class MiElHvac extends EventEmitter {
80
80
  const sensors = miElHvac.sensors || [];
81
81
  this.sensorsConfigured = [];
82
82
  for (const sensor of sensors) {
83
- const displayType = sensor.displayType ?? 0;
84
- if (displayType === 0) {
83
+ const displayType = sensor.displayType;
84
+ if (!displayType) {
85
85
  continue;
86
86
  }
87
87
 
@@ -118,6 +118,7 @@ class MiElHvac extends EventEmitter {
118
118
  this.mielHvac = {};
119
119
  this.previousStateSwingV = 'auto';
120
120
  this.previousStateSwingH = 'center';
121
+ this.functions = new Functions();
121
122
 
122
123
  //axios instance
123
124
  const url = `http://${config.host}/cm?cmnd=`;
@@ -144,39 +145,37 @@ class MiElHvac extends EventEmitter {
144
145
  });
145
146
  }
146
147
 
147
- //impulse generator
148
- this.call = false;
149
- this.call1 = false;
148
+ //lock flags
149
+ this.locks = {
150
+ checkState: false,
151
+ updateRemoteTemp: false,
152
+ };
150
153
  this.impulseGenerator = new ImpulseGenerator()
151
- .on('checkDeviceState', async () => {
152
- if (this.call) return;
153
-
154
- try {
155
- this.call = true;
156
- await this.checkDeviceState();
157
- this.call = false;
158
- } catch (error) {
159
- this.call = false;
160
- this.emit('error', `Inpulse generator error: ${error}`);
161
- };
162
- })
163
- .on('updateRemoteTemp', async () => {
164
- if (this.call1) return;
165
-
166
- try {
167
- this.call1 = true;
168
- await this.updateRemoteTemp();
169
- } catch (error) {
170
- this.call1 = false;
171
- this.emit('error', `Impulse generator error: ${error}`);
172
- }
173
- })
154
+ .on('checkState', () => this.handleWithLock('checkState', async () => {
155
+ await this.checkState();
156
+ }))
157
+ .on('updateRemoteTemp', () => this.handleWithLock('updateRemoteTemp', async () => {
158
+ await this.checkState();
159
+ }))
174
160
  .on('state', (state) => {
175
161
  this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
176
162
  });
177
163
  }
178
164
 
179
- async checkDeviceState() {
165
+ async handleWithLock(lockKey, fn) {
166
+ if (this.locks[lockKey]) return;
167
+
168
+ this.locks[lockKey] = true;
169
+ try {
170
+ await fn();
171
+ } catch (error) {
172
+ this.emit('error', `Inpulse generator error: ${error}`);
173
+ } finally {
174
+ this.locks[lockKey] = false;
175
+ }
176
+ }
177
+
178
+ async checkState() {
180
179
  if (this.enableDebugMode) this.emit('debug', `Requesting status`);
181
180
  try {
182
181
  //power status
@@ -232,8 +231,8 @@ class MiElHvac extends EventEmitter {
232
231
  const operationEnergy = miElHvac.OperationEnergy ?? 0;
233
232
  const operationStatus = miElHvac.OperationStatus ?? 'Unknown';
234
233
  const swingMode = vaneVerticalDirection === 'swing' && vaneHorizontalDirection === 'swing' ? 1 : 0;
235
- const defaultCoolingSetTemperature = parseFloat(await this.readData(this.info.defaultCoolingSetTemperatureFile));
236
- const defaultHeatingSetTemperature = parseFloat(await this.readData(this.info.defaultHeatingSetTemperatureFile));
234
+ const defaultCoolingSetTemperature = parseFloat(await this.functions.readData(this.info.defaultCoolingSetTemperatureFile));
235
+ const defaultHeatingSetTemperature = parseFloat(await this.functions.readData(this.info.defaultHeatingSetTemperatureFile));
237
236
  const remoteTemperatureSensorState = miElHvac.RemoteTemperatureSensorState ?? false; //ON, OFF
238
237
  const remoteTemperatureSensorAutoClearTime = miElHvac.RemoteTemperatureSensorAutoClearTime ?? 0; //time in ms
239
238
 
@@ -721,30 +720,10 @@ class MiElHvac extends EventEmitter {
721
720
  }
722
721
  }
723
722
 
724
- async saveData(path, data) {
725
- try {
726
- data = JSON.stringify(data, null, 2);
727
- await fsPromises.writeFile(path, data);
728
- if (this.enableDebugMode) this.emit('debug', `Saved data: ${data}`);
729
- return true;
730
- } catch (error) {
731
- throw new Error(`Save data error: ${error}`);
732
- }
733
- }
734
-
735
- async readData(path) {
736
- try {
737
- const data = await fsPromises.readFile(path);
738
- return data;
739
- } catch (error) {
740
- throw new Error(`Read data error: ${error}`);
741
- }
742
- }
743
-
744
723
  async startImpulseGenerator() {
745
724
  try {
746
725
  //start impulse generator
747
- const timers = [{ name: 'checkDeviceState', sampling: this.refreshInterval }];
726
+ const timers = [{ name: 'checkState', sampling: this.refreshInterval }];
748
727
  if (this.remoteTemperatureSensorEnable) timers.push({ name: 'updateRemoteTemp', sampling: this.remoteTemperatureSensorRefreshInterval });
749
728
  await this.impulseGenerator.start(timers);
750
729
  return true;
@@ -934,7 +913,7 @@ class MiElHvac extends EventEmitter {
934
913
  .onSet(async (value) => {
935
914
  try {
936
915
  if (this.mielHvac.targetOperationMode === 0) {
937
- await this.saveData(this.info.defaultCoolingSetTemperatureFile, value);
916
+ await this.functions.saveData(this.info.defaultCoolingSetTemperatureFile, value);
938
917
  value = (value + this.info.mielHvac.defaultHeatingSetTemperature) / 2;
939
918
  }
940
919
 
@@ -959,7 +938,7 @@ class MiElHvac extends EventEmitter {
959
938
  .onSet(async (value) => {
960
939
  try {
961
940
  if (this.mielHvac.targetOperationMode === 0) {
962
- await this.saveData(this.info.defaultHeatingSetTemperatureFile, value);
941
+ await this.functions.saveData(this.info.defaultHeatingSetTemperatureFile, value);
963
942
  value = (value + this.info.mielHvac.defaultCoolingSetTemperature) / 2;
964
943
  }
965
944
 
@@ -1254,7 +1233,7 @@ class MiElHvac extends EventEmitter {
1254
1233
  async start() {
1255
1234
  try {
1256
1235
  //check device state
1257
- const checkState = await this.checkDeviceState();
1236
+ const checkState = await this.checkState();
1258
1237
  if (!checkState) return null;
1259
1238
 
1260
1239
  //connect to deice success
package/src/sensors.js CHANGED
@@ -1,7 +1,7 @@
1
- import { promises as fsPromises } from 'fs';
2
1
  import axios from 'axios';
3
2
  import EventEmitter from 'events';
4
3
  import ImpulseGenerator from './impulsegenerator.js';
4
+ import Functions from './functions.js';
5
5
  import { ApiCommands, SensorKeys } from './constants.js';
6
6
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
7
7
 
@@ -25,6 +25,7 @@ class Sensors extends EventEmitter {
25
25
  this.disableLogInfo = config.disableLogInfo || false;
26
26
  this.disableLogDeviceInfo = config.disableLogDeviceInfo || false;
27
27
  this.refreshInterval = refreshInterval;
28
+ this.functions = new Functions();
28
29
 
29
30
  //sensors
30
31
  this.sensorsCount = 0;
@@ -41,27 +42,33 @@ class Sensors extends EventEmitter {
41
42
  }
42
43
  });
43
44
 
44
- //impulse generator
45
- this.call = false;
45
+ //lock flags
46
+ this.locks = {
47
+ checkState: false,
48
+ };
46
49
  this.impulseGenerator = new ImpulseGenerator()
47
- .on('checkDeviceState', async () => {
48
- if (this.call) return;
49
-
50
- try {
51
- this.call = true;
52
- await this.checkDeviceState();
53
- this.call = false;
54
- } catch (error) {
55
- this.call = false;
56
- this.emit('error', `Inpulse generator error: ${error}`);
57
- };
58
- })
50
+ .on('checkState', () => this.handleWithLock('checkState', async () => {
51
+ await this.checkState();
52
+ }))
59
53
  .on('state', (state) => {
60
54
  this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
61
55
  });
62
56
  }
63
57
 
64
- async checkDeviceState() {
58
+ async handleWithLock(lockKey, fn) {
59
+ if (this.locks[lockKey]) return;
60
+
61
+ this.locks[lockKey] = true;
62
+ try {
63
+ await fn();
64
+ } catch (error) {
65
+ this.emit('error', `Inpulse generator error: ${error}`);
66
+ } finally {
67
+ this.locks[lockKey] = false;
68
+ }
69
+ }
70
+
71
+ async checkState() {
65
72
  if (this.enableDebugMode) this.emit('debug', `Requesting status`);
66
73
  try {
67
74
  //sensor status
@@ -189,30 +196,10 @@ class Sensors extends EventEmitter {
189
196
  }
190
197
  }
191
198
 
192
- async saveData(path, data) {
193
- try {
194
- data = JSON.stringify(data, null, 2);
195
- await fsPromises.writeFile(path, data);
196
- if (this.enableDebugMode) this.emit('debug', `Saved data: ${data}`);
197
- return true;
198
- } catch (error) {
199
- throw new Error(`Save data error: ${error}`);
200
- }
201
- }
202
-
203
- async readData(path) {
204
- try {
205
- const data = await fsPromises.readFile(path);
206
- return data;
207
- } catch (error) {
208
- throw new Error(`Read data error: ${error}`);
209
- }
210
- }
211
-
212
199
  async startImpulseGenerator() {
213
200
  try {
214
201
  //start impulse generator
215
- const timers = [{ name: 'checkDeviceState', sampling: this.refreshInterval }];
202
+ const timers = [{ name: 'checkState', sampling: this.refreshInterval }];
216
203
  await this.impulseGenerator.start(timers);
217
204
  return true;
218
205
  } catch (error) {
@@ -538,7 +525,7 @@ class Sensors extends EventEmitter {
538
525
  async start() {
539
526
  try {
540
527
  //check device state
541
- await this.checkDeviceState();
528
+ await this.checkState();
542
529
 
543
530
  //connect to deice success
544
531
  this.emit('success', `Connect Success`)
package/src/switches.js CHANGED
@@ -1,7 +1,7 @@
1
- import { promises as fsPromises } from 'fs';
2
1
  import axios from 'axios';
3
2
  import EventEmitter from 'events';
4
3
  import ImpulseGenerator from './impulsegenerator.js';
4
+ import Functions from './functions.js';
5
5
  import { ApiCommands } from './constants.js';
6
6
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
7
7
 
@@ -27,6 +27,7 @@ class Switches extends EventEmitter {
27
27
  this.disableLogInfo = config.disableLogInfo || false;
28
28
  this.disableLogDeviceInfo = config.disableLogDeviceInfo || false;
29
29
  this.refreshInterval = refreshInterval;
30
+ this.functions = new Functions();
30
31
 
31
32
  //axios instance
32
33
  const url = `http://${config.host}/cm?cmnd=`;
@@ -40,27 +41,33 @@ class Switches extends EventEmitter {
40
41
  }
41
42
  });
42
43
 
43
- //impulse generator
44
- this.call = false;
44
+ //lock flags
45
+ this.locks = {
46
+ checkState: false,
47
+ };
45
48
  this.impulseGenerator = new ImpulseGenerator()
46
- .on('checkDeviceState', async () => {
47
- if (this.call) return;
48
-
49
- try {
50
- this.call = true;
51
- await this.checkDeviceState();
52
- this.call = false;
53
- } catch (error) {
54
- this.call = false;
55
- this.emit('error', `Inpulse generator error: ${error}`);
56
- };
57
- })
49
+ .on('checkState', () => this.handleWithLock('checkState', async () => {
50
+ await this.checkState();
51
+ }))
58
52
  .on('state', (state) => {
59
53
  this.emit('success', `Impulse generator ${state ? 'started' : 'stopped'}.`);
60
54
  });
61
55
  }
62
56
 
63
- async checkDeviceState() {
57
+ async handleWithLock(lockKey, fn) {
58
+ if (this.locks[lockKey]) return;
59
+
60
+ this.locks[lockKey] = true;
61
+ try {
62
+ await fn();
63
+ } catch (error) {
64
+ this.emit('error', `Inpulse generator error: ${error}`);
65
+ } finally {
66
+ this.locks[lockKey] = false;
67
+ }
68
+ }
69
+
70
+ async checkState() {
64
71
  if (this.enableDebugMode) this.emit('debug', `Requesting status`);
65
72
  try {
66
73
  //power status
@@ -107,30 +114,10 @@ class Switches extends EventEmitter {
107
114
  }
108
115
  }
109
116
 
110
- async saveData(path, data) {
111
- try {
112
- data = JSON.stringify(data, null, 2);
113
- await fsPromises.writeFile(path, data);
114
- if (this.enableDebugMode) this.emit('debug', `Saved data: ${data}`);
115
- return true;
116
- } catch (error) {
117
- throw new Error(`Save data error: ${error}`);
118
- }
119
- }
120
-
121
- async readData(path) {
122
- try {
123
- const data = await fsPromises.readFile(path);
124
- return data;
125
- } catch (error) {
126
- throw new Error(`Read data error: ${error}`);
127
- }
128
- }
129
-
130
117
  async startImpulseGenerator() {
131
118
  try {
132
119
  //start impulse generator
133
- const timers = [{ name: 'checkDeviceState', sampling: this.refreshInterval }];
120
+ const timers = [{ name: 'checkState', sampling: this.refreshInterval }];
134
121
  await this.impulseGenerator.start(timers);
135
122
  return true;
136
123
  } catch (error) {
@@ -215,7 +202,7 @@ class Switches extends EventEmitter {
215
202
  async start() {
216
203
  try {
217
204
  //check device state
218
- await this.checkDeviceState();
205
+ await this.checkState();
219
206
 
220
207
  //connect to deice success
221
208
  this.emit('success', `Connect Success`)