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 +31 -27
- package/package.json +1 -1
- package/src/fans.js +25 -38
- package/src/functions.js +31 -0
- package/src/lights.js +27 -44
- package/src/mielhvac.js +39 -60
- package/src/sensors.js +25 -38
- package/src/switches.js +25 -38
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
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
|
-
//
|
|
44
|
-
this.
|
|
44
|
+
//lock flags
|
|
45
|
+
this.locks = {
|
|
46
|
+
checkState: false,
|
|
47
|
+
};
|
|
45
48
|
this.impulseGenerator = new ImpulseGenerator()
|
|
46
|
-
.on('
|
|
47
|
-
|
|
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
|
|
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: '
|
|
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.
|
|
518
|
+
await this.checkState();
|
|
532
519
|
|
|
533
520
|
//connect to deice success
|
|
534
521
|
this.emit('success', `Connect Success`)
|
package/src/functions.js
ADDED
|
@@ -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
|
-
|
|
43
|
+
//lock flags
|
|
44
|
+
this.locks = {
|
|
45
|
+
checkState: false,
|
|
46
|
+
};
|
|
43
47
|
this.impulseGenerator = new ImpulseGenerator()
|
|
44
|
-
.on('
|
|
45
|
-
|
|
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
|
|
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: '
|
|
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.
|
|
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
|
|
44
|
-
if (displayType
|
|
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
|
|
64
|
-
if (displayType
|
|
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
|
|
84
|
-
if (displayType
|
|
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
|
-
//
|
|
148
|
-
this.
|
|
149
|
-
|
|
148
|
+
//lock flags
|
|
149
|
+
this.locks = {
|
|
150
|
+
checkState: false,
|
|
151
|
+
updateRemoteTemp: false,
|
|
152
|
+
};
|
|
150
153
|
this.impulseGenerator = new ImpulseGenerator()
|
|
151
|
-
.on('
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
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: '
|
|
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.
|
|
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
|
-
//
|
|
45
|
-
this.
|
|
45
|
+
//lock flags
|
|
46
|
+
this.locks = {
|
|
47
|
+
checkState: false,
|
|
48
|
+
};
|
|
46
49
|
this.impulseGenerator = new ImpulseGenerator()
|
|
47
|
-
.on('
|
|
48
|
-
|
|
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
|
|
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: '
|
|
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.
|
|
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
|
-
//
|
|
44
|
-
this.
|
|
44
|
+
//lock flags
|
|
45
|
+
this.locks = {
|
|
46
|
+
checkState: false,
|
|
47
|
+
};
|
|
45
48
|
this.impulseGenerator = new ImpulseGenerator()
|
|
46
|
-
.on('
|
|
47
|
-
|
|
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
|
|
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: '
|
|
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.
|
|
205
|
+
await this.checkState();
|
|
219
206
|
|
|
220
207
|
//connect to deice success
|
|
221
208
|
this.emit('success', `Connect Success`)
|